在 CUDA 中,可以使用以下方法展开循环#pragma
unroll 指令通过增加指令级并行性来提高性能。这#pragma
可以选择后跟一个数字,指定必须展开循环的次数。
不幸的是,文档没有给出何时应使用该指令的具体指示。由于编译器已经展开了具有已知行程计数的小循环,因此应该#pragma
unroll 可以用在更大的循环上吗?在带有变量计数器的小循环上?那么可选的展开数量又如何呢?还有关于 cuda 特定循环展开的推荐文档吗?
没有任何快速且硬性的规则。 CUDA 编译器至少有两个展开器,一个位于 NVVM 或 Open64 前端,一个位于 PTXAS 后端。一般来说,他们倾向于非常积极地展开循环,所以我发现自己使用#pragma unroll 1
(以防止展开)比任何其他展开属性更频繁。关闭循环展开的原因有两个:
(1) 当循环完全展开时,套准压力可以增加。例如,小型本地存储器数组的索引可能会成为编译时常量,从而允许编译器将本地数据放入寄存器中。完全展开还可能倾向于延长基本块,从而允许更积极地调度纹理和全局加载,这可能需要额外的临时变量并因此需要寄存器。寄存器压力增加可能会因寄存器溢出而导致性能下降。
(2) 部分展开的循环通常需要一定量的预计算和清理用于处理不完全是展开因子倍数的循环计数的代码。对于行程计数较短的循环,此开销可能会淹没从展开循环中获得的任何性能增益,从而导致展开后性能降低。虽然编译器包含用于在这些限制下查找合适循环的启发式方法,但启发式方法并不总是提供最佳决策。
在极少数情况下,我发现手动提供比编译器自动使用的展开因子更高的展开因子对性能有微小的有益影响(通常增益为个位数百分比)。这些通常是内存密集型代码的情况,其中较大的展开因子允许更积极地调度全局或纹理负载,或者非常严格的计算绑定循环,这得益于循环开销的最小化。
使用展开因素应该在优化过程的后期进行,因为编译器默认值涵盖了实践中会遇到的大多数情况。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)