如何使用嵌套for循环添加两个2d(音调)数组?

use*_*164 9 loops cuda multidimensional-array

我是cuda的新手.我想将两个2d数组加到第三个数组中.我使用以下代码:

cudaMallocPitch((void**)&device_a, &pitch, 2*sizeof(int),2);
cudaMallocPitch((void**)&device_b, &pitch, 2*sizeof(int),2);
cudaMallocPitch((void**)&device_c, &pitch, 2*sizeof(int),2);
Run Code Online (Sandbox Code Playgroud)

现在我的问题是我不想在我的内核代码中使用这些数组作为扁平的二维数组我希望di使用两个for循环并将结果放在第三个数组中

__global__ void add(int *dev_a ,int *dev_b,int* dec_c)
{
    for i=0;i<2;i++)
    { 
      for j=0;j<2;j++)
      {
        dev_c[i][j]=dev_a[i][j]+dev_b[i][j];
      }
    }
}
Run Code Online (Sandbox Code Playgroud)

我怎么能在CUDA做到这一点?请告诉我如何以这种方式使用二维阵列?

使用2d-array的内核调用应该是什么?如果可能,请使用代码示例进行说明.

tal*_*ies 18

简短的回答是,你做不到.该cudaMallocPitch()函数正如其名称所暗示的那样,它分配了音调线性内存,其中音调被选择为GPU内存控制器和纹理硬件的最佳选择.

如果你想在内核中使用指针数组,那么内核代码必须如下所示:

__global___ void add(int *dev_a[] ,int *dev_b[], int* dec_c[])
{
    for i=0;i<2;i++) { 
      for j=0;j<2;j++) {
        dev_c[i][j]=dev_a[i][j]+dev_b[i][j];
      }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你需要cudaMalloc在主机端进行嵌套调用来构造指针数组并将其复制到设备内存中.对于相当简单的2x2示例,分配单个数组的代码如下所示:

int ** h_a = (int **)malloc(2 * sizeof(int *));
cudaMalloc((void**)&h_a[0], 2*sizeof(int));
cudaMalloc((void**)&h_a[1], 2*sizeof(int));

int **d_a;
cudaMalloc((void ***)&d_a, 2 * sizeof(int *));
cudaMemcpy(d_a, h_a, 2*sizeof(int *), cudaMemcpyHostToDevice);
Run Code Online (Sandbox Code Playgroud)

这将在d_a中保留指定的指针设备数组,并将其传递给内核.

出于代码复杂性和性能原因,您实际上不希望这样做,使用CUDA代码中的指针数组比使用线性内存的替代方案更难更慢.


要在CUDA中显示使用指针数组的愚蠢行为,下面是一个完整的示例问题示例,它结合了上述两个想法:

#include <cstdio>
__global__ void add(int * dev_a[], int * dev_b[], int * dev_c[])
{
    for(int i=0;i<2;i++)
    { 
        for(int j=0;j<2;j++)
        {
            dev_c[i][j]=dev_a[i][j]+dev_b[i][j];
        }
    }
}

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__); }

int main(void)
{
    const int aa[2][2]={{1,2},{3,4}};
    const int bb[2][2]={{5,6},{7,8}};
    int cc[2][2];

    int ** h_a = (int **)malloc(2 * sizeof(int *));
    for(int i=0; i<2;i++){
        GPUerrchk(cudaMalloc((void**)&h_a[i], 2*sizeof(int)));
        GPUerrchk(cudaMemcpy(h_a[i], &aa[i][0], 2*sizeof(int), cudaMemcpyHostToDevice));
    }

    int **d_a;
    GPUerrchk(cudaMalloc((void ***)&d_a, 2 * sizeof(int *)));
    GPUerrchk(cudaMemcpy(d_a, h_a, 2*sizeof(int *), cudaMemcpyHostToDevice));

    int ** h_b = (int **)malloc(2 * sizeof(int *));
    for(int i=0; i<2;i++){
        GPUerrchk(cudaMalloc((void**)&h_b[i], 2*sizeof(int)));
        GPUerrchk(cudaMemcpy(h_b[i], &bb[i][0], 2*sizeof(int), cudaMemcpyHostToDevice));
    }

    int ** d_b;
    GPUerrchk(cudaMalloc((void ***)&d_b, 2 * sizeof(int *)));
    GPUerrchk(cudaMemcpy(d_b, h_b, 2*sizeof(int *), cudaMemcpyHostToDevice));

    int ** h_c = (int **)malloc(2 * sizeof(int *));
    for(int i=0; i<2;i++){
        GPUerrchk(cudaMalloc((void**)&h_c[i], 2*sizeof(int)));
    }

    int ** d_c;
    GPUerrchk(cudaMalloc((void ***)&d_c, 2 * sizeof(int *)));
    GPUerrchk(cudaMemcpy(d_c, h_c, 2*sizeof(int *), cudaMemcpyHostToDevice));

    add<<<1,1>>>(d_a,d_b,d_c);
    GPUerrchk(cudaPeekAtLastError());

    for(int i=0; i<2;i++){
        GPUerrchk(cudaMemcpy(&cc[i][0], h_c[i], 2*sizeof(int), cudaMemcpyDeviceToHost));
    }

    for(int i=0;i<2;i++) {
        for(int j=0;j<2;j++) {
            printf("(%d,%d):%d\n",i,j,cc[i][j]);
        }
    }

    return cudaThreadExit();
}
Run Code Online (Sandbox Code Playgroud)

我建议你研究它,直到你理解它的作用,以及与使用线性记忆相比,它为什么这么糟糕.