<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>GPU Hacks on Dispatch3 Inc.</title><link>https://dispatch3.com/tags/gpu-hacks/</link><description>Recent content in GPU Hacks on Dispatch3 Inc.</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 03 Mar 2016 00:00:00 -0500</lastBuildDate><atom:link href="https://dispatch3.com/tags/gpu-hacks/index.xml" rel="self" type="application/rss+xml"/><item><title>A CUDA Error Checking Macro</title><link>https://dispatch3.com/posts/cuda_macro/</link><pubDate>Thu, 03 Mar 2016 00:00:00 -0500</pubDate><guid>https://dispatch3.com/posts/cuda_macro/</guid><description>I just switched over to a new CUDA error checking macro and really like how it works.
This error checking macro will transform a CUDA Runtime API function into its error-checked equivalent simply by parenthesizing everything after the lower case cuda function prefix.
Examples:
cuda(GetDeviceProperties(&amp;amp;props,device)); cuda(SetDevice(device)); cuda(Malloc(&amp;amp;vin_d, bytes)); cuda(Memset(vin_d,0,bytes)); cuda(Free(vin_d)); cuda(EventCreate(&amp;amp;end)); cuda(EventRecord(end)); cuda(EventSynchronize(end)); cuda(EventElapsedTime(&amp;amp;elapsed,start,end)); cuda(EventDestroy(end)); cuda(DeviceReset()); The C99/C++ macro and assert look like this:
#define cuda(...) cuda_assert((cuda##__VA_ARGS__), __FILE__, __LINE__, true); cudaError_t cuda_assert(const cudaError_t code, const char* const file, const int line, const bool abort) { if (code !</description></item><item><title>An Idiom for SMEM Variables</title><link>https://dispatch3.com/posts/smem_idiom/</link><pubDate>Thu, 18 Jul 2013 00:00:00 -0400</pubDate><guid>https://dispatch3.com/posts/smem_idiom/</guid><description>It&amp;rsquo;s common to declare a number of shared memory variables at the top of a CUDA kernel file.
You often see these declarations with Hungarian&amp;rsquo;ish names that imply the variables somehow reside in shared memory.
But as someone who likes to write highly readable code, I&amp;rsquo;ve found that naming, referencing and maintaining independently declared shared variables can sometimes turn into an endeavor.
Some example issues:
I would like to use the same meaningful variable name for both the shared and in-register instances.</description></item><item><title>Kernel Args vs. Constants</title><link>https://dispatch3.com/posts/kernel_args_vs_constants/</link><pubDate>Thu, 09 May 2013 00:00:00 -0400</pubDate><guid>https://dispatch3.com/posts/kernel_args_vs_constants/</guid><description>It&amp;rsquo;s not uncommon to have a GPU kernel where a number of the kernel parameters are left as constants throughout the entire call chain and, if the target were a CPU, would have been implemented as traditional static const file scope variables.
For this reason, you might think that exploiting the __constant__ qualifier and its associated cudaXXXSymbol() routines is a good way of reducing the number of kernel arguments and generally cleaning up your code.</description></item><item><title>Memoryless Matrix Transposition II</title><link>https://dispatch3.com/posts/fast_matrix_transpo_kepler_2/</link><pubDate>Sun, 07 Apr 2013 00:00:00 -0400</pubDate><guid>https://dispatch3.com/posts/fast_matrix_transpo_kepler_2/</guid><description>Last time I presented a clever way of transposing that exploited the GPU&amp;rsquo;s support of 32-byte stores as its smallest &amp;ldquo;100% efficient&amp;rdquo; transaction size.
An open question was whether designing a transpose that performed 64-byte stores would achieve better performance at the cost of more instructions.
The answer is yes. Performing 64-byte transactions improves throughput by ~8%. The new 64-byte transpose kernel reaches ~148 GB/sec. on a 1024x1024 matrix of 32-bit elements on a K20c (758MHz).</description></item><item><title>Memoryless Matrix Transposition</title><link>https://dispatch3.com/posts/fast_matrix_transpo_kepler/</link><pubDate>Tue, 26 Mar 2013 00:00:00 -0400</pubDate><guid>https://dispatch3.com/posts/fast_matrix_transpo_kepler/</guid><description>I needed a fast and minimal routine that could transpose a warp with 32 elements per lane and store the result to device memory as the final step in a complex kernel.
However, I had a hypothesis that Kepler SHFL instructions and 16-byte stores by pairs of lanes would be functionally equivalent to the standard matrix transpose approach but not require any shared memory or thread block synchronization yet still achieve 100% memory store efficiency.</description></item><item><title>Experiments with SHFL</title><link>https://dispatch3.com/posts/experiments_with_shfl/</link><pubDate>Thu, 14 Mar 2013 00:00:00 -0400</pubDate><guid>https://dispatch3.com/posts/experiments_with_shfl/</guid><description>I wanted to double-check my understanding of Kepler&amp;rsquo;s shfl operation when using negative indices or negative index offsets. The PTX documentation on this instruction is accurate but a little terse so a micro-test was in order.
The summary results are:
shfl.idx handles negative indices without any problem which means &amp;ldquo;shuffle rotations&amp;rdquo; are feasible. shfl.up has no chance to mask the lane - bval value so it sets the in-range predicate to false when negative indices are produced and the lane&amp;rsquo;s current value is assigned.</description></item><item><title>GPU Hack: LLVM for pre-Fermi Kernels</title><link>https://dispatch3.com/posts/gpu_hack_pre_fermi/</link><pubDate>Sun, 27 May 2012 00:00:00 -0400</pubDate><guid>https://dispatch3.com/posts/gpu_hack_pre_fermi/</guid><description>I&amp;rsquo;ve been cleaning up a set of kernels so that they will run optimally on GT200 devices (sm_1x). The kernels run extremely well on Fermi so I was disappointed when the opencc compiler struggled to use a reasonable number of registers despite having access to the same number of registers per thread.
I was getting over 200 bytes of spills in a critical kernel that had no spills at all on Fermi.</description></item><item><title>CUDA "warpSize"?</title><link>https://dispatch3.com/posts/why_warpsize/</link><pubDate>Thu, 19 Apr 2012 00:00:00 -0400</pubDate><guid>https://dispatch3.com/posts/why_warpsize/</guid><description>In CUDA C, the built-in variable warpSize is initially treated as a variable at compile-time and doesn&amp;rsquo;t appear to be recognized as a constant until the PTX generation phase. This could be an issue if the warp width is part of some tricky preprocessing early in the compilation.
The simple line:
const unsigned int w99 = warpSize * 99;` is resolved to the following PTX:
mov.u32 %r5, WARP_SZ; mul.lo.s32 %r6, %r5, 99; Yes, the stage after PTX will do a great job folding/propagating away WARP_SZ but sometimes you need to resolve logic in the preprocessor.</description></item><item><title>GPU Hack: High Lane Wins</title><link>https://dispatch3.com/posts/gpu_hack_high_lane_wins/</link><pubDate>Wed, 27 Jul 2011 00:00:00 -0400</pubDate><guid>https://dispatch3.com/posts/gpu_hack_high_lane_wins/</guid><description>A useful GF100 GPU hack is revealed on page 6 in the Laine &amp;amp; Karras' paper &amp;ldquo;High-Performance Software Rasterization on GPUs&amp;rdquo;.
They state that:
When there are shared memory write conflicts within the warp, the write from a thread on a higher lane, therefore containing a later triangle, will override a write from a thread on a lower lane, containing an earlier triangle. The CUDA programming guide explicitly leaves it undefined which thread will succeed in the write, but at least on GF100 the behavior is consistent and can be exploited.</description></item></channel></rss>