使用C ++在CUDA中为GPGPU创建2D网格

时间:2012-12-31 11:02:19

标签: cuda

我正在尝试将网格从1d扩展到2d网格。有没有办法做到这一点?

这是我目前的代码:

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

#include列表中,我有以下定义:

#define BLOCKS_PER_GRID 102

#define THREADS_PER_BLOCK 1024

3 个答案:

答案 0 :(得分:1)

假设您希望每个块有1024个线程,则可以轻松地将块重新整形为2D。

32 x 32 = 1024;

所以你的块看起来像这样:

dim3 Block(32,32); //1024 threads per block. Will only work for devices of at least 2.0 Compute Capability.

我不知道您的确切要求是什么,但通常不修复块数(正如您在宏中定义的那样)。块数取决于输入数据大小,因此网格可以动态扩展。

根据您的情况,您有很多选项,但网格最接近的最佳尺寸为17 x 66 x 17

dim3 Grid(17,6);

现在您可以使用以下参数调用内核:

kernel<<<Grid,Block>>>();

在内核中,线程的二维索引计算如下:

int xIndex = blockIdx.x * blockDim.x + threadIdx.x;
int yIndex = blockIdx.y * blockDim.y + threadIdx.y;

或者,如果您遵循行/列约定而不是x / y,则:

int row    = blockIdx.y * blockDim.y + threadIdx.y;
int column = blockIdx.x * blockDim.x + threadIdx.x;

答案 1 :(得分:1)

您还可以拥有1维线程块的2D网格,以便绕过每网格尺寸65535个块的限制(对于pre-cc3.0设备)。这可能是一种更简单的方法,可以在不引入数据的二维数组表示的情况下,将基本的一维问题扩展到限制之外。

假设我们将DATA_ELEMENTS参数定义为内核将处理的元素数(每个线程一个元素)。如果DATA_ELEMENTS大于65535 * 1024,那么如果每个线程只处理1个元素,则无法使用1-D网格处理它们。

您可以保持THREADS_PER_BLOCK参数相同。内核中的线程索引计算将更改为:

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

您需要确保使用以下内容来调整内核计算:

if (idx < DATA_ELEMENTS){
   (kernel code)
  }

您的网格尺寸如下:

dim3 grid;
if (DATA_ELEMENTS > (65535*THREADS_PER_BLOCK)){ // create a 2-D grid
  int gridx = 65535;  // could choose another number here
  int gridy = ((DATA_ELEMENTS+(THREADS_PER_BLOCK-1))/THREADS_PER_BLOCK)/gridx;
  if ((((DATA_ELEMENTS+(THREADS_PER_BLOCK-1))/THREADS_PER_BLOCK)%gridx) != 0) gridy++;
  grid.x=gridx;
  grid.y=gridy;
  grid.z=1;
  }
else{ // create a 1-D grid
  int gridx = (DATA_ELEMENTS+(THREADS_PER_BLOCK-1))/THREADS_PER_BLOCK;
  grid.x=gridx;
  grid.y=1;
  grid.z=1;
  }

你可以将你的内核启动为:

 kernel<<<grid, THREADS_PER_BLOCK>>>(...);

解决此类问题的另一种方法是创建某个维度的一维网格(假设网格中的线程总数为NUM_THREADS_PER_GRID),并让每个线程都在多个线程上工作数据元素数组中的元素,使用类似for循环或while循环的东西:

while (idx < DATA_ELEMENTS) {
    (code to process an element)
    idx += NUM_THREADS_PER_GRID
    }

答案 2 :(得分:0)

我喜欢Robert的上述解决方案。我对他的第一个解决方案的唯一评论是,gridx似乎应该使DATA_ELEMENTS > (65535*THREADS_PER_BLOCK)尽可能小。65535*THREADS_PER_BLOCK + 1。原因是,如果数据元素的数量为gridx,而6553565535*2*THREADS_PER_BLOCK,则会启动gridx,因此几乎一半的线程将无效。如果{{1}}较小,则会有较少的线程无效。