8

在 CUDA 中,可以使用#pragmaunroll 指令展开循环,以通过增加指令级并行度来提高性能。可以选择#pragma后跟一个数字,指定循环必须展开多少次。

不幸的是,文档没有给出何时应该使用该指令的具体说明。由于具有已知行程计数的小循环已经被编译器展开,是否应该#pragma在较大的循环上使用展开?在带有可变计数器的小循环上?那么可选的展开次数呢?还有关于 cuda 特定循环展开的推荐文档吗?

4

2 回答 2

12

没有任何快速而硬性的规则。CUDA 编译器至少有两个展开器,一个在 NVVM 或 Open64 前端,一个在 PTXAS 后端。一般来说,他们倾向于非常积极地展开循环,所以我发现自己使用#pragma unroll 1(防止展开)比任何其他展开属性更频繁。关闭循环展开的原因有两个:

(1) 当一个环完全展开时,套准压力会增加。例如,小型本地内存数组的索引可能成为编译时常量,允许编译器将本地数据放入寄存器。完全展开也可能会延长基本块,允许更积极地调度纹理和全局加载,这可能需要额外的临时变量,因此需要寄存器。由于套准溢出,增加的套准压力会导致性能下降。

(2) 部分展开的循环通常需要一定数量的预计算和清理代码来处理不完全是展开因子倍数的循环计数。对于行程数较短的循环,此开销可能会淹没展开循环所获得的任何性能提升,从而导致展开后的性能降低。虽然编译器包含在这些限制下寻找合适循环的启发式方法,但启发式方法并不总是提供最佳决策。

在极少数情况下,我发现手动提供比编译器自动使用的展开因子更高的展开因子对性能的有益影响很小(典型增益为个位数百分比)。这些通常是内存密集型代码的情况,其中较大的展开因子允许更积极地调度全局或纹理加载,或者非常紧密的计算绑定循环,受益于循环开销的最小化。

使用展开因子应该在优化过程的后期进行,因为编译器默认值涵盖了人们在实践中会遇到的大多数情况。

于 2012-11-05T00:00:31.407 回答
-1

这是一个可用于展开循环的工具。何时应该/不应该使用它的细节会根据您的代码(例如循环内的内容)而有很大差异。没有任何好的通用技巧,除了想想你的代码在展开与滚动时会是什么样子,并考虑它是否会更好地展开。

于 2012-11-04T19:53:56.893 回答