CUDA 2D阵列nvidia

时间:2013-04-04 08:23:49

标签: cuda nvidia cuda-gdb

我正在使用cudaMallocPitchcudaMemcpy2D来表示2D数组。即使我无法正确输出,我也不确定我的编码是否正确。有人可以帮忙吗?任何人都可以调试我的错误吗?提前致谢。

#include<stdio.h>
#include<cuda.h>
#define siz 4*sizeof(int)
__global__ void addmatrix(int *m1,int *m2,size_t pitch)
{
    int r=threadIdx.x;
    int *r1=m1+r*pitch;
    int *r2=m2+r*pitch;
    int c;
    for(c=1;c<=4;c++)
    {
        r1[c]+=r2[c];
    }
}
int main()
{
    int i,j;
    int **m1_c,**m2_c;
    int *m1_d,*m2_d;
    size_t pitch;
    cudaError_t err;
    m1_c=(int **)malloc(4*sizeof(int *));
    for(i=1;i<=4;i++)
    {
        m1_c[i]=(int *)malloc(siz);
    }
    m2_c=(int **)malloc(4*sizeof(int *));
    for(i=1;i<=4;i++)
    {
        m2_c[i]=(int *)malloc(siz);
    }
    for(i=1;i<=4;i++)
    {
        for(j=1;j<=4;j++)
        {
            m1_c[i][j]=rand()%10;
            m2_c[i][j]=rand()%10;
        }
    }
    for(i=1;i<=4;i++)
    {
        for(j=1;j<=4;j++)
        {
            printf("%d\t",m1_c[i][j]);
        }
        printf("\n");
    }
    printf("\n\n");
    for(i=1;i<=4;i++)
    {
        for(j=1;j<=4;j++)
        {
            printf("%d\t",m2_c[i][j]);
        }
        printf("\n");
    }
    err=cudaMallocPitch((void **)&m1_d,&pitch,siz,siz);
    err=cudaMallocPitch((void **)&m2_d,&pitch,siz,siz);
    err=cudaMemcpy2D(m1_d,pitch,m1_c,siz,siz,4,cudaMemcpyHostToDevice);
    err=cudaMemcpy2D(m2_d,pitch,m2_c,siz,siz,4,cudaMemcpyHostToDevice);
    dim3 grid(1);
    dim3 block(16);
    addmatrix<<<grid,block>>>(m1_d,m2_d,siz);
    cudaMemcpy2D(m1_c,siz,m1_d,pitch,siz,4,cudaMemcpyDeviceToHost);

    for(i=1;i<=4;i++)
    {
        for(j=1;j<=4;j++)
        {
            printf("%d\t",m1_c[i][j]);
        }
        printf("\n");
    }
    err=cudaFree(m1_d);
    err=cudaFree(m2_d);
    err=cudaDeviceReset();      
}

1 个答案:

答案 0 :(得分:1)

