可以使用
maxrregcount
编译器选项或启动边界来控制寄存器使用,如启动边界中所描述的那样。
根据我的理解(如果我错了,请纠正我),虽然-maxrregcount
限制了整个.cu
文件可能使用的寄存器数量,但是__launch_bounds__
限定符为每个__global__
内核定义了maxThreadsPerBlock
和minBlocksPerMultiprocessor
。这两个人完成相同的任务,但以两种不同的方式。
我的使用要求每个线程都有40
寄存器,以最大限度地提高性能。因此,我可以使用-maxrregcount 40
。我还可以使用40
强制使用__launch_bounds__(256, 6)
寄存器,但这会导致加载和存储寄存器溢出。
两者之间的区别是什么导致这些登记泄漏?
发布于 2017-06-22 13:16:41
这个问题的序言是引用CUDA C Programming Guide
的话,
内核使用的寄存器越少,在多处理器上驻留的线程和线程块就越多,这可以提高性能。
现在,__launch_bounds__
和maxregcount
通过两种不同的机制限制寄存器的使用。
__launch_bounds__
nvcc
通过平衡内核启动设置的性能和通用性来决定__global__
函数要使用的寄存器数量。不同的说法是,选择使用寄存器的数量“保证”每个块的不同线程数和每个多处理器的块数。但是,如果在编译时可以得到每个块的最大线程数以及(可能)每个多处理器的最小块数的大致概念,那么可以使用这些信息来优化内核。换句话说
#define MAX_THREADS_PER_BLOCK 256
#define MIN_BLOCKS_PER_MP 2
__global__ void
__launch_bounds__(MAX_THREADS_PER_BLOCK, MIN_BLOCKS_PER_MP)
fooKernel(int *inArr, int *outArr)
{
// ... Computation of kernel
}
通知编译器可能的启动配置,以便nvcc
能够以“最优”的方式为这种启动配置选择寄存器数量。
MAX_THREADS_PER_BLOCK
参数是强制性的,而MIN_BLOCKS_PER_MP
参数是可选的。还请注意,如果内核启动时每个块的线程数大于MAX_THREADS_PER_BLOCK
,则内核启动将失败。
Programming Guide
中对限制机制的描述如下:
如果指定了启动边界,编译器首先从它们派生内核应该使用的寄存器数量的上限
L
,以确保maxThreadsPerBlock
线程的minBlocksPerMultiprocessor
块(如果没有指定minBlocksPerMultiprocessor
)可以驻留在多处理器上。然后,编译器以下列方式优化寄存器的使用:
L
,则编译器将其进一步减少,直至其小于或等于L
,通常以牺牲更多的本地内存使用量和/或更多的指令数量为代价;因此,__launch_bounds__
可能导致注册溢出。
maxrregcount
maxrregcount
是一个编译器标志,它通过强制编译器重新安排寄存器的使用,将雇用寄存器的数量严格限制在用户设置的数字上,与__launch_bounds__
不一致。当编译器不能保持在规定的限制之下时,它只会将其泄漏到本地内存,这实际上是DRAM
。即使这个局部变量存储在全局DRAM
内存变量中,也可以缓存在L1,L2中。
https://stackoverflow.com/questions/44704506
复制