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

了解CUDA网格尺寸、块尺寸和线程组织(简单说明),cuda,nvidia,Cuda,Nvidia,GPU如何组织线程执行?硬件 例如,如果一个GPU设备有4个多处理单元,每个单元可以运行768个线程:那么在给定时刻,实际并行运行的线程不会超过4*768个(如果您计划了更多线程,那么它们将等待轮到它们) 软件 线程以块的形式组织。块由多处理单元执行。 可以使用1维(x)、2维(x,y)或3维索引(x,y,z)来识别(索引)块的线程,但在任何情况下,xyz假设9800GT GPU: 它有14个多处理器(SM) 每个SM有8个线程处理器(也称为流处理器、SP或内核) 每个块最多允许512个线程

GPU如何组织线程执行?

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

软件 线程以块的形式组织。块由多处理单元执行。 可以使用1维(x)、2维(x,y)或3维索引(x,y,z)来识别(索引)块的线程,但在任何情况下,xyz假设9800GT GPU:

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

一个块的活动线程数不能超过512个,因此
\u syncthreads
只能同步有限数量的线程。i、 e.如果使用600个线程执行以下操作:

func1();
__syncthreads();
func2();
__syncthreads();
那么内核必须运行两次,执行顺序为:

  • 对前512个线程执行func1
  • 对前512个线程执行func2
  • 对其余线程执行func1
  • 对其余线程执行func2
  • 注意:

    主要的一点是
    \uu syncthreads
    是一个块范围的操作,它不会同步所有线程


    我不确定
    \u syncthreads
    可以同步的线程的确切数量,因为您可以创建一个包含512个以上线程的块,并让warp处理调度。据我所知,更准确的说法是:至少在前512个线程中执行func1

    在编辑这个答案之前(回到2010年),我测量了14x8x32个线程是使用
    \uuu syncthreads
    同步的


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

    如果每个块可以运行768个线程,为什么只使用64个?如果使用768的最大限制,则块会更少,因此性能会更好。@Aliza:块是逻辑的,768个线程的限制适用于每个物理处理单元。根据问题的规格使用块,以便将工作分配给线程。对于您遇到的每个问题,您不可能总是使用768个线程的块。假设您必须处理64x64图像(4096像素)。4096/768=5.333333块?块是逻辑块,但每个块都分配给一个核心。如果块多于核心,则块将排队,直到核心变为空闲。在您的示例中,您可以使用6个块,而让额外的线程不做任何事情(第6个块上有2/3的线程)。@cibercitizen1-我认为Aliza的观点很好:如果可能,您希望每个块使用尽可能多的线程。如果有一个约束需要更少的线程,最好在第二个示例中解释为什么会出现这种情况(但仍然要首先解释更简单和更理想的情况)。@thouis Yes,maybe。但情况是,每个线程所需的内存量取决于应用程序。例如,在我的上一个程序中,每个线程调用一个最小二乘优化函数,需要“大量”内存。如此之多,以至于块不能大于4x4个线程。即使如此,与顺序版本相比,所获得的加速比也是惊人的。如果func2()依赖于func1()的结果,会发生什么。我想这是wrong@Chris我在七年前写过这篇文章,但如果我没记错的话,我做了一个测试,得出了一个结论,即线程数超过gpu的内核会以这种方式运行。如果您碰巧测试了这个案例并得到了不同的结果,那么我将不得不删除此帖子。对不起,我认为这是错误的,而且GPU只能同时运行112个线程。@StevenLu您尝试过吗?我也不认为112个并发线程对GPU有任何意义。112是流处理器的数量。我几乎记不起CUDA了:)@StevenLu最大线程数不是这里的问题,
    \uu syncthreads
    是一个块范围的操作,实际上它并没有同步所有线程,这对CUDA学习者来说是一个麻烦。所以我根据你给我的信息更新了我的答案。我真的很感激。CUDA编程指南应该是一个很好的开始。我还建议您从中查看CUDA介绍。
    dim3 numBlocks(imageWidth/threadsPerBlock.x,  /* for instance 512/8 = 64*/
                  imageHeight/threadsPerBlock.y); 
    
    myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );       
    
    uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
    uint j = (blockIdx.y * blockDim.y) + threadIdx.y;
    
    func1();
    __syncthreads();
    func2();
    __syncthreads();