63

我是 CUDA 范式的新手。我的问题是确定每个块的线程数和每个网格的块数。有一点艺术和试验的作用吗?我发现很多例子都为这些东西选择了看似任意的数字。

我正在考虑一个问题,我可以将任意大小的矩阵传递给乘法方法。因此,C 的每个元素(如 C = A * B)将由单个线程计算。在这种情况下,您将如何确定线程/块、块/网格?

4

5 回答 5

99

通常,您希望调整块/网格的大小以匹配您的数据并同时最大化占用率,即一次有多少线程处于活动状态。影响占用率的主要因素是共享内存使用、寄存器使用和线程块大小。

启用 CUDA 的 GPU 将其处理能力拆分为 SM(流式多处理器),SM 的数量取决于实际的卡,但为了简单起见,这里我们将专注于单个 SM(它们的行为都相同)。每个 SM 都有有限数量的 32 位寄存器、共享内存、最大数量的活动块和最大数量的活动线程。这些数字取决于您的 GPU 的 CC(计算能力),可以在 Wikipedia 文章http://en.wikipedia.org/wiki/CUDA的中间找到。

首先,您的线程块大小应该始终是 32 的倍数,因为内核在 warp(32 个线程)中发出指令。例如,如果您有 50 个线程的块大小,GPU 仍会向 64 个线程发出命令,而您只是在浪费它们。

其次,在担心共享内存和寄存器之前,请尝试根据与卡的计算能力相对应的最大线程数和块数来调整块的大小。有时有多种方法可以做到这一点……例如,CC 3.0 卡每个 SM 可以有 16 个活动块和 2048 个活动线程。这意味着如果每个块有 128 个线程,则可以在 SM 中容纳 16 个块,然后再达到 2048 个线程的限制。如果您使用 256 个线程,则只能容纳 8 个线程,但您仍在使用所有可用线程并且仍将完全占用。然而,当达到 16 个块的限制时,每个块使用 64 个线程只会使用 1024 个线程,因此只有 50% 的占用率。如果共享内存和寄存器的使用不是瓶颈,这应该是您主要关心的问题(除了您的数据维度)。

关于你的网格的主题......你的网格中的块分散在 SM 上以开始,然后将剩余的块放入管道中。一旦 SM 中有足够的资源来获取块,块就会被移动到 SM 中进行处理。换句话说,当块在 SM 中完成时,新的块会被移入。您可以认为具有较小的块(128 而不是前面示例中的 256)可能会更快完成,因为特别慢的块会占用更少的资源,但是这在很大程度上取决于代码。

关于寄存器和共享内存,请看下一个,因为它可能会限制您的占用。共享内存对于整个 SM 来说是有限的,因此请尝试以允许尽可能多的块仍然适合 SM 的数量使用它。寄存器使用也是如此。同样,这些数字取决于计算能力,可以在维基百科页面上找到。祝你好运!

于 2012-10-16T19:11:13.050 回答
22

https://docs.nvidia.com/cuda/cuda-occupancy-calculator/index.html

CUDA 占用计算器允许您通过给定的 CUDA 内核计算 GPU 的多处理器占用。多处理器占用率是 GPU 的多处理器上支持的活动扭曲与最大扭曲数的比率。设备上的每个多处理器都有一组 N 个寄存器可供 CUDA 程序线程使用。这些寄存器是在多处理器上执行的线程块之间分配的共享资源。CUDA 编译器尝试最小化寄存器使用以最大化机器中可以同时处于活动状态的线程块的数量。如果程序尝试启动内核,而每个线程使用的寄存器乘以线程块大小大于 N,则启动将失败...

于 2010-12-09T04:54:37.150 回答
16

除了极少数例外,您应该在每个块中使用恒定数量的线程。然后每个网格的块数由问题大小决定,例如矩阵乘法中的矩阵维数。

选择每个块的线程数非常复杂。大多数 CUDA 算法都承认有很大范围的可能性,并且选择基于使内核最有效地运行的因素。由于线程调度硬件的工作方式,它几乎总是 32 的倍数,并且至少是 64。第一次尝试的好选择是 128 或 256。

于 2010-12-08T19:20:54.703 回答
3

You also need to consider shared memory because threads in the same block can access the same shared memory. If you're designing something that requires a lot of shared memory, then more threads-per-block might be advantageous.

For example, in terms of context switching, any multiple of 32 works just the same. So for the 1D case, launching 1 block with 64 threads or 2 blocks with 32 threads each makes no difference for global memory accesses. However, if the problem at hand naturally decomposes into 1 length-64 vector, then the first option will be better (less memory overhead, every thread can access the same shared memory) than the second.

于 2011-11-08T20:03:28.057 回答
1

没有银弹。每个块的最佳线程数很大程度上取决于被并行化的特定应用程序的特性。CUDA 的设计指南建议当卸载到 GPU 的函数有多个障碍时,每个块使用少量线程,但是,有实验表明,对于某些应用程序,每个块的少量线程会增加同步的开销,从而产生更大的开销. 相反,每个块的线程数较多可能会减少同步量并提高整体性能。

有关每个块的线程数对 CUDA 内核的影响的深入讨论(对于 StackOverflow 来说太长了),请查看这篇期刊文章,它显示了 NPB(NAS Parallel)中每个块的线程数的不同配置的测试基准)套件,一组 CFD(计算流体动力学)应用程序。

于 2021-12-20T19:02:51.763 回答