作者:英伟达高性能计算
事实上,寄存器数量限制程序性能的案例还是比较少的。
首先您要明确是否真的是此因素导致了您程序性能无法进一步提升。
寄存器影响主要两个方面:active warp 的数量(即occupancy )和寄存器溢出导致的local memory的传输。
首先看active warp:
什么时候是因为寄存器使用过多导致active warp数量少,导致性能低呢?
第一,程序为延迟密集型程序,也就是说程序大部分时间是在等待高延迟指令返回结果(其他两种为指令密集型和内存密集型,详见GTC 录像中讲座Analysis Driven Optimization with CUDA
http://www.gputechconf.com/gtcnew/on-demand-gtc.php )。因为只有在这种情况下程序才需要更多的active warp来隐藏延迟。
第二,仅仅通过instruction by byte ratio, instruction throughput, memory throughput来确定是否为延迟密集型是不完整的。很多情况下,当我们的程序有较严重的负载不均衡的现象,即某几个block或某些warps运行时间远超过其他时,或者没有分配足够的blocks和threads时。instruction throughput 和 memory throughput 也会很低。这两种情况的特征是实际的occupancy数量远远低于理论的occupancy。实际occupancy可以通过以下公式求出:
actual occupancy = active warps/duration/#sm/frequency_of_gpu/max_active_warps_in_a_sm
其中active warps 可以通过Toolkit 中提供的profiler:nvvp 测得。duration 为kernel运行时间,#sm为此gpu中sm的数量,frequency_of_gpu为gpu的主频,max_active_warps_in_a_sm为一个sm最大可以有多少个resident warps。理论occupance同样可以通过nvvp测得,或者通过toolkit中提供的excel工具测得。
第三,即使理论和实际occupancy接近,也不一定是由于寄存器使用过多导致occupancy少,occupancy还受到shared memory,每个block分配多少线程的影响,可以通过excel工具查看。
只有在程序为延迟密集型程序,且经验证,理论occupancy和实际occupancy接近时,并通过excel工具查得确实寄存器为限制因素时才可得出寄存器使用过多导致性能无法进一步提高的结论。
另外,再来看寄存器溢出导致local memory传输制约程序性能的可能性:
如果是内存传输为程序瓶颈,那么kernel一定是内存密集型。其表现为程序sm到L2内存传输速度基本达到gpu峰值。至于判断是寄存器溢出导致的local memory,还是局部数组存储导致的local memory成为瓶颈还是由于一般的global memory的访问或者tex访问。我们可以通过查看Profiler 中的Metrics: Local Memory Overhead查看,看是否local memory的吞吐量占其中主要部分。在local memory的吞吐占主要部分,且代码中用数组存储局部变量的情况时,才可得出寄存器溢出导致local memory传输制约程序性能的结论。
如果寄存器使用确实成为程序瓶颈。以下策略可以减少程序中寄存器的使用。
1、 拆分代码为较小的Kernel(一般需要同时修改算法才能达到比较好的效果)。
2、 运用maxrregcount编译选项控制寄存器使用。