GPU如何组织线程以便执行?
假设一个GPU设备有4个多处理器单元,并且它们可以每个运行768个线程:那么在某一时刻,最多只有4*768个线程会真正并行运行(如果您计划更多的线程,则它们将等待它们的轮到)。
线程被组织在块中。一个块由一个多处理器单元执行。块的线程可以使用1维(x)、2维(x、y)或3维(x、y、z)索引来识别(编号),但无论如何,对于我们的示例,xyz<=768(对x、y、z还有其他限制,请参见指南和设备能力)。
显然,如果您需要超过那4*768个线程,那么您就需要更多的块。块也可以索引为1D、2D或3D。有一个块队列等待进入GPU(因为在我们的示例中,GPU有4个多处理器单元,只有4个块同时被执行)。
假设我们想要一个线程来处理一个像素(i,j)。
我们可以使用每个块64个线程的块。然后我们需要4096个块(这样就有512x512个线程=4096x64)。
通常为了使图像索引更容易,将线程组织在2D块中,每个块的blockDim为8 x 8(每个块64个线程)。我更喜欢称其为threadsPerBlock。
dim3 threadsPerBlock(8, 8); // 64 threads
2D的网格大小为64 x 64个块(需要4096个块),我更喜欢称其为numBlocks。
dim3 numBlocks(imageWidth/threadsPerBlock.x, /* for instance 512/8 = 64*/
imageHeight/threadsPerBlock.y);
内核是这样启动的:
myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );
最后会有一个类似于“4096个块的队列”,其中一个块正在等待被分配给GPU的一个多处理器来执行其64个线程。
在内核中,要由线程处理的像素(i,j)是这样计算的:
uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
uint j = (blockIdx.y * blockDim.y) + threadIdx.y;
假设有一块9800GT显卡:
https://www.tutorialspoint.com/cuda/cuda_threads.htm
一个块不能有超过512个活动线程,因此__syncthreads
只能同步有限数量的线程。例如,如果您使用600个线程执行以下操作:
func1();
__syncthreads();
func2();
__syncthreads();
__syncthreads
是块级操作,它不会同步所有线程。
我不确定__syncthreads
可以同步多少个线程,因为你可以创建一个带有超过512个线程的块,并让warp处理调度。据我理解,更准确的说法是:func1至少执行前512个线程。
在我编辑这篇答案之前(2010年),我测量了14x8x32个线程使用__syncthreads
进行了同步。
如果有人能再次测试以获得更准确的信息,我将不胜感激。
__syncthreads
是一个块级操作,它实际上并没有同步所有线程,这对于 CUDA 学习者来说是一个麻烦。所以我根据你给我的信息更新了我的答案。非常感谢。 - Bizhan