我想知道我可以在GPU上发送的线程/线程组的“网格”。我正在使用Direct Compute,所以我将使用该API给出一个具体的例子。例如,如果我调用Dispatch(2,2,2),我理解它总共调度2x2x2 = 8个线程组。但是,如果我调用Dispatch(8,1,1),它还调度8x1x1 = 8个线程组,那有什么区别?有没有性能差异?
P.S。与GPU上的线程相同的问题。在计算(.hlsl)文件中声明的numthreads(2,2,2)和numthreads(8,1,1)之间的区别是什么?
任何帮助都将不胜感激。
答案 0 :(得分:13)
从纯粹的性能角度来看,本身并没有真正的差异,因为定义线程组或块的网格维度的能力更多是为了正确地将工作负载应用于问题本身的抽象而不是表现。换句话说,如果您的问题很好地抽象到3D体积网格,那么虽然可以使用将3D问题转换为1D线性表示的映射来创建相同数量的线程组/块,但是该映射的抽象处理起来可能有点麻烦。此外,如果映射太复杂,可能会造成很小的性能损失。
您创建的线程组/块的数量以及这些块中的线程数很重要。在Nvidia GPU的情况下,每个线程组被分配给GPU上的SMX处理器,并且将多个线程块及其相关联的线程映射到SMX对于隐藏由于存储器访问等引起的延迟是必要的。此外,您想要在线程组/块中拥有足够的线程,以便利用GPU的SIMT(相同指令/多线程)功能。这意味着对于Nvidia GPU的SMX内的每个时钟周期(或一组时钟周期),它可以在锁定步骤中同时执行X个线程。这个数字称为"线程扭曲"尺寸。您希望块中有足够的线程来填充此扭曲计数,否则当GPU在GPU的个别SMX上运行时,GPU核心流处理器的资源不会被耗尽处理器。这个数字是Nvidia Fermi GPU上的32个主题。在CUDA中,您可以根据您正在使用的GPU查询此信息,尽管我假设使用DirectCompute,这将被抽象掉。 ATI卡还有一个"螺纹宽度"他们的流媒体处理器也是64个线程/#34; wavefront"。
理想情况下,您最终希望在块中有足够的线程来填充wavefront中的线程数或GPU的warp大小,然后可以映射到GPU上的每个流处理器的大量块这样,无论何时遇到高延迟操作,它们都可以保持在飞行中并在流处理器上交换。这最大化了GPU的计算带宽。
答案 1 :(得分:2)
一个块可以以三维方式排列线程。
让我们举个例子。 假设您要分派32个线程。这32个线程可以以三维方式排列。想象一下轴系统有X,Y和Z轴。您可以只安排所有32个线程和X轴.i.e。 (32,1,1)。或者你可以将它与X轴和Y轴一起排列(如2D矩阵)(8,4,1),即8列,4行。或者你也可以用3维方式排列,(8,2,2)即8列,2行和2(想象一个高度为8,宽度为2,长度为2的立方体)。试着想象并构建图片你的想法。