可以提前设置一个自变量,提高性能吗?

时间:2013-06-09 13:03:23

标签: cuda

  

线程不会因内存访问而失速

来自Vasily Volkov的着名论文http://www.cs.berkeley.edu/~volkov/volkov10-GTC.pdf

我假设基于这个陈述:

__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未被缓存。

1 个答案:

答案 0 :(得分:2)

引用的档位确实是内存读取

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

假设我有:

__device__ int a[32];

然后这个线程代码不会导致停顿(虽然它会生成内存事务):

int b = a[0];

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

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,写入(并且从先前写入的值读取,假设它们没有从缓存中逐出)到全局存储器由缓存提供服务,因此线程代码似乎是写入全局内存通常是写入L1或L2缓存,而实际的全局内存写入事务将在以后发生,并不一定会造成任何类型的停顿。

因此,在您的示例中,通常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的重用并将其分配给寄存器,完全消除您认为存在的危险。从理论上讲,如果没有缓存(对于计算1.x设备是正确的)并且没有寄存器,那么编译器可能会被迫按照您的建议使用全局内存,但实际上它不会发生。