const * __restrict__ 可以增加 cuda 寄存器的使用吗?
Can a const * __restrict__ increase cuda register usage?
因为我的指针都指向非重叠内存,所以我全力以赴将传递给内核(及其内联函数)的指针替换为 restricted,并且在可能的情况下也使它们成为常量。然而,这增加了一些内核的寄存器使用,而减少了其他内核的使用。这对我来说没有多大意义。
有人知道为什么会这样吗?
是的,它可以增加寄存器的使用。
参考 programming guide for __restrict__
:
The effects here are a reduced number of memory accesses and reduced number of computations. This is balanced by an increase in register pressure due to "cached" loads and common sub-expressions.
Since register pressure is a critical issue in many CUDA codes, use of restricted pointers can have negative performance impact on CUDA code, due to reduced occupancy.
const __restrict__
可能至少有两个好处:
在支持它的体系结构上,它可能使编译器能够发现 constant cache 的用途,这可能是一种性能增强功能。
如上面 linked 编程指南部分所述,它可以使编译器进行其他优化(例如减少指令和内存访问),这也可以提高性能 如果相应的套准压力没有成为问题。
减少导致寄存器压力增加的指令和内存访问可能是不直观的。让我们考虑上面编程指南中给出的示例 link:
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 个寄存器,可以重复使用。对于该示例的其余部分,可能会发生类似的寄存器重用,从而导致总寄存器较低 usage/pressure.
但是如果我们允许编译器重新排序,那么我们必须为预先加载的每个值分配寄存器,并保留到该值退出为止。这种重新排序可以 增加 寄存器 usage/pressure,但最终可能会导致更快的代码(或者它可能会导致更慢的代码,如果寄存器压力成为性能限制因素。)
因为我的指针都指向非重叠内存,所以我全力以赴将传递给内核(及其内联函数)的指针替换为 restricted,并且在可能的情况下也使它们成为常量。然而,这增加了一些内核的寄存器使用,而减少了其他内核的使用。这对我来说没有多大意义。
有人知道为什么会这样吗?
是的,它可以增加寄存器的使用。
参考 programming guide for __restrict__
:
The effects here are a reduced number of memory accesses and reduced number of computations. This is balanced by an increase in register pressure due to "cached" loads and common sub-expressions.
Since register pressure is a critical issue in many CUDA codes, use of restricted pointers can have negative performance impact on CUDA code, due to reduced occupancy.
const __restrict__
可能至少有两个好处:
在支持它的体系结构上,它可能使编译器能够发现 constant cache 的用途,这可能是一种性能增强功能。
如上面 linked 编程指南部分所述,它可以使编译器进行其他优化(例如减少指令和内存访问),这也可以提高性能 如果相应的套准压力没有成为问题。
减少导致寄存器压力增加的指令和内存访问可能是不直观的。让我们考虑上面编程指南中给出的示例 link:
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 个寄存器,可以重复使用。对于该示例的其余部分,可能会发生类似的寄存器重用,从而导致总寄存器较低 usage/pressure.
但是如果我们允许编译器重新排序,那么我们必须为预先加载的每个值分配寄存器,并保留到该值退出为止。这种重新排序可以 增加 寄存器 usage/pressure,但最终可能会导致更快的代码(或者它可能会导致更慢的代码,如果寄存器压力成为性能限制因素。)