Cuda 尽早设置自变量是否可以提高绩效?

Cuda 尽早设置自变量是否可以提高绩效?,cuda,Cuda,线程不会在内存访问时暂停 来自瓦西里·沃尔科夫的著名论文 基于此声明,我假设: __device__ int a; int b, c, d; a = b * c; // Do some work that is independent of 'a' // ... d = a + 1; 比这还快 __device__ int a; int b, c, d; a = b * c; d = a + 1; // Do some work that is independent of 'a' // ..

线程不会在内存访问时暂停

来自瓦西里·沃尔科夫的著名论文

基于此声明,我假设:

__device__ int a;
int b, c, d;
a = b * c;
// Do some work that is independent of 'a'
// ...
d = a + 1;
比这还快

__device__ int a;
int b, c, d;
a = b * c;
d = a + 1;
// Do some work that is independent of 'a'
// ...
我只是假设,因为我给线程机会在写入全局内存时执行不同的指令,而在第二种方法中,我没有

我的假设正确吗?


如果我的假设是正确的,那么在内核开始时设置所有将要使用的变量是一个好的实践吗?假设它们彼此独立,也假设
a
未缓存。

实际上引用的暂停是内存读取

它指出,内存读取不会产生暂停,使用假定不可用的读取值会导致暂停

假设我有:

__device__ int a[32];
然后,此线程代码不会导致暂停(尽管它会生成内存事务):

但如果我这样做,我会得到一个摊位:

int b = a[0];
int c = a[1];
int d = b * c; // stall occurs here
因此,如果我能做到这一点:

int b = a[0];
int c = a[1];

//  do lots of other work here
int d = b * c; // this might not stall
对于Fermi和Kepler GPU,对全局内存的写入(以及从先前写入的值读取,假设它们没有从缓存中逐出)由缓存提供服务,因此似乎要写入全局内存的线程代码通常会写入一级或二级缓存,而对全局内存的实际写入事务将在稍后发生,也不一定会造成任何形式的摊位

因此,在您的示例中,通常
a
将由缓存提供服务:

__device__ int a;
int b, c, d;
a = b * c; // a gets written to cache
d = a + 1; // a is serviced from cache
请注意,缓存中的服务仍然比最快的访问机制(例如寄存器和共享内存)慢,但比全局内存暂停快得多

说到这里,编译器通常会做一些可能会影响它的事情。首先,编译器可能会发现独立的工作,并在某种程度上为您重新排序代码,而不是手动重新排序代码。其次,在您的示例中,编译器将发现
a
被重复使用,除了在某个点更新全局内存中的值外,还很可能将其分配给寄存器变量。它位于寄存器中的事实意味着在上面示例的最后一行中使用
a
,很可能会从寄存器中得到服务,而不是全局内存或缓存


所以为了回答你们的问题,我想说,一般来说,你们的假设是不正确的。编译器将发现
a
的重复使用,并将其分配到寄存器,完全消除您认为存在的危险。理论上,如果没有缓存(对于compute 1.x设备是如此)和寄存器,那么编译器可能会按照您的建议被迫使用全局内存,但实际上不会发生这种情况。

CUDA编译器根据数据依赖性调度指令。它知道长延迟指令(如加载),并尝试提前安排它们。一般来说,不需要重新安排源代码以考虑长延迟操作,但编译器可能无法跨分支或函数调用移动负载。寄存器的使用有一个折衷。编译器时间表越早加载,temp regs的活动范围越长,寄存器压力越高。由于寄存器文件较小,在费米级GPU上实现良好的平衡尤其困难
__device__ int a;
int b, c, d;
a = b * c; // a gets written to cache
d = a + 1; // a is serviced from cache