寄存器使用过多成为CUDA程序瓶颈的情况分析
2014-04-11 09:25
204 查看
原文地址:http://blog.sina.com.cn/s/blog_c25b76e20101jywj.html 作者:英伟达高性能计算
事实上,寄存器数量限制程序性能的案例还是比较少的。
首先您要明确是否真的是此因素导致了您程序性能无法进一步提升。
寄存器影响主要两个方面: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编译选项控制寄存器使用。
事实上,寄存器数量限制程序性能的案例还是比较少的。
首先您要明确是否真的是此因素导致了您程序性能无法进一步提升。
寄存器影响主要两个方面: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编译选项控制寄存器使用。
相关文章推荐
- 用MAT分析JAVA程序运行时的内存使用情况
- dos窗口下能编译java程序,但不能执行情况分析
- xpath解析使用extract()的各种情况分析
- 小程序的使用场景及用途分析
- 使用ToolRunner运行Hadoop程序基本原理分析
- 使用showmap分析android进程内存占用情况(转载)
- 使用ToolRunner运行Hadoop程序基本原理分析
- 【经验】使用Profiler工具分析内存占用情况
- Android最佳性能实践(二)——分析内存的使用情况
- 用于分析table的内存使用情况space_usage
- Java程序内存分析:使用mat工具分析内存占用
- 如何分析Android应用内存使用情况
- [转载]分析SDK下的俄罗斯方块程序(仅供学习使用)
- 转linux c程序获取cpu使用率及内存使用情况
- 如何使用strace+pstack利器分析程序性能
- linux c程序获取cpu使用率及内存使用情况
- 简单说明什么是递归,什么情况下会使用递归,并写一个简单的递归程序。
- Win32程序函数调用时堆栈变化情况分析(zt)
- Android最佳性能实践(二)——分析内存的使用情况
- 使用vs的性能分析asp.net程序时报错的解决方法