了解CUDA网格尺寸,块尺寸和线程组织(简单说明)


161

如何组织线程以由GPU执行?


CUDA编程指南应该是开始的好地方。我还建议您从此处查看CUDA简介。
汤姆

Answers:


287

硬件

例如,如果一个GPU设备具有4个多处理单元,并且每个单元可以运行768个线程:那么在给定的时刻,真正并行运行的线程将不超过4 * 768(如果您计划更多的线程,它们将在等待轮到他们了)。

软件

线程按块组织。块由多处理单元执行。可以使用1Dimension(x),2Dimensions(x,y)或3Dim索引(x,y,z)来标识(索引)块的线程,但在任何情况下,对于我们的示例,x y z <= 768(适用其他限制)到x,y,z,请参阅指南和您的设备功能)。

显然,如果您需要多个4 * 768线程,则需要四个以上的块。块也可以索引为1D,2D或3D。等待进入GPU的队列有很多(因为在我们的示例中,GPU有4个多处理器,并且只有4个块正在同时执行)。

现在是一个简单的案例:处理512x512的图片

假设我们要一个线程处理一个像素(i,j)。

我们可以每个使用64个线程的块。然后我们需要512 * 512/64 = 4096块(因此要具有512x512线程= 4096 * 64)

通常将具有blockDim = 8 x 8(每个块64个线程)的2D块中的线程组织起来(使索引索引更容易)。我更喜欢将其称为threadsPerBlock。

dim3 threadsPerBlock(8, 8);  // 64 threads

和2D gridDim = 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;

11
如果每个块可以运行768个线程,为什么只使用64个?如果使用768的最大限制,则将具有更少的块并因此具有更好的性能。
Aliza

10
@Aliza:逻辑块,每个物理处理单元最多768个线程。您可以根据问题的规格使用块,以便将工作分配给线程。您不可能总是为遇到的每个问题使用768个线程的块。假设您必须处理64x64图像(4096像素)。4096/768 = 5.333333块
cibercitizen11

1
块是逻辑的,但是每个块都分配给一个内核。如果块多于核心,则将这些块排队直到核心空闲为止。在您的示例中,您可以使用6个块,并使多余的线程不执行任何操作(第6个块中的线程的2/3)。
Aliza

3
@ cibercitizen1-我认为Aliza的观点很不错:如果可能的话,每个块要使用尽可能多的线程。如果存在需要较少线程的约束,则在第二个示例中更好地解释为什么会是这种情况(但仍然首先解释更简单和更理想的情况)。

6
@thouis是的,也许。但是情况是每个线程所需的内存量取决于应用程序。例如,在我的上一个程序中,每个线程调用一个最小二乘优化函数,需要“大量”内存。这么多,这些块不能大于4x4线程。即便如此,与顺序版本相比,获得的提速还是惊人的。
cibercitizen1 2012年

9

假设9800GT GPU:

  • 它有14个多处理器(SM)
  • 每个SM具有8个线程处理器(AKA流处理器,SP或内核)
  • 每个块最多允许512个线程
  • warpsize为32(这意味着每个14x8 = 112线程处理器可以调度多达32个线程)

https://www.tutorialspoint.com/cuda/cuda_threads.htm

一个块的活动线程数不能超过512,因此__syncthreads只能同步有限数量的线程。即如果您使用600个线程执行以下操作:

func1();
__syncthreads();
func2();
__syncthreads();

那么内核必须运行两次,执行顺序为:

  1. 对于前512个线程执行func1
  2. 对于前512个线程执行func2
  3. 对其余线程执行func1
  4. 对其余线程执行func2

注意:

要点是__syncthreads块级操作,它不同步所有线程。


我不确定__syncthreads可以同步的确切线程数,因为您可以创建一个具有512个以上线程的块,并让warp处理调度。据我了解,更准确地说:func1 至少在前512个线程中执行。

在编辑此答案之前(早在2010年),我测量了14x8x32线程使用进行了同步__syncthreads

如果有人再测试一次以获得更准确的信息,我将不胜感激。


如果func2()取决于func1()的结果,会发生什么。我认为这是错的
克里斯(Chris

@Chris我是七年前写的,但是如果我没记错的话,我对此进行了测试,得出的结论是,线程多于gpu的内核的行为是这样的。如果您碰巧要测试此案例并得出不同的结果,那么我将不得不删除此帖子。
Bizhan

抱歉,我认为这也是错误的,GPU只能同时运行112个线程。
史蒂文·卢

@StevenLu您尝试过吗?同样,我认为112个并发线程对GPU没有任何意义。112是流处理器的数量。我现在几乎不记得CUDA了:)
Bizhan

1
@StevenLu此处最大线程数不是问题,它__syncthreads是一个块范围的操作,它实际上并未同步所有线程,这对CUDA学习者来说是个麻烦。因此,我根据您提供给我的信息更新了答案。我真的很感激。
Bizhan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.