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

CUDA动态并行代码的错误结果,cuda,Cuda,我最近偶然遇到了在上所说明的问题。简而言之,我不时收到一个不可纠正的ECC错误,我的动态并行代码生成不正确的结果。不可纠正ECC错误的最可能假设是驱动程序堆栈损坏,另一个用户的经验也间接地证实了这一点(见上文)。我现在要面对第二个问题,即算法问题。为此,我正在处理下面报告的复制器,因为生成不正确结果的原始代码使用动态并行,所以也使用这个CUDA特性 我看不出这段代码有任何evindent问题。我认为关于子内核启动的同步应该是可以的:第一个\uuu syncthreads()应该是不必要的,而cu

我最近偶然遇到了在上所说明的问题。简而言之,我不时收到一个不可纠正的ECC错误,我的动态并行代码生成不正确的结果。不可纠正ECC错误的最可能假设是驱动程序堆栈损坏,另一个用户的经验也间接地证实了这一点(见上文)。我现在要面对第二个问题,即算法问题。为此,我正在处理下面报告的复制器,因为生成不正确结果的原始代码使用动态并行,所以也使用这个CUDA特性

我看不出这段代码有任何evindent问题。我认为关于子内核启动的同步应该是可以的:第一个
\uuu syncthreads()
应该是不必要的,而
cudaDeviceSynchronize()
应该确保子内核的所有内存写入都在
printf
之前完成

我的问题是:这段代码是错误的还是错误的结果是由于非编程问题造成的

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

#include <stdio.h>
#include <conio.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) { getch(); exit(code); }
    }
}

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

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

    P1[m] = (double)m;
}

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

    if(i<M) {

        double* P1 = new double[13];

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

        __syncthreads();
        child_kernel<<<dimGrid,dimBlock>>>(P1);
        cudaDeviceSynchronize();

        for(int m=0; m<2*K+1; m++) printf("%f %f\n",P1[m],(double)m);

    }
}

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());

    getch();

    return 0;
}
#包括
#包括
#定义k6
#定义块大小为256
#定义gpuerchk(ans){gpuAssert((ans),_文件_,_行__)}
内联void gpuAssert(cudaError\u t代码,char*文件,int行,bool abort=true)
{
如果(代码!=cudaSuccess)
{
fprintf(标准,“GPUassert:%s%s%d\n”,cudaGetErrorString(代码)、文件、行);
如果(中止){getch();退出(代码);}
}
}
intidivup(inta,intb){返回((a%b)!=0)?(a/b+1):(a/b);}
__全局无效子内核(双*P1)
{
int m=threadIdx.x;
P1[m]=(双)m;
}
__全局无效父内核(双*限制,整数M)
{
int i=threadIdx.x+blockDim.x*blockIdx.x;

如果(i),我很确定你已经超过了。你的代码几乎不可能保持原样,但我已经修改了它,并在子内核启动时添加了错误检查

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

#包括
#定义k6
#定义块大小为256
#定义gpuerchk(ans){gpuAssert((ans),_文件_,_行__)}
内联void gpuAssert(cudaError\u t代码,char*文件,int行,bool abort=true)
{
如果(代码!=cudaSuccess)
{
fprintf(标准,“GPUassert:%s%s%d\n”,cudaGetErrorString(代码)、文件、行);
if(abort){exit(code);}
}
}
intidivup(inta,intb){返回((a%b)!=0)?(a/b+1):(a/b);}
__全局无效子内核(无符号长*P1)
{
int m=threadIdx.x;
P1[m]=(无符号长)m;
}
__全局无效父内核(双*限制,整数M)
{
int i=threadIdx.x+blockDim.x*blockIdx.x;

如果(I)当你说你有不正确的结果时,结果是什么?你确定这不是像
printf
buffer overflow那样简单吗?@talonmes通常,我第一次启动代码时会收到“或多或少”的结果正确的结果是,同一行中的两个数字基本上是一致的。随后我启动它时,
P1[m]
的数量不断增加,这与
(双精度)不同m
具有不合理的
值。不,我不确定这是否是
printf
缓冲区溢出。要检查它,我应该将
printf
分流,并使用调试器或将
P1
传递到
main
,这是我在接下来的几个小时内无法进行的测试,因为机器暂时很忙。@Talonmesd请您告诉我一些已知的方向,以避免
printf
缓冲区溢出,这是一件非常好的事情。请看一下
cudaDeviceSetLimit
。您的
new
分配和
printf
存储到的堆有一些设置。如果它们不够大,那么代码将无法工作k正如预期的那样。您的内核
new
也可能会失败,并且您也没有检查.19000 x 13 x 8字节=~2MB,因此可能没有超过限制,但是如果有疑问,您可以检查返回的指针是否为null,这表示分配错误。非常感谢您的回答。现在我无法测试您的代码ce这台机器在一次模拟中被一位同事卡住了,他有一个截止日期,我将在周一继续解决这个问题。与此同时,我已经研究了你对这个问题的答案,这对我很有启发。我错误地相信,父内核的错误检查会捕获子内核启动时的错误,现在我将添加t他还对设备内核启动进行了错误检查。我终于测试了您的代码,确实超出了启动挂起限制。特别是,如果我将
err
变量的解码更改为
if(err==cudaerrorlaunchpendingcountextended)printf(“!”);
,然后我收到
。另外,如果我设置
gpuerchk(cudadevevicesetlimit(cudaLimitDevRuntimePendingLaunchCount,20000));
在代码开头,我不再收到
。最后,通过将挂起的启动计数设置为
20000
,我的原始代码现在可以正常工作。谢谢。我将接受您的回答。
#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;
}