为什么这个简单的 CUDA 内核会得到错误的结果?

Why is this simple CUDA kernel getting a wrong result?

我是 CUDA 的新手。我正在学习一些基本的东西,因为我想在其他项目中使用 CUDA。我写这段代码是为了添加一个 8x8 平方矩阵中的所有元素,该矩阵已填充 1,因此结果必须为 64。

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

const int SIZE = 64;


__global__ void add_matrix_values(int* matrix, int sum, int c)
{

    int i = threadIdx.x + blockIdx.x * blockDim.x;
    int j = threadIdx.y + blockIdx.x * blockDim.x;

    sum += matrix[i*c+j];

}



int main()
{
    
    int* device_matrix;
    int* host_matrix;
    int c = 8;      //Squared matrix cxc
    int device_c = 8;
    int device_sum =  0;
    int host_sum  = 0;

    //Allocate host memory
    host_matrix = (int*)malloc(sizeof(int)*SIZE);
    //Fill the matrix values with 1's
    for(auto i = 0; i < SIZE; i++)
        host_matrix[i] = 1;
    
    //Allocate device memory
    cudaMalloc((void**) &device_matrix,sizeof(int)*SIZE);
    cudaMalloc((void**) &device_sum, sizeof(int));
    cudaMalloc((void**) &device_c,sizeof(int));

    //Fill device_matrix with host_matrix values
    cudaMemcpy(&device_matrix,&host_matrix,sizeof(int)*SIZE,cudaMemcpyHostToDevice);
    //Initialize device_sum with a 0 
    cudaMemcpy(&device_sum,&host_sum,sizeof(int),cudaMemcpyHostToDevice);
    //Initialize device_c with the correct value
    cudaMemcpy(&device_c,&c,sizeof(int),cudaMemcpyHostToDevice);


    //4 blocks with 16 threads every single block ¿Is this correct?
    add_matrix_values<<<4,16>>>(device_matrix, device_sum,device_c);

    cudaMemcpy(&host_sum,&device_sum,sizeof(int),cudaMemcpyDeviceToHost);

    std::cout<<"The value is: "<<host_sum<<std::endl;


    cudaFree(device_matrix);
    free(host_matrix);

    return 0;




}


结果必须是 64,但我得到的数字有误。

 migue@migue  ~/Escritorio  ./program
The value is: 32762
 migue@migue  ~/Escritorio  ./program
The value is: 32608
 migue@migue  ~/Escritorio  ./program
The value is: 32559

我不知道我做错了什么。可能是 gridSize 和 blockSize ?或者它可能是 cuda 内核中的 i 和 j 操作?

我不是很明白这些条款。

存在一些问题:

  • 您正在创建一维网格(网格配置、块配置),因此内核代码中的二维索引(i、j 或 x、y)没有任何意义
  • 您正在按值传递 sum。您无法以这种方式检索结果。内核中对 sum 的更改不会反映在调用环境中。这是一个 C++ 概念,并非特定于 CUDA。请改用正确分配的指针。
  • 在 CUDA 多线程环境中,您不能让多个线程在没有任何控制的情况下更新同一个 location/value。 CUDA 不会为您整理出那种访问权限。您必须使用并行缩减技术,这里的一种简单方法可能是使用原子。您可以在讨论并行缩减的 cuda 标签上找到许多问题。
  • 您通常会混淆按值传递和按指针传递。按值传递的项目可以是普通的宿主变量。您通常不需要为这些分配 cudaMalloc。您也不要在指针以外的任何类型的变量上使用 cudaMalloc
  • 您对 cudaMemcpy 的使用不正确。不需要取指针的地址。

以下代码解决了上述问题:

$ cat t135.cu
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

const int SIZE = 64;


__global__ void add_matrix_values(int* matrix, int *sum, int c)
{

    int i = threadIdx.x + blockIdx.x * blockDim.x;
    atomicAdd(sum, matrix[i]);

}



int main()
{

    int* device_matrix;
    int* host_matrix;
    int device_c = 8;
    int *device_sum;
    int host_sum  = 0;

    //Allocate host memory
    host_matrix = (int*)malloc(sizeof(int)*SIZE);
    //Fill the matrix values with 1's
    for(auto i = 0; i < SIZE; i++)
        host_matrix[i] = 1;

    //Allocate device memory
    cudaMalloc((void**) &device_matrix,sizeof(int)*SIZE);
    cudaMalloc((void**) &device_sum, sizeof(int));

    //Fill device_matrix with host_matrix values
    cudaMemcpy(device_matrix,host_matrix,sizeof(int)*SIZE,cudaMemcpyHostToDevice);
    //Initialize device_sum with a 0
    cudaMemcpy(device_sum,&host_sum,sizeof(int),cudaMemcpyHostToDevice);


    //4 blocks with 16 threads every single block ¿Is this correct?
    add_matrix_values<<<4,16>>>(device_matrix, device_sum,device_c);

    cudaMemcpy(&host_sum,device_sum,sizeof(int),cudaMemcpyDeviceToHost);

    std::cout<<"The value is: "<<host_sum<<std::endl;


    cudaFree(device_matrix);
    free(host_matrix);

    return 0;

}
$ nvcc -o t135 t135.cu
$ cuda-memcheck ./t135
========= CUDA-MEMCHECK
The value is: 64
========= ERROR SUMMARY: 0 errors
$