CUDA线程寻址((threadIdx.x,threadIdx.y,threadIdx.z)和块寻址(blockidx.x,blockidx.y)

时间:2013-05-06 17:29:38

标签: cuda

我只需要澄清一些非常基本的东西 - 大多数计算实例都使用类似的东西:

ID = blockIdx.x * blockDim.x + threadIdx.x;

// ...然后对数组[ID]进行计算

我的问题是,如果我想在一个块(1024)中使用最大线程数,那么我是否真的需要'考虑所有(threadIdx.x,{{''构造'我的'threadID' 1}},threadIdx.y)?

如果是这样,建议将其散列为单个值的方法是什么?

如果不是这样,为什么有人会以类似的方式在图像处理相关的操作中使用它,例如在这篇文章中:

https://stackoverflow.com/questions/11503406/cuda-addressing-a-matrix

threadIdx.zblockidx.x如何与blockidx.y在这方面相同?

4 个答案:

答案 0 :(得分:8)

创建2D或3D线程块通常是因为问题适用于数据的2D或3D解释,并且使用2D或3D线程块处理它可能使代码更具可读性。但是没有具体的理由说明为什么不能使用具有适当索引的1D线程块。

创建2D或3D网格(块)通常是出于上述原因和/或绕过网格任意一维中块数量的前CC 3.0设备的限制(65535最大块)在任何方面)。

对于threadblock情况,您可以在一个维度中的单个块中使用1024个线程,因此如果不这样做,则无需使用threadIdx.ythreadIdx.z构建ID变量想要。

如果你有一个预CC 3.0设备,并且你的问题在块方面足够大,你可能仍然想要构建一个2D网格。您仍然可以在该网格中使用1D线程块。在这种情况下,可以创建一个唯一的ID变量,如:

 int idx = threadIdx.x + (((gridDim.x * blockIdx.y) + blockIdx.x)*blockDim.x);  

上述构造应该处理带有任何2D网格的1D线程块。

除了构建2D网格以处理大问题大小之外,还有其他方法,例如让您的块在某种循环中处理多个数据块。

答案 1 :(得分:0)

在您的示例中,

threadID是一个误导性术语。计算的值实际上是当前线程将读取或写入的数组的索引。如果使用多个块调用内核,则需要以这种方式计算索引以处理每个数组元素一次。

答案 2 :(得分:0)

请记住,将threadIdx.xthreadIdx.yblockIdx.xblockIdx.y散列为单个值的方式会影响您正在执行的全局内存访问的合并,请参阅哈里斯在这个帖子中的回答

CUDA coalesced access to global memory

答案 3 :(得分:0)

这是罗伯特克罗维拉的回答:

创建2D / 3D网格不仅仅是为了便于阅读,而且还用于利用片上共享内存中的2D / 3D位置,从而提供更快的访问速度。如果您的问题适用于2D网格,则无法使用1D网格有效利用此类位置。