CUDA核心功能似乎显示竞争条件,尽管竞赛检查显示0竞争条件

时间:2015-11-28 20:08:21

标签: c++ cuda parallel-processing gpu

我的CUDA内核函数没有返回预期的结果(向量b中所有元素的总和),而是从向量b返回单个值。我尝试了memcheck和racecheck,但没有出现:

[breecej@compute-0-32 newsum]$ cuda-memcheck mystock
========= CUDA-MEMCHECK
========= ERROR SUMMARY: 0 errors
[breecej@compute-0-32 newsum]$ cuda-memcheck --tool racecheck mystock
========= CUDA-MEMCHECK
========= RACECHECK SUMMARY: 0 hazards displayed (0 errors, 0 warnings) 
[breecej@compute-0-32 newsum]$ 

这是内核函数:

__global__ void AddDoubles(double *a, double *b, int count)
{
    int id = blockIdx.x * blockDim.x + threadIdx.x;
    if(id < count)
    {
        a[0] += b[id];
        __syncthreads();
    }
}

以下是进入它的变量以及我在main中调用它的方式:

int count = vect.size();
//allocate memory for the sum and stock values for the host side
double *h_a = new double[1];
double *h_b = new double[count];
//array a set to 0, array b set to the values from the line
h_a[0] = 0;
for(int i = 0; i < count; i++)
{
    h_b[i] = vect.at(i);
}
//allocate memory for the sum and stock values arrays for the device side
double *d_a, *d_b;
if(cudaMalloc(&d_a, sizeof(double)) != cudaSuccess)
{
    cout << "Nope! a did not allocate correctly";
    return 0;
}
if(cudaMalloc(&d_b, sizeof(double) * count) != cudaSuccess)
{
    cout << "Nope! b did not allocate correctly";
    cudaFree(d_a);
    return 0;
}
//copy the host pointer to the device pointer
if(cudaMemcpy(d_a, h_a, sizeof(double), cudaMemcpyHostToDevice) != cudaSuccess)
{
    cout << "Could not copy!" << endl;
    cudaFree(d_a);
    cudaFree(d_b);
    return 0;
}
if(cudaMemcpy(d_b, h_b, sizeof(double) * count, cudaMemcpyHostToDevice) != cudaSuccess)
{
    cout << "Could not copy!" << endl;
    cudaFree(d_a);
    cudaFree(d_b);
    return 0;
}
//use AddDoubles to sum up all of the values in b and put them into a
AddDoubles<<<count / 256 + 1, 256>>>(d_a, d_b, count);

其中“vect”是双打矢量。

为什么看起来有一场比赛要改变核心功能中的值,但是在比赛检查中什么都没有出现?

1 个答案:

答案 0 :(得分:3)

您的代码有全局内存竞争,但cuda-memcheck无法检测到它。引自documentation

  

racecheck 工具是运行时共享内存数据访问的危险   探测器。此工具的主要用途是帮助识别内存   访问使用共享内存的CUDA应用程序中的竞争条件。

即。 cuda-memcheck只能检测共享内存竞争。您的代码不使用共享内存。

如果您的内核是这样编写的,那么竞争本身就会变得明显:

__global__ void AddDoubles(double *a, double *b, int count)
{
    int id = blockIdx.x * blockDim.x + threadIdx.x;
    if(id < count)
    {
        double x = a[0];  // 1. load a[0] to thread local register
        double y = b[id]; // 2. load b[id] to thread local register
        double z = x + y; // 3. perform addition in thread local register
        a[0] = z;         // 4. store thread local register sum to a[0] 
    }
}

如果执行序列化,这只能是正确的。如果任何线程存储到a[0]而另一个线程在步骤1和4之间,那么a[0]的内容将被第二次写入无效。在像CUDA这样的大规模并行流水线执行模型中,这将是理所当然的。

另请注意,您对__syncthreads()的使用根本不会影响此行为,并且无论是否包含在代码中,内核都会出现相同的故障。

要了解如何在CUDA中并行执行此类缩减操作,请参阅CUDA reduction example,其中包含有关操作和性能调整选项的优秀白皮书。