CUDA 线程和块组织方向
CUDA thread and block organization directions
在 CUDA 编程中,线程和块有多个方向(x、y 和 z)。
直到现在,我都忽略了这一点,只考虑了 x 方向(threadIdx.x、blockIdx.x、blockDim.x 等)。
显然,块内的线程和网格上的块都排列成立方体。但是,如果是这种情况,为什么指定 x 方向就足够了?我不会像那样处理多个线程吗?仅使用 x 方向,我是否能够处理我的 GPU 可用的所有线程?
Only using the x direction, am I able to address all threads available to my GPU?
如果我们谈论的是启动约 2 万亿个线程或更少的线程,那么就没有使用多维块或网格的特殊要求。所有具有 3.0 及更高计算能力的 CUDA GPU 都可以启动多达约 20 亿个块 (2^31-1),每个块有 1024 个线程,使用一维网格组织。
使用像 grid-stride loop 这样的方法,对我来说似乎很少 需要 .
超过 2 万亿个线程
我声称可以在 1D 网格中实现的任何问题都可以在 2D 或 3D 网格中实现,反之亦然,但没有正式的证据。这只是从一种实现到另一种实现的数学映射。此外,应该可以在任一实现中安排重要的副产品,如合并访问。
以一维或多维方式实现时,可能会有一些可读性优势、代码复杂性优势以及可能的小性能考虑。我能想到的通常情况是要处理的数据“本质上”是多维的。在这种情况下,让 CUDA 引擎为您生成 2 或 3 个不同的索引:
int idx = threadIdx.x+blockDim.x*blockIdx.x;
int idy = threadIdx.y+blockDim.y*blockIdx.y;
可能比使用一维网格索引并从中计算二维数据索引更简单:
int tid = threadIdx.x+blockDim.x*blockIdx.x;
int idx = tid%DATA_WIDTH;
int idy = tid/DATA_WIDTH;
(上面的整数除法运算在一般情况下是不可避免的,可以利用整数除法的结果简化取模运算。)
当只创建一维网格时,可以说这是到达同一点所需的额外代码行和额外除法运算。但是我建议即使这是小土豆,作为程序员,您应该使用对您来说最合理和最舒适的方法。
如果出于某种原因您希望启动超过 2 万亿个线程,那么至少无法避免转向多维网格。
Apparently, both threads within a block and blocks on the grid are arranged as a cube.
要了解在任何情况下如何计算 threadblock 线程索引,请参阅 the programming guide。很明显,一种情况可以等同于另一种情况——无论您如何指定线程块尺寸,每个线程都会获得一个唯一的线程 ID。在我看来,线程块应该只被认为是线程的“立方体”(即 3 维)如果您以这种方式指定配置:
dim3 block(32,8,4); //for example
However, if this is the case, why is it enough to specify the x direction? Would I not address multiple threads like that?
如果在 32、8、4 的情况下仅使用单个线程块维度创建线程索引:
int tid = threadIdx.x;
那么您肯定会使用该方法“寻址”多个线程(在 y 和 z 中)。根据我的经验,这通常是“损坏的”代码。因此,如果块或网格被指定为一维,则设计为使用多维块或网格的内核可能无法正常工作,反之亦然。您可以在 cuda
标签上找到此类问题的示例(线程索引计算对于网格设计不正确)。
在 CUDA 编程中,线程和块有多个方向(x、y 和 z)。
直到现在,我都忽略了这一点,只考虑了 x 方向(threadIdx.x、blockIdx.x、blockDim.x 等)。
显然,块内的线程和网格上的块都排列成立方体。但是,如果是这种情况,为什么指定 x 方向就足够了?我不会像那样处理多个线程吗?仅使用 x 方向,我是否能够处理我的 GPU 可用的所有线程?
Only using the x direction, am I able to address all threads available to my GPU?
如果我们谈论的是启动约 2 万亿个线程或更少的线程,那么就没有使用多维块或网格的特殊要求。所有具有 3.0 及更高计算能力的 CUDA GPU 都可以启动多达约 20 亿个块 (2^31-1),每个块有 1024 个线程,使用一维网格组织。
使用像 grid-stride loop 这样的方法,对我来说似乎很少 需要 .
超过 2 万亿个线程我声称可以在 1D 网格中实现的任何问题都可以在 2D 或 3D 网格中实现,反之亦然,但没有正式的证据。这只是从一种实现到另一种实现的数学映射。此外,应该可以在任一实现中安排重要的副产品,如合并访问。
以一维或多维方式实现时,可能会有一些可读性优势、代码复杂性优势以及可能的小性能考虑。我能想到的通常情况是要处理的数据“本质上”是多维的。在这种情况下,让 CUDA 引擎为您生成 2 或 3 个不同的索引:
int idx = threadIdx.x+blockDim.x*blockIdx.x;
int idy = threadIdx.y+blockDim.y*blockIdx.y;
可能比使用一维网格索引并从中计算二维数据索引更简单:
int tid = threadIdx.x+blockDim.x*blockIdx.x;
int idx = tid%DATA_WIDTH;
int idy = tid/DATA_WIDTH;
(上面的整数除法运算在一般情况下是不可避免的,可以利用整数除法的结果简化取模运算。)
当只创建一维网格时,可以说这是到达同一点所需的额外代码行和额外除法运算。但是我建议即使这是小土豆,作为程序员,您应该使用对您来说最合理和最舒适的方法。
如果出于某种原因您希望启动超过 2 万亿个线程,那么至少无法避免转向多维网格。
Apparently, both threads within a block and blocks on the grid are arranged as a cube.
要了解在任何情况下如何计算 threadblock 线程索引,请参阅 the programming guide。很明显,一种情况可以等同于另一种情况——无论您如何指定线程块尺寸,每个线程都会获得一个唯一的线程 ID。在我看来,线程块应该只被认为是线程的“立方体”(即 3 维)如果您以这种方式指定配置:
dim3 block(32,8,4); //for example
However, if this is the case, why is it enough to specify the x direction? Would I not address multiple threads like that?
如果在 32、8、4 的情况下仅使用单个线程块维度创建线程索引:
int tid = threadIdx.x;
那么您肯定会使用该方法“寻址”多个线程(在 y 和 z 中)。根据我的经验,这通常是“损坏的”代码。因此,如果块或网格被指定为一维,则设计为使用多维块或网格的内核可能无法正常工作,反之亦然。您可以在 cuda
标签上找到此类问题的示例(线程索引计算对于网格设计不正确)。