何时使用volatile与共享CUDA内存

时间:2013-03-11 04:02:46

标签: compiler-construction cuda gpu gpgpu volatile

在什么情况下你应该将volatile关键字与CUDA内核的共享内存一起使用?我理解volatile告诉编译器永远不会缓存任何值,但我的问题是关于共享数组的行为:

__shared__ float products[THREADS_PER_ACTION];

// some computation
products[threadIdx.x] = localSum;

// wait for everyone to finish their computation
__syncthreads();

// then a (basic, ugly) reduction:
if (threadIdx.x == 0) {
    float globalSum = 0.0f;
    for (i = 0; i < THREADS_PER_ACTION; i++)
        globalSum += products[i];
}

在这种情况下,我是否需要products易变?每个数组条目只能由一个线程访问,除了最后,所有内容都由线程0读取。编译器是否可以缓存整个数组,因此我需要它为volatile,或者它只会缓存元素吗?

谢谢!

1 个答案:

答案 0 :(得分:16)

如果您没有将共享数组声明为volatile,那么编译器可以通过将它们放在寄存器(其范围特定于单个线程)中来优化共享内存中的位置,对于任何线程,在它的选择。无论您是否仅从一个线程访问该特定共享元素,都是如此。因此,如果您使用共享内存作为块的线程之间的通信工具,则最好将其声明为volatile

显然,如果每个线程只访问自己的共享内存元素,而不是那些与另一个线程相关的元素,那么这没关系,编译器优化不会破坏任何东西。

在您的情况下,如果您有一段代码,其中每个线程都访问它自己的共享内存元素,并且唯一的线程间访问发生在一个很好理解的位置,您可以使用memory fence function来强制编译器驱逐临时存储在寄存器中的任何值,退回到共享数组。因此,您可能认为__threadfence_block()可能有用,但在您的情况下,__syncthreads() already has memory-fencing functionality built in。因此,__syncthreads()调用足以强制执行线程同步,并强制将共享内存中的任何寄存器缓存值驱逐回共享内存。

顺便说一句,如果代码末尾的减少与性能有关,那么您可以考虑使用并行缩减方法来加速它。