在CUDA中利用寄存器内存

4
我对cuda寄存器内存有一些问题。
1)是否有方法在cuda内核中释放寄存器?我在寄存器中有变量、1D和2D数组。 (最大数组大小为48)
2)如果我使用设备函数,那么设备函数中使用的寄存器会发生什么情况?它们在执行后是否可用于调用内核执行或其他设备函数?
3)nvcc如何优化寄存器使用?请分享与内存密集型内核优化相关重要的点。
PS:我要将一个复杂算法移植到cuda中,它需要大量寄存器进行计算,我正在尝试弄清楚是将中间数据存储在寄存器中并编写一个内核,还是将其存储在全局内存中并将算法分解成多个内核。
1个回答

5

只有本地变量才能被分配到寄存器中 (也可参见在CUDA核函数中声明变量)。对于哪些变量(标量或静态数组)会分配到寄存器中,你没有直接控制权。编译器会根据寄存器的空闲情况自行选择,力求在性能和寄存器节省之间达到平衡。

使用nvcc编译器的maxrregcount选项可以限制寄存器使用量。

大多数小型1D、2D数组可以放在共享内存中,或者如果访问的是常量数据,则将其内容放入常量内存中(它们缓存得非常接近寄存器,就像L1缓存一样)。

处理计算密集型CUDA核函数时,减少寄存器使用的另一种方法是通过阶段性处理数据,在多次全局核函数调用中存储中间结果到全局内存中。每个核函数需要的寄存器较少,这样每个SM上的活动线程数就能够隐藏更多的加载/存储数据移动操作。这种技术与流和异步数据传输的适当使用相结合,通常能取得很好的效果。

关于使用设备函数,我不确定,但我猜调用函数的寄存器内容会被移动/存储到本地内存中(L1缓存或类似的地方),就像使用太多本地变量时发生的寄存器溢出一样(参见CUDA编程指南->设备内存访问->本地内存)。这个操作将为被调用的设备函数释放一些寄存器。在设备函数完成后,它们的局部变量将不存在,寄存器可以由调用者函数重新使用,并填充之前保存的内容。

请记住,在全局核函数的同一源代码中定义的小型设备函数可能会被编译器内联以提高性能:当这种情况发生时,生成的核函数通常需要更多的寄存器。


我已经在使用共享内存和常量内存,但由于算法的计算密集性,仍需要大量寄存器(>255,实际上我在设计算法时就问过这个问题以计算所需的寄存器数量)。如果我将中间结果存储在全局内存中,并将计算分成多个内核,则我确定会浪费很多时间在读写上。让寄存器溢出到本地内存是否更好?(这样,如果在下一代GPU中支持相同的算法,则线程每个寄存器增加) - Adarsh
@Adarsh:你无法仅凭CUDA源代码推断使用寄存器的数量,这是编译器的选择,你可以使用'maxrregcount'或使用较少的局部变量来限制。当从CPU移植代码到CUDA时,还要考虑将算法更改为更适合GPU硬件的算法。对于计算密集型算法,将大任务拆分成多个内核是最好的方法(回答已更新):每个内核使用的寄存器越少,越多的活动线程将隐藏负载/存储。nvvp会告诉您是否存在这种情况。不要“确信”,试一下。 - Luca Ferraro
@Adarsh 如果我的回答让您满意,请将其标记为已接受或澄清缺少什么。 - Luca Ferraro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接