2D多维数组传递给内核,CUDA

时间:2016-01-04 12:27:19

标签: c++ cuda

我一直在努力寻找一种允许我将预定义的2D数组传递给内核的实现。

int values[2][3];

我需要将所有数据保存在正确的列和行中。现在我知道CUDA接受线性形式的2D数组,但是如何传递已经构建的数组?

1 个答案:

答案 0 :(得分:1)

正如@ jarod42指出的那样,对于你所展示的“自动”,“非可变长度”的C风格数组:

int values[2][3];

此类阵列的存储格式与以下内容相同:

int values[2*3];

这意味着我们可以将该数组视为线性单一下标数组(即使它不是):

  1. 用于从主机到设备的转移:

    #define W 3
    #define H 2
    int values[H][W];
    int *d_values;
    cudaMalloc(&d_values, H*W*sizeof(int));
    cudaMemcpy(d_values, values, H*W*sizeof(int), cudaMemcpyHostToDevice);
    
  2. 并且为了在设备代码中访问,使用“模拟”2D访问:

    __global__ void kernel(int *values, int width, ...){
      int col = threadIdx.x+blockDim.x*blockIdx.x;
      int row = threadIdx.y+blockDim.y*blockIdx.y;
      int my_value = values[row*width+col];
      ...
    }  
    
    int main(){
      ...
      kernel<<<...>>>(d_values, W, ...);
      ...
      }
    
  3. 但根据你问题中的措辞:

      

    现在我知道CUDA接受线性形式的2D数组,但是如何传递已经构建的数组呢?

    看起来您可能已经意识到上述方法,我通常将其称为“展平”2D阵列以线性方式对待它(可能使用“模拟”2D访问)。

    通常,处理编译时未知的宽度的2D数组,同时仍然允许在设备代码中进行双向下标访问,rather involved,我不推荐它,特别是对于CUDA初学者。但事实并非如此:

      

    内核的预定义2D数组。

    int values[2][3];
                  ^
                 the "width"
    

    我认为这意味着在编译时已知数组的“宽度”(即第二个的范围,即最后一个下标)。在这种情况下,我们可以利用编译器为我们生成必要的数组索引,使传输和使用过程比“扁平”情况稍微复杂一些,同时仍允许在内核中进行双向下标访问:

    $ cat t1023.cu
    #include <stdio.h>
    
    #define W 3
    #define H 2
    #define BSIZE 8
    
    typedef int arrtype[W];
    
    __global__ void kernel(arrtype *values, int width, int height){
    
      int col=threadIdx.x+blockDim.x*blockIdx.x;
      int row=threadIdx.y+blockDim.y*blockIdx.y;
    
      if ((row < height)&&(col < width)){
    
        int my_val = values[row][col]; //doubly-subscripted access
        printf("row: %d, col: %d, value: %d\n", row, col, my_val);
        }
    }
    
    int main(){
    
      int values[H][W];
      for (int i = 0; i < H; i++)
        for (int j = 0; j < W; j++)
          values[i][j] = i+j;
      arrtype *d_values;
      cudaMalloc(&d_values, H*W*sizeof(int));
      cudaMemcpy(d_values, values, H*W*sizeof(int), cudaMemcpyHostToDevice);
      dim3 block(BSIZE,BSIZE);
      dim3 grid((W+block.x-1)/block.x, (H+block.y-1)/block.y);
      kernel<<<grid,block>>>(d_values, W, H);
      cudaDeviceSynchronize();
      return 0;
    }
    $ nvcc -o t1023 t1023.cu
    $ ./t1023
    row: 0, col: 0, value: 0
    row: 0, col: 1, value: 1
    row: 0, col: 2, value: 2
    row: 1, col: 0, value: 1
    row: 1, col: 1, value: 2
    row: 1, col: 2, value: 3
    $
    

    对于完全工作的3D(即三重下标)示例,请参阅here