@Dounm
2018-12-11T11:16:24.000000Z
字数 2047
阅读 1974
对于一个CUDA kernel function而言,其通常由如下几个部分组成:
__syncthreads__
call<<<BlocksNum, ThreadsNumPerBlock>>>
我们分别考虑如何对这些部分进行优化。
__global__
function的参数是存在constant mem里的,并且其大小被限制为4KB。
通常来说,我们传入的参数都比较少,因此这些参数大部分是直接缓存在SM上的register上的,因此读取起来最快。但如果register不够用,那么就会被放到constant mem/cache上,速度就会变慢。
对于单独的local var,其会被放在register里面,因此读写极快。
对于数组类型的local var,根据访问pattern的不同,速度也不同(见https://d.docs.live.net/606463c833bea118/Documents/Distribute%20Computing/GPU.one">per-thread array的访问)
总结而言是这样的:
__syncthreads__
callshared memory就如同2.3节所述,我们需要尽量避免bank confilicts,这样读取最快,一个cycle clock就可以读取128byte。
除此之外,因为shared memory由同一block内的thread共享,所以在初始化shared mem之后,需要调用__syncthreads__
来对同一block内的所有threads进行同步。
编译器会自行决定device function是否会被inlined(多数情况下会inline)。通常来说,inline会更好,因为少了函数调用的开销。
我们可以用forceinline来给编译器提示
在书写kernel function时,应尽量避免loop/if,因为这两个在代码里引入了分支结构。
如果代码有分支,那么
因此在可能的情况下,我们应该尽量使用模板参数来替换掉loop/if:
针对一些边界是常量(如0->5)的循环,在循环体足够简单的情况下,可以使用#pragma unroll
来告诉编译器展开该循环。
朱泙漫学屠龙于支离益,单千金之家。三年技成,而无所用其巧
---《庄子·列御寇》
BlocksNum
和ThreadsNumPerBlock
是执行kernel function时配置的值。这两个值通常都是经验求解,很难找到最优值。
简单来说,
ThreadsNumPerBlock
受限于device property的MaxThreadsPerBlock
,经验取值为512/1024。BlocksNum
最大无限制,常见求解公式为。更详细的见《CUDA程序调优指南(三):BlockNum和ThreadNumPerBlock》