CUDA动态并行代码的错误结果

时间:2014-01-14 09:20:37

标签: cuda

我最近碰到了Uncorrectable ECC error所示的问题。简而言之,我不时会收到 Uncorrectable ECC error ,而我的动态并行代码会产生不正确的结果。无法纠正的ECC错误最可能的假设是损坏的驱动程序堆栈,这也被另一个用户的经验间接证实(参见上面的帖子)。我现在想面对第二个问题,即算法问题。为此,我正在处理下面报告的重现器,由于原始代码生成不正确的结果使用动态并行,因此也使用此CUDA功能。

我没有看到这个代码有任何明显的问题。我认为关于子内核启动的同步应该没问题:第一个__syncthreads()不应该是必需的,cudaDeviceSynchronize()应该确保子内核的所有内存写入都在{{1}之前完成}}

我的问题是:这个代码是错误的还是错误的结果是由于非编程问题?

我的配置:CUDA 5.0,Windows 7,4-GPU系统配备Kepler K20c,驱动程序327.23。

printf

1 个答案:

答案 0 :(得分:2)

我很确定你超过launch pending limit。几乎不可能按原样判断你的代码,但是我修改了它并在子内核启动时添加了错误检查。

当我这样做时,我会发现启动错误,由打印输出!表示。跳过启动错误案例,我对P1[m]m的所有内核检查都会通过(我根本没有*打印输出。)

#include <stdio.h>

#define K 6
#define BLOCK_SIZE 256

#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
    if (code != cudaSuccess)
    {
        fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
        if (abort) { exit(code); }
    }
}

int iDivUp(int a, int b) { return ((a % b) != 0) ? (a / b + 1) : (a / b); }

__global__ void child_kernel(unsigned long long* P1)
{
    int m = threadIdx.x;

    P1[m] = (unsigned long long)m;
}

__global__ void parent_kernel(double* __restrict__ x, int M)
{
    int i = threadIdx.x + blockDim.x * blockIdx.x;

    if(i<M) {

        unsigned long long* P1 = new unsigned long long[13];

        dim3 dimBlock(2*K+1,1); dim3 dimGrid(1,1);

        __syncthreads();
        child_kernel<<<dimGrid,dimBlock>>>(P1);
        cudaDeviceSynchronize();
        cudaError_t err = cudaGetLastError();
        if (err != cudaSuccess) printf("!");
        else for(unsigned long long m=0; m<dimBlock.x; m++) if (P1[m] != m) printf("*");

    }
}

int main() {

    const int M = 19000;

//gpuErrchk(cudaSetDevice(0));

    double* x = (double*)malloc(M*sizeof(double));
    for (int i=0; i<M; i++) x[i] = (double)i;

    double* d_x; gpuErrchk(cudaMalloc((void**)&d_x,M*sizeof(double)));

    gpuErrchk(cudaMemcpy(d_x,x,M*sizeof(double),cudaMemcpyHostToDevice));

    dim3 dimBlock(BLOCK_SIZE,1); dim3 dimGrid(iDivUp(M,BLOCK_SIZE));
    parent_kernel<<<dimGrid,dimBlock>>>(d_x,M);
    gpuErrchk(cudaPeekAtLastError());
    gpuErrchk(cudaDeviceSynchronize());

    return 0;
}

随意在父内核中添加err变量的进一步解码,以说服自己超过启动暂挂限制。作为另一项测试,您可以在主机代码中将M设置为2048而不是19000,并且所有!打印输出都会消失。 (启动待定限制默认值== 2048)

正如我在评论中所述,我认为无法纠正的ECC错误是一个单独的问题,我建议尝试在评论中链接的驱动程序321.01。