本文为《CUDA C Programming Guide》chapter 5 Performance Guidelines章节的总结。精力有限,可能没做到覆盖所有的点,期望指正。
该章的主要内容是指导如何进行性能优化。从三个大方面入手:最大化利用率;最大
化内存吞吐量;和最大化指令吞吐量。
最大化利用率
应用层次:
- 使用异步函数和流,最大化主机端(host)任务、设备端(device)任务和主机设备通信任务的并行性;
- 将需要使用共享内存通信的线程放到一个block内。
设备层次
- 将没有数据依赖,可并行的kernel使用stream加速。
Multiprocessor 层次
- 编写kernel代码时谨慎使用寄存器和共享内存,防止影响occupancy;
- block大小应该为warp的倍数
最大化内存吞吐量
- 尽量使用page-locked内存;
- 尽可能的减少host和device之间的内存传输。比如(1)将多次传输合并为一次大传输;(2)可以将一些并行度不高但是需要H-D传输的任务放到GPU上,虽然这个任务在CPU上会更快一些,但是减少了H-D传输,这是一个trade-off问题。
- 访问全局内存时,要考虑对齐问题,尽可能的合访问。比如(1)使用cudaMallocPitch申请逻辑二维数组(比如图像);(2)设计访存模型时,考虑合并访问问题;
- 不要让kernel中的变量被放到local Memory中;
- 使用shared Memory时,防止bank conflict;
最大化指令吞吐量
- 尽量少使用低吞吐量的算术指令;
- 在不影响最后结果的情况下使用低精度类型,使用内部计算接口而不是自己实现;
- 使用单精度float而不是双精度double;
- 尽量减少流程控制指令,即减少条件分支。比如(1)控制条件仅取决于(threadIdx / warpSize);(2)使用#pragma unroll展开循环。
- __fdividef(x,y)是比除法运算符更快的单精度浮点除法
- 大部分情况下,rsqrtf()效率比1.0 / sqrtf()高。
- 使用三角函数时,尽量使用单精度,且x值域较小为宜;
- 尽量使用位运算代替整数除法和模运算;
- 半精度计算,使用half2代替half
- 调用接口时,尽量保持参数类型一致,否则会有类型转换的消耗;比如函数参数是int类型,输入是char类型或者short类型,需要先将类型转化为int类型。