CUDA确定每个块的线程,每个网格块

我刚接触CUDA范例。 我的问题是确定每个块的线程数,每个网格块。 有一些艺术和审判玩这个? 我发现,很多例子都是为这些事情select了一个看似随意的数字。

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

一般来说,您希望调整块/网格以匹配数据,同时最大化占用率,即一次激活多less个线程。 影响占用率的主要因素是共享内存使用率,寄存器使用率和线程块大小。

支持CUDA的GPU将其处理能力分解为SM(stream式多处理器),并且SM的数量取决于实际的卡,但为了简单起见,我们将重点关注单个SM(它们都performance相同)。 每个SM具有有限数量的32位寄存器,共享存储器,最大数量的活动块,以及最大数量的活动线程。 这些数字取决于您的GPU的CC(计算能力),可以在维基百科文章http://en.wikipedia.org/wiki/CUDA中find

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

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

关于你的网格的话题…网格中的块被分散到SMs上,然后剩余的块被放入pipe道中。 只要该SM中有足够的资源接收该块,块就被移入SM中进行处理。 换句话说,当SM中的块完成时,新的块将被移入。您可能会认为具有更小的块(在前面的示例中为128,而不是256)可能会更快地完成,因为特别慢的块将占用更less的资源,但是这非常依赖于代码。

关于寄存器和共享内存,请看下一步,因为它可能会限制你的占用。 共享内存对于整个SM来说是有限的,所以尽量使用它,尽可能多的块仍然适合SM。 注册使用也一样。 再次,这些数字取决于计算能力,可以在维基百科页面上列出。 祝你好运!

http://developer.download.nvidia.com/compute/cuda/CUDA_Occupancy_calculator.xls

CUDA占用率计算器允许您通过给定的CUDA内核来计算GPU的多处理器占用率 。 多处理器占用率是GPU的多处理器上支持的最大活动warps数量与最大warp数量的比率。 设备上的每个多处理器都有一组N个寄存器供CUDA程序线程使用。 这些寄存器是在多处理器上执行的线程块之间分配的共享资源。 CUDA编译器试图最大限度地减less寄存器的使用,以最大限度地增加机器中可以同时激活的线程块的数量。 如果一个程序试图启动每个线程使用的寄存器的内核次数,线程块大小大于N,则启动将失败。

除了罕见的例外,你应该使用每块的恒定数量的线程。 然后每个网格的块数由问题的大小决定,例如matrix乘法情况下的matrix维数。

select每个块的线程数是非常复杂的。 大多数CUDAalgorithm都有很大的可能性,而select是基于内核运行效率最高的。 由于线程调度硬件的工作原理,它几乎总是32的倍数,至less是64。 第一次尝试的好select是128或256。

您还需要考虑共享内存,因为同一个块中的线程可以访问相同的共享内存。 如果你devise的东西需要大量的共享内存,那么每块更多的线程可能是有利的。

例如,就上下文切换而言,32的任何倍数都是一样的。 因此,对于一维情况,启动一个有64个线程的块或者有32个线程的2个块对于全局内存访问是没有区别的。 但是,如果手头的问题自然分解为长度为64的vector,那么第一个选项会比第二个选项更好(更less的内存开销,每个线程都可以访问相同的共享内存)。