GPU上的线程和线程组

13
我想了解在GPU上可以调度的线程/线程组的“网格”。我正在使用Direct Compute,因此我将使用该API给出一个具体的示例。例如,如果我调用Dispatch(2,2,2),我理解它会总共调度2x2x2=8个线程组。但是,如果我调用Dispatch(8,1,1)有什么区别呢?这也会调度8x1x1=8个线程组吗?是否存在性能差异?
附注:与GPU上的线程相同的问题。在计算(.hlsl)文件中声明的numthreads(2,2,2)和numthreads(8,1,1)之间有什么区别?
任何帮助都将不胜感激。
2个回答

15
从纯性能角度来看,实际上没有什么区别,因为定义线程组或块的网格的维度是为了正确地将工作负载应用于问题本身的抽象,而不是为了提高性能。换句话说,如果您的问题很好地抽象为三维体积网格,则可以使用将三维问题转换为一维线性表示的映射创建相同数量的线程组/块,但该映射的抽象可能会有些棘手。此外,如果映射过于复杂,可能会导致小型性能损失。
但是,创建的线程组/块数以及其中的线程数非常重要。在 Nvidia GPU 的情况下,每个线程组分配给 GPU 上的 SMX 处理器,并且将多个线程块及其相关线程映射到 SMX 中是必要的,以隐藏由于内存访问等引起的延迟。此外,您希望线程组/块中有足够的线程利用 GPU 的 SIMT(同一指令/多线程)功能。这意味着在 Nvidia GPU 的 SMX 内部的每个时钟周期(或一组时钟周期)内,它可以同时执行 X 个线程。这个数字称为 "线程束" 大小。您希望块中有足够的线程来填满此线程束计数,否则当块在 GPU 的单个 SMX 处理器上运行时,GPU 核心流处理器的资源不会被使用。在 Nvidia Fermi GPU 上,这个数字是 32 个线程。在 CUDA 中,您可以根据使用的 GPU 查询此信息,尽管我假设在 DirectCompute 中,这将被抽象化。ATI 显卡的流处理器也有一个 "线程宽度",每个 "wavefront" 有 64 个线程。
最理想的情况是,最终您要在块中有足够的线程来填满 GPU 的线程束或波形大小,并且有大量的块可以映射到 GPU 上的每个流处理器,以便它们可以保持流动并在遇到高延迟操作时在流处理器上交换。这最大化了 GPU 的计算带宽。

1
非常感谢。这是一个非常详细的答案。它回答了我的问题,还解决了我一些不确定的事情,我无法清楚地提出一个明确的问题。:) 再次感谢。我会给你+1,但正如你所看到的,我还没有足够的声誉。 - l3utterfly
刚给你点了个赞。刚刚因为采纳了你的答案获得了声望,哈哈。 - l3utterfly

2
一个块可以以三维方式排列线程。
让我们来看一个例子。假设您要分派32个线程。这32个线程可以以三维方式排列。想象一下带有X、Y和Z轴的坐标系。您可以仅沿着X轴排列所有32个线程,即(32,1,1)。或者您可以将其与X和Y轴一起排列(如2D矩阵)(8,4,1),即8列,4行。您还可以以三维方式排列,(8,2,2)即8列,2行和宽度为2(想象一个高度为8,宽度为2,长度为2的立方体)。试着在脑海中构建图像。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接