使用二维线程在CUDA中添加两个矩阵

时间:2016-01-19 17:38:31

标签: c++ matrix cuda

我是CUDA的新手。我试图添加两个向量,它工作正常。现在我想添加两个矩阵。我想使用二维线程(threadIdx.x和threadIdx.y)添加两个矩阵。我在Internet上找到了这段代码,并且我做了一些更改来显示结果。它汇编。但显示意外的结果,它看起来像内存地址。请帮帮我,谢谢你。

#include <stdio.h>
#include <stdlib.h>

#define N 5
#define BLOCK_DIM 10

__global__ void matrixAdd (int *a, int *b, int *c) {
    int col = blockIdx.x * blockDim.x + threadIdx.x;
    int row = blockIdx.y * blockDim.y + threadIdx.y;

    int index = col + row * N;

    if (col < N && row < N) {
        c[index] = a[index] + b[index];
    }

}

int main() {
    int a[N][N], b[N][N], c[N][N];
    int *dev_a, *dev_b, *dev_c;

    int size = N * N;

    for(int i=0; i<N; i++)
        for (int j=0; j<N; j++){
            a[i][j] = 1;
            b[i][j] = 2;
        }

    cudaMalloc((void**)&dev_a, size);
    cudaMalloc((void**)&dev_b, size);
    cudaMalloc((void**)&dev_c, size);

    cudaMemcpy(dev_a, a, size, cudaMemcpyHostToDevice);
    cudaMemcpy(dev_b, b, size, cudaMemcpyHostToDevice);

    dim3 dimBlock(BLOCK_DIM, BLOCK_DIM);
    dim3 dimGrid((int)ceil(N/dimBlock.x),(int)ceil(N/dimBlock.y));

    matrixAdd<<<dimGrid,dimBlock>>>(dev_a,dev_b,dev_c);
    cudaDeviceSynchronize();

    for(int i=0; i<N; i++){
        for (int j=0; j<N; j++){
            printf("%d\t", c[i][j] );
        }
        printf("\n");
    }

    cudaMemcpy(c, dev_c, size, cudaMemcpyDeviceToHost);

    cudaFree(dev_a); 
    cudaFree(dev_b); 
    cudaFree(dev_c);
}

,输出

0   0   -780197879  32659   1   
0   452489360   32764   6303208 0   
4198328 0   452489376   32764   4198181 
0   2   0   4198557 0   
4196864 0   0   0   4198480 

我的预期输出是元素3的5x5矩阵。请帮助我。

1 个答案:

答案 0 :(得分:2)

如果您遇到CUDA代码问题,应始终使用proper cuda error checking并使用cuda-memcheck运行代码。我建议您在此处寻求帮助之前 。即使您不理解错误输出,它也会对那些试图帮助您的人有所帮助。

  1. 如果您已完成正确的CUDA错误检查,则会在内核启动时收到“无效参数”错误的通知。它是由于这个计算而产生的:

    dim3 dimGrid((int)ceil(N/dimBlock.x),(int)ceil(N/dimBlock.y));
    

    如果在计算后打印出实际计算值:

    printf("dimGrid.x = %d, dimGrid.y = %d\n", dimGrid.x, dimGrid.y);
    

    你会发现它们都是零。这是非法的。

    这个结构:

    N/dimBlock.x
    

    正在使用整数除法。如果值N = 5且dimBlock.x = 10,则这两个数的整数除以零。 ceil的使用不会影响您的写作方式。

    有很多方法可以修复它。一种可能的方法是像这样进行算术:

    dim3 dimGrid((N+dimBlock.x-1)/dimBlock.x, (N+dimBlock.y-1)/dimBlock.y);
    
  2. 下一个错误在于计算size变量:

    int size = N * N;
    

    cudaMalloccudaMemcpy,如mallocmemcpy,预计字节的大小。所以你应该这样做:

    int size = N * N * sizeof(int);
    
  3. 最后,您希望将数据复制回主机,然后再将其打印出来。所以这不正确:

    for(int i=0; i<N; i++){
        for (int j=0; j<N; j++){
            printf("%d\t", c[i][j] );
        }
        printf("\n");
    }
    
    cudaMemcpy(c, dev_c, size, cudaMemcpyDeviceToHost);
    

    你想这样做:

    cudaMemcpy(c, dev_c, size, cudaMemcpyDeviceToHost);
    for(int i=0; i<N; i++){
        for (int j=0; j<N; j++){
            printf("%d\t", c[i][j] );
        }
        printf("\n");
    }
    
  4. 这是一个工作示例,显示了对代码的上述修改:

    $ cat t1058.cu
    #include <stdio.h>
    #include <stdlib.h>
    
    #define N 5
    #define BLOCK_DIM 10
    
    __global__ void matrixAdd (int *a, int *b, int *c) {
        int col = blockIdx.x * blockDim.x + threadIdx.x;
        int row = blockIdx.y * blockDim.y + threadIdx.y;
    
        int index = col + row * N;
    
        if (col < N && row < N) {
            c[index] = a[index] + b[index];
        }
    
    }
    
    int main() {
        int a[N][N], b[N][N], c[N][N];
        int *dev_a, *dev_b, *dev_c;
    
        int size = N * N * sizeof(int);
    
        for(int i=0; i<N; i++)
            for (int j=0; j<N; j++){
                a[i][j] = 1;
                b[i][j] = 2;
            }
    
        cudaMalloc((void**)&dev_a, size);
        cudaMalloc((void**)&dev_b, size);
        cudaMalloc((void**)&dev_c, size);
    
        cudaMemcpy(dev_a, a, size, cudaMemcpyHostToDevice);
        cudaMemcpy(dev_b, b, size, cudaMemcpyHostToDevice);
    
        dim3 dimBlock(BLOCK_DIM, BLOCK_DIM);
        //dim3 dimGrid((int)ceil(N/dimBlock.x),(int)ceil(N/dimBlock.y));
        dim3 dimGrid((N+dimBlock.x-1)/dimBlock.x, (N+dimBlock.y-1)/dimBlock.y);
        printf("dimGrid.x = %d, dimGrid.y = %d\n", dimGrid.x, dimGrid.y);
        matrixAdd<<<dimGrid,dimBlock>>>(dev_a,dev_b,dev_c);
        cudaDeviceSynchronize();
        cudaMemcpy(c, dev_c, size, cudaMemcpyDeviceToHost);
    
        for(int i=0; i<N; i++){
            for (int j=0; j<N; j++){
                printf("%d\t", c[i][j] );
            }
            printf("\n");
        }
    
    
        cudaFree(dev_a);
        cudaFree(dev_b);
        cudaFree(dev_c);
    }
    $ nvcc -o t1058 t1058.cu
    $ cuda-memcheck ./t1058
    ========= CUDA-MEMCHECK
    dimGrid.x = 1, dimGrid.y = 1
    3 3 3 3 3
    3 3 3 3 3
    3 3 3 3 3
    3 3 3 3 3
    3 3 3 3 3
    ========= ERROR SUMMARY: 0 errors
    $