【发布时间】:2015-07-10 15:18:17
【问题描述】:
因为我的指针都指向非重叠内存,所以我全力以赴,将传递给内核(及其内联函数)的指针替换为 restricted,并将它们设为 const , 尽可能。然而,这增加了某些内核的寄存器使用量并减少了其他内核的使用量。这对我来说没有多大意义。
有人知道为什么会这样吗?
【问题讨论】:
标签: cuda cpu-registers restrict-qualifier
因为我的指针都指向非重叠内存,所以我全力以赴,将传递给内核(及其内联函数)的指针替换为 restricted,并将它们设为 const , 尽可能。然而,这增加了某些内核的寄存器使用量并减少了其他内核的使用量。这对我来说没有多大意义。
有人知道为什么会这样吗?
【问题讨论】:
标签: cuda cpu-registers restrict-qualifier
是的,它可以增加寄存器使用率。
对于__restrict__,请参考programming guide:
这里的效果是减少了内存访问次数和计算次数。这可以通过“缓存”负载和常见子表达式导致的寄存器压力增加来平衡。
由于寄存器压力在许多 CUDA 代码中是一个关键问题,因此使用受限指针会对 CUDA 代码产生负面的性能影响,因为占用率会降低。
const __restrict__ 可能至少有两个原因:
在支持它的架构上,它可以使编译器发现constant cache 的用途,这可能是一个性能增强功能。
如上面链接的编程指南部分所述,它可以使编译器进行其他优化(例如减少指令和内存访问),如果相应的寄存器压力不成为问题,这也可以提高性能 .
减少导致寄存器压力增加的指令和内存访问可能是不直观的。让我们考虑上面编程指南链接中给出的示例:
void foo(const float* a, const float* b, float* c) {
c[0] = a[0] * b[0];
c[1] = a[0] * b[0];
c[2] = a[0] * b[0] * a[1];
c[3] = a[0] * a[1];
c[4] = a[0] * b[0];
c[5] = b[0]; ... }
如果我们在上面的例子中允许指针别名,那么编译器就不能做很多优化,编译器本质上被简化为完全按照编写的代码执行。第一行代码:
c[0] = a[0] * b[0];
将需要 3 个寄存器。下一行代码:
c[1] = a[0] * b[0];
还需要 3 个寄存器,因为一切都是按原样生成的,所以它们可以是 相同的 3 个寄存器,可以重复使用。示例的其余部分可能会发生类似的寄存器重用,从而导致整体寄存器使用率/压力较低。
但是,如果我们允许编译器重新排序,那么我们必须为每个预先加载的值分配寄存器,并保留到该值退出为止。这种重新排序可以增加寄存器使用/压力,但最终可能会导致代码更快(或者如果寄存器压力成为性能限制因素,它可能会导致代码变慢。)
【讨论】: