CUDA.如何展开前32个线程,以便它们并行执行?

Вит*_*ров 7 c++ cuda gpu

我知道"每个warp包含连续增加的线程ID的线程,第一个warp包含线程0",因此前32个线程应该在第一个warp中.另外我知道一个warp中的所有线程都在任何可用的Streaming Multiprocessor上同时执行.

据我所知,因为如果只执行一个warp,就不需要线程同步.但是如果我删除__syncthreads()倒数第二个if块中的任何一个,下面的代码会产生错误的答案.我试图找到原因,但最终没有任何结果.我真的希望得到你的帮助,所以你可以告诉我这段代码有什么问题?为什么我不能只留下最后__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);
...
}
Run Code Online (Sandbox Code Playgroud)

PS我正在使用GT560Ti

tal*_*ies 7

您应该将共享内存变量声明为volatile:

__shared__ volatile int data [BLOCK_SIZE]; 
Run Code Online (Sandbox Code Playgroud)

您看到的问题是Fermi架构和编译器优化的工件.Fermi架构缺乏直接在共享存储器上运行的指令(它们存在于G80/90/GT200系列中).所以一切都被加载到注册,操作和存储回共享内存.但是编译器可以自由地推断,如果在寄存器中暂存一系列操作,则可以使代码更快,而不需要从共享内存中间加载和存储.这非常好,除非您依赖于同一warp操作共享内存中的线程的隐式同步,就像在这种缩减代码中一样.

通过将共享内存缓冲区声明为volatile,您将强制编译器在减少的每个阶段之后强制执行共享内存写入,并且还原warp中线程之间的隐式数据同步.

Fermi的编程说明中讨论了这个问题,该编程说明随CUDA工具包一起发布(或可能随附).