CUDA.如何展开前32个线程,以便并行执行
CUDA. How to unroll first 32 threads so they will be executed in parallel?
我知道"每个经线包含连续的线程,增加第一个经线包含线程0的线程id "所以前32个线程应该在第一个经线。我还知道,在一个warp中的所有线程在任何可用的流多处理器上同时执行。
据我所知,因为没有必要在线程同步,如果只有一个经纱正在执行。但是如果我在倒数第二个if
块中删除任何__syncthreads()
,下面的代码会产生错误的答案。我试图找出原因,但却一无所获。我非常希望得到你的帮助,你可以告诉我这个代码有什么问题吗?为什么我不能只留下最后一个__syncthreads()
而得到正确的答案?
#define BLOCK_SIZE 128
__global__ void reduce ( int * inData, int * outData )
{
__shared__ int data [BLOCK_SIZE];
int tid = threadIdx.x;
int i = blockIdx.x * blockDim.x + threadIdx.x;
data [tid] = inData [i] + inData [i + blockDim.x / 2 ];
__syncthreads ();
for ( int s = blockDim.x / 4; s > 32; s >>= 1 )
{
if ( tid < s )
data [tid] += data [tid + s];
__syncthreads ();
}
if ( tid < 32 )
{
data [tid] += data [tid + 32];
__syncthreads ();
data [tid] += data [tid + 16];
__syncthreads ();
data [tid] += data [tid + 8];
__syncthreads ();
data [tid] += data [tid + 4];
__syncthreads ();
data [tid] += data [tid + 2];
__syncthreads ();
data [tid] += data [tid + 1];
__syncthreads ();
}
if ( tid == 0 )
outData [blockIdx.x] = data [0];
}
void main()
{
...
reduce<<<dim3(128), dim3(128)>>>(dev_data, dev_res);
...
}
注:我用的是GT560Ti
您应该将共享内存变量声明为volatile:
__shared__ volatile int data [BLOCK_SIZE];
你看到的问题是费米架构和编译器优化的产物。费米架构缺乏直接操作共享内存的指令(它们存在于G80/90/GT200系列中)。因此,所有内容都被加载到注册、操作并存储回共享内存中。但是编译器可以自由地推断,如果将一系列操作暂存到寄存器中,而不需要从共享内存中加载和存储,则代码可以编写得更快。这是非常好的,除了,当您依赖于同一warp内操作共享内存的线程的隐式同步时,就像在这种缩减代码中一样。
通过将共享内存缓冲区声明为volatile,您将强制编译器在每个缩减阶段之后强制执行共享内存写入,并且在warp内的线程之间的隐式数据同步被恢复。
这个问题在Fermi的编程说明中讨论,它随CUDA工具包一起发货(或可能发货)。
相关文章:
- 并行块(线程清理器)之外的 OpenMP 中的争用条件;误报?
- MFC执行线程问题
- Qt不能多次执行线程
- OpenMP 并行编程基于线程数与执行时间的关系
- future::wait() 是否与 async() 执行线程的完成同步?
- 从并行线程在主 Maya 线程上执行代码
- 将执行从一个线程移动到另一个线程,以实现任务并行性并在将来调用
- 在C++中并行运行线程
- 如何在 WinRT 下的并行线程中执行 c++ 函数
- CUDA - 了解线程的并行执行(扭曲)和合并的内存访问
- std::线程何时执行线程
- 英特尔 TBB 并行循环线程 ID
- 如何在每个块的元素多于线程的数组上执行并行扫描
- OpenMP:为什么这些omp并行部分不是用多个线程执行的
- 使用for循环执行线程
- 并行线程执行以实现性能
- 松弛的内存顺序效果是否可以扩展到执行线程的生命周期之后?
- 在C++11中,"不代表执行线程"的线程有什么意义?
- 使用openmp并行中止线程
- C++ 线程执行时间和另一个线程中的执行线程