一、指令优化
(一)代数指令
1、除法跟模运算尽量少用,可能的话替换为比特级操作
2、平方根倒数 rsqrt,rcbrt
3、其他指令:避免双精度到单精度的自动转换。
4、小分数的指数运算使用2中的组合
5、数学库:使用快速的数学库(__sin)和专用的函数(exp2(),exp10(),sinpi())
-use_fast_math选项将普通函数转换为快速库函数
(二)内存指令
少使用全局内存,尽量使用共享内存,全局内存需要六百多个时钟周期。
二、控制流
1、避免同一线程束执行不同的路径
2、对于编译器,在循环和控制语句中使用分支预测。展开循环
3、循环计数使用符号数,而非无符号数
4、在循环中同步发散线程:在发散线程中避免使用同步函数,尽量使所有线程执行同样的次数。
三、内存优化
1、最小化主机和设备间的数据传输,即使意味着函数在GPU上运行时间相较于主机未表现出减少。
2、中间结构不回传至主机。
3、联合几个小的传输成一个大的传输。即使,这些内存不连续。
4、锁页内存由更大的带款。
不应该过度使用锁页内存,否则,可能造成性能下降,因为锁页内存是稀缺资源。
异步和重叠复制及计算
1、重叠计算和数据传输:因为传输为异步,可以同主机运算重叠;
2、并发复制和执行:使用不同的流即可;
3、顺序的复制和执行;
4、分步的并发复制和执行:综合2,3技术;
零复制
零复制内存是一种可以使设备线程直接访问主机内存的技术。常用于集成GPU。需要使用映射不可分页内存。该内存可以在不使用流的情况下,重叠数据传输和计算。但是,重复传输会引起重复数据传输,所以应该在GPU上申请数据缓存。
统一虚拟寻址
主机内存和设备内存共享一个虚拟内存空间。在此之前,应用需要跟踪内存来源,现在可以通过函数查询cudaPointerGetAttributes()。
锁页主机内存的地址一致不需要函数cudaHostGetDevicePointer(),但是,分配后再注册的内存仍需要上述函数。
统一虚拟寻址可以使GPU进行对等访问,而不要通过主机内存。
设备内存空间
纹理内存:为只读内存,所以写的时候必须小心。
1、纹理引用绑定到全局内存中的线性数组,设备线程可以访问潜在数组
2、绑定到CUDA数组的纹理引用可以通过表面写操作完成写入,绑定一个表面到相同的潜在数组。
对全局内存的聚合访问
确保全局内存聚合访问
默认使用一级缓存,128字节宽;分散存储使用二级缓存,防止过加载,32字节宽。
全局内存使用二级缓存,本地内存使用一级缓存。高版本设备全局内存也可以使用一级缓存。
聚合访问对ECC也很重要。
简单访问模式:一个128字节:每个线程4字节,或者几个线程不访问。
顺序非对齐访问:访问两个128字节,对于非缓存事务,直接访问多次二级缓存
分配内存应该是256字节 的倍数
非对齐访问:应该使用一个专用的复制核函数。