cuda中的动态3D数组参数

时间:2014-08-01 04:55:05

标签: arrays cuda

我正在尝试在cuda的内核函数中使用动态3D数组参数,但我做得不好。

__global__ void kernel ( 3D array pointer )
{
// do something
}

int main()
{
    const int NUM_OF_ARRAY;
    const int ROW;
    const int CAL;

    int arr[NUM_OF_ARRAY][ROW][CAL]; 
    // Maybe I should use cudaMalloc3D or cudaMalloc3DArray

    dim3 grid( , , ,);
    dim3 block( , , , );

    kernel <<< grid, block >>> ( ? );
 }

我看到罗伯特对sending 3d array to CUDA kernel的回答,但我认为我的情况略有不同。

如果在运行时确定了数组的行和cal,我如何在cuda中分配该内存并将该指针指向内核函数?

我尝试使用cudaMalloc3D或cudaMalloc3DArray,但我不能好,因为我以前从未使用过。

任何人都可以使用动态3D数组参数显示简单示例吗?

对我有帮助。感谢。

1 个答案:

答案 0 :(得分:2)

由于上一个链接答案和其他地方建议的所有原因,这不一定是处理3D阵列的好方法。更好的方法是展平数组并使用指针算法来模拟3D访问。

但只是为了证明上一个示例并不需要是硬编码维度,这里修改了示例以显示变量(运行时)维度用法:

#include <iostream>

inline void GPUassert(cudaError_t code, char * file, int line, bool Abort=true)
{
    if (code != 0) {
        fprintf(stderr, "GPUassert: %s %s %d\n", cudaGetErrorString(code),file,line);
        if (Abort) exit(code);
    }
}

#define GPUerrchk(ans) { GPUassert((ans), __FILE__, __LINE__); }



  __global__ void doSmth(int*** a, int sz_x, int sz_y, int sz_z) {
    for(int i=0; i<sz_z; i++)
     for(int j=0; j<sz_y; j++)
      for(int k=0; k<sz_x; k++)
       a[i][j][k]=i-j+k;
 }
 int main() {

  unsigned sx;
  unsigned sy;
  unsigned sz;
  std::cout << std::endl << "Enter x dimension (3rd subscript): " ;
  std::cin >> sx;
  std::cout << std::endl << "Enter y dimension (2nd subscript): " ;
  std::cin >> sy;
  std::cout << std::endl << "Enter z dimension (1st subscript): " ;
  std::cin >> sz;

  int*** h_c = (int***) malloc(sz*sizeof(int**));
  for(int i=0; i<sz; i++) {
   h_c[i] = (int**) malloc(sy*sizeof(int*));
   for(int j=0; j<sy; j++)
    GPUerrchk(cudaMalloc((void**)&h_c[i][j],sx*sizeof(int)));
  }
  int ***h_c1 = (int ***) malloc(sz*sizeof(int **));
  for (int i=0; i<sz; i++){
    GPUerrchk(cudaMalloc((void***)&(h_c1[i]), sy*sizeof(int*)));
    GPUerrchk(cudaMemcpy(h_c1[i], h_c[i], sy*sizeof(int*), cudaMemcpyHostToDevice));
    }
  int*** d_c;
  GPUerrchk(cudaMalloc((void****)&d_c,sz*sizeof(int**)));
  GPUerrchk(cudaMemcpy(d_c,h_c1,sz*sizeof(int**),cudaMemcpyHostToDevice));
  doSmth<<<1,1>>>(d_c, sx, sy, sz);
  GPUerrchk(cudaPeekAtLastError());
  int res[sz][sy][sx];
  for(int i=0; i<sz; i++)
   for(int j=0; j<sy; j++)
    GPUerrchk(cudaMemcpy(&res[i][j][0], h_c[i][j],sx*sizeof(int),cudaMemcpyDeviceToHost));
  std::cout << std::endl;
  for(int i=0; i<sz; i++)
   for(int j=0; j<sy; j++)
    for(int k=0; k<sx; k++)
     printf("[%d][%d][%d]=%d\n",i,j,k,res[i][j][k]);
 }

我已将内核存储的数据修改为i-j+k而不是i+j+k。此外,我已经为下标创建了[z][y][x]顺序,因为这将建议使用线程索引计算安排,例如[threadIdx.z][threadIdx.y][threadIdx.x],这将最有利于合并访问。但是,由于指针追逐以解析数据的最终位置,内核中的这种类型的多下标数组仍然往往效率低下。