因此这段代码存在一些问题。没有特别的顺序:

  1. 您正在通过各种数组从1到4进行索引,但这在C中是不正确的.C索引从零开始,并且比维度小一个。这与CUDA无关。
  2. cudaMemcpy2D需要两个指针(srcdst),这两个指针都指向内存中的线性数组。我意识到这是令人困惑的,因为2D出现在整个描述中,但是两个指针参数基本上都是相同的类型(指向内存的指针),并且你传递2种不同类型的指针(一个是指向内存的指针,另一个是是指向内存指针的指针。从cudaMemcpy2D的定义来看,你的用法是不正确的。关于如何使用cudaMemcpy2D的示例有很多已回答的问题,我建议您搜索并查看其中的一些。请注意,修复此问题可能会导致您从根本上重新考虑如何将数据存储在主机矩阵中。关于处理多维矩阵有很多问题,例如this one - 如果可能的话,你应该将它们弄平。请注意,在当前代码中,使用cudaMemcpy2D时出现此错误会破坏主机矩阵上的指针数组,这会在您尝试打印结果时导致seg错误。
  3. 传递给cudaMallocPitch的参数不太对劲。对于widthheight参数,您传递的是siz,即矩阵维,以字节为单位。但是您应该只传递width参数的字节维度。对于height参数,您应该传递行数,即在您的情况下为4。对cudaMemcpy2D的调用也有类似的要求,但是你就在那里。
  4. 现在让我们来看看你的内核。在调用中,您将启动一个包含16个线程的块的网格。由于你的矩阵有16个元素,这似乎是明智的。这意味着线程策略,其中每个线程将负责结果的单个元素。但是看一下你的内核代码,你就会让每个线程计算整行的结果,即4个元素。有两种方法可以解决这个问题:您可以将网格减少到4个线程而不是16个线程(可能从代码修改的角度来看更简单),或者您可以重新编写内核(消除for循环)并拥有每个线程计算单个输出元素(可能会并行执行更多工作)。
  5. 此外,在您的内核中,您在基于指针算法的索引中使用pitch参数。但请记住,音调位于 bytes 中,对于指针算术索引,编译器希望参数位于元素中 - 它会根据您的转换为字节。数据类型。同样,这实际上是一个C问题,并不是特定于CUDA。您可以使用(pitch/sizeof(int))在内核中使用pitch的任何地方解决此问题。
  6. 您正在将siz传递给您的内核。你应该传递pitch作为音高参数。 siz实际上是主机数据存储上的“间距”,但pitch是设备上存储的间距。内核正在设备存储上运行,因此需要正确的间距。
  7. 作为建议,请对所有cuda API调用和内核调用执行cuda error checking
  8. 以下是一些以某种方式解决上述所有问题的代码:

    #include<stdio.h>
    #define siz (4*sizeof(int))
    
    #define cudaCheckErrors(msg) \
        do { \
            cudaError_t __err = cudaGetLastError(); \
            if (__err != cudaSuccess) { \
                fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                    msg, cudaGetErrorString(__err), \
                    __FILE__, __LINE__); \
                fprintf(stderr, "*** FAILED - ABORTING\n"); \
                exit(1); \
            } \
        } while (0)
    
    __global__ void addmatrix(int *m1,int *m2,size_t pitch)
    {
        int r=threadIdx.x;
        int *r1=m1+r*(pitch/sizeof(int));
        int *r2=m2+r*(pitch/sizeof(int));
        int c;
        for(c=0;c<4;c++)
        {
            r1[c]+=r2[c];
        }
    }
    int main()
    {
        int i,j;
        int *m1_c,*m2_c;
        int *m1_d,*m2_d;
        size_t pitch;
        cudaError_t err;
        m1_c=(int *)malloc(16*sizeof(int));
        m2_c=(int *)malloc(16*sizeof(int));
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
            {
                m1_c[(i*4)+j]=rand()%10;
                m2_c[(i*4)+j]=rand()%10;
            }
        }
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
            {
                printf("%d\t",m1_c[(i*4)+j]);
            }
            printf("\n");
        }
        printf("\n\n");
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
            {
                printf("%d\t",m2_c[(i*4)+j]);
            }
            printf("\n");
        }
        err=cudaMallocPitch((void **)&m1_d,&pitch,siz,4);
        cudaCheckErrors("cm1");
        err=cudaMallocPitch((void **)&m2_d,&pitch,siz,4);
        cudaCheckErrors("cm2");
        err=cudaMemcpy2D(m1_d,pitch,m1_c,siz,siz,4,cudaMemcpyHostToDevice);
        cudaCheckErrors("cm3");
        err=cudaMemcpy2D(m2_d,pitch,m2_c,siz,siz,4,cudaMemcpyHostToDevice);
        cudaCheckErrors("cm4");
        dim3 grid(1);
        dim3 block(4);
        addmatrix<<<grid,block>>>(m1_d,m2_d,pitch);
        cudaMemcpy2D(m1_c,siz,m1_d,pitch,siz,4,cudaMemcpyDeviceToHost);
        cudaCheckErrors("cm5");
    
        for(i=0;i<4;i++)
        {
            for(j=0;j<4;j++)
            {
                printf("%d\t",m1_c[(i*4)+j]);
            }
            printf("\n");
        }
        err=cudaFree(m1_d);
        err=cudaFree(m2_d);
        err=cudaDeviceReset();
    }