首页 > 解决方案 > CUDA线程和块组织方向

问题描述

在 CUDA 编程中,线程和块有多个方向(x、y 和 z)。

到目前为止,我忽略了这一点,只考虑了 x 方向(threadIdx.x、blockIdx.x、blockDim.x 等)。

显然,块内的线程和网格上的块都排列为立方体。但是,如果是这种情况,为什么指定 x 方向就足够了?我不会像那样处理多个线程吗?仅使用 x 方向,我是否能够处理我的 GPU 可用的所有线程?

标签: cuda

解决方案


仅使用 x 方向,我是否能够处理我的 GPU 可用的所有线程?

如果我们谈论的是启动约 2 万亿或更少线程的愿望,那么就没有特别要求使用多维块或网格。所有具有 3.0 及更高计算能力的 CUDA GPU 都可以使用一维网格组织启动多达约 20 亿个块 (2^31-1),每个块有 1024 个线程。

使用网格步长循环之类的方法,对我来说似乎很少需要超过 2 万亿个线程。

我在没有正式证据的情况下声称可以在 1D 网格中实现的任何问题都可以在 2D 或 3D 网格中实现,反之亦然。这只是从一种实现到另一种实现的数学映射。此外,应该可以在任一实现中安排重要的副产品,例如合并访问。

当以 1D 或多维方式实现时,可能会有一些可读性优势、代码复杂性优势以及可能的较小性能考虑。我能想到的通常情况是要处理的数据“固有地”是多维的。在这种情况下,让 CUDA 引擎为您生成 2 或 3 个不同的索引:

int idx = threadIdx.x+blockDim.x*blockIdx.x;
int idy = threadIdx.y+blockDim.y*blockIdx.y;

可能比使用 1D 网格索引并从这些索引计算 2D 数据索引更简单:

int tid = threadIdx.x+blockDim.x*blockIdx.x;
int idx = tid%DATA_WIDTH;
int idy = tid/DATA_WIDTH;

(上面的整数除法运算在一般情况下是不可避免的。模运算可以使用整数除法的结果来简化。)

可以说,当只创建一维网格时,到达同一点需要额外的代码行和额外的除法运算。但是,我建议即使这是小菜一碟,作为程序员,您应该使用对您来说最合理和最舒适的方法。

如果出于某种原因您希望启动超过 2 万亿个线程,那么至少移动到多维网格是不可避免的。

显然,块内的线程和网格上的块都排列为立方体。

要了解在任何情况下如何计算线程块线程索引,请参阅编程指南。很明显,一种情况可以等同于另一种情况——无论您如何指定线程块尺寸,每个线程都会获得一个唯一的线程 ID。在我看来,如果您以这种方式指定配置,则只能将线程块视为线程的“立方体”(即 3 维):

dim3 block(32,8,4);  //for example

但是,如果是这种情况,为什么指定 x 方向就足够了?我不会像那样处理多个线程吗?

如果在 32,8,4 的情况下只使用单个线程块维度创建线程索引:

int tid = threadIdx.x;

那么您肯定会使用该方法“处理”多个线程(在 y 和 z 中)。根据我的经验,这通常是“损坏”的代码。因此,如果将块或网格指定为一维,则设计为使用多维块或网格的内核可能无法正常工作,并且相反的陈述也是正确的。cuda您可以在标签上找到此类问题的示例(线程索引计算对于网格设计不正确) 。


推荐阅读