来自NVIDIA CUDA C Programming Guide:
可以使用
maxrregcount
编译器控制寄存器使用情况 选项或启动边界,如启动边界中所述。
根据我的理解(如果我错了,请纠正我),而-maxrregcount
限制整个.cu
文件可能使用的寄存器数量,__launch_bounds__
限定符定义{{每个maxThreadsPerBlock
内核都有1}}和minBlocksPerMultiprocessor
。这两个完成相同的任务,但有两种不同的方式。
我的用法要求我每个线程都有__global__
个寄存器,以最大限度地提高性能。因此,我可以使用40
。我也可以使用-maxrregcount 40
强制40
个注册,但这会导致加载和放大商店注册溢出。
导致这些寄存器泄漏的两者之间有什么区别?
答案 0 :(得分:10)
这个问题的前言是,引用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
确保minBlocksPerMultiprocessor
块(或单个块) 如果未指定minBlocksPerMultiprocessor
)maxThreadsPerBlock
个线程可以驻留在多处理器上。该 编译器然后以下列方式优化寄存器使用:
- 如果初始寄存器使用率高于
L
,编译器会将其进一步减少,直到它变得小于或等于L
,通常在 更多本地内存使用和/或更高数量的费用 指令;
因此,__launch_bounds__
会导致注册溢出。
<强> maxrregcount
强>
maxrregcount
是一个编译器标志,通过强制编译器重新安排其寄存器的使用,简单地将所用寄存器的数量限制为用户设置的数字,与__launch_bounds__
不一致。当编译器不能保持低于强制限制时,它只会将其溢出到本地内存,实际上是DRAM
。即使这个局部变量存储在全局DRAM
内存变量中,也可以缓存在L1,L2中。