CUDA程序导致nvidia驱动程序崩溃

zet*_*atr 4 crash cuda driver nvidia

我的monte carlo pi计算CUDA程序导致我的nvidia驱动程序在我超过500次试验和256个完整程序段时崩溃.它似乎发生在monteCarlo内核函数中.非常感谢.

#include <stdio.h>
#include <stdlib.h>
#include <cuda.h>
#include <curand.h>
#include <curand_kernel.h>


#define NUM_THREAD 256
#define NUM_BLOCK 256



///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////

// Function to sum an array
__global__ void reduce0(float *g_odata) {
extern __shared__ int sdata[];

// each thread loads one element from global to shared mem
unsigned int tid = threadIdx.x;
unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
sdata[tid] = g_odata[i];
__syncthreads();

// do reduction in shared mem
for (unsigned int s=1; s < blockDim.x; s *= 2) { // step = s x 2
    if (tid % (2*s) == 0) { // only threadIDs divisible by the step participate
        sdata[tid] += sdata[tid + s];
    }
    __syncthreads();
}

// write result for this block to global mem
if (tid == 0) g_odata[blockIdx.x] = sdata[0];
}

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
__global__ void monteCarlo(float *g_odata, int  trials, curandState *states){
//  unsigned int tid = threadIdx.x;
    unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
    unsigned int incircle, k;
    float x, y, z;
    incircle = 0;

    curand_init(1234, i, 0, &states[i]);

    for(k = 0; k < trials; k++){
        x = curand_uniform(&states[i]);
        y = curand_uniform(&states[i]);
        z =(x*x + y*y);
        if (z <= 1.0f) incircle++;
    }
    __syncthreads();
    g_odata[i] = incircle;
}
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
int main() {

    float* solution = (float*)calloc(100, sizeof(float));
    float *sumDev, *sumHost, total;
    const char *error;
    int trials; 
    curandState *devStates;

    trials = 500;
    total = trials*NUM_THREAD*NUM_BLOCK;

    dim3 dimGrid(NUM_BLOCK,1,1); // Grid dimensions
    dim3 dimBlock(NUM_THREAD,1,1); // Block dimensions
    size_t size = NUM_BLOCK*NUM_THREAD*sizeof(float); //Array memory size
    sumHost = (float*)calloc(NUM_BLOCK*NUM_THREAD, sizeof(float));

    cudaMalloc((void **) &sumDev, size); // Allocate array on device
    error = cudaGetErrorString(cudaGetLastError());
    printf("%s\n", error);


    cudaMalloc((void **) &devStates, (NUM_THREAD*NUM_BLOCK)*sizeof(curandState));
    error = cudaGetErrorString(cudaGetLastError());
    printf("%s\n", error);


    // Do calculation on device by calling CUDA kernel
    monteCarlo <<<dimGrid, dimBlock>>> (sumDev, trials, devStates);
    error = cudaGetErrorString(cudaGetLastError());
    printf("%s\n", error);

        // call reduction function to sum
    reduce0 <<<dimGrid, dimBlock, (NUM_THREAD*sizeof(float))>>> (sumDev);
    error = cudaGetErrorString(cudaGetLastError());
    printf("%s\n", error);

    dim3 dimGrid1(1,1,1);
    dim3 dimBlock1(256,1,1);
    reduce0 <<<dimGrid1, dimBlock1, (NUM_THREAD*sizeof(float))>>> (sumDev);
    error = cudaGetErrorString(cudaGetLastError());
    printf("%s\n", error);

    // Retrieve result from device and store it in host array
    cudaMemcpy(sumHost, sumDev, sizeof(float), cudaMemcpyDeviceToHost);
    error = cudaGetErrorString(cudaGetLastError());
    printf("%s\n", error);


    *solution = 4*(sumHost[0]/total);
    printf("%.*f\n", 1000, *solution);
    free (solution);
    free(sumHost);
    cudaFree(sumDev);
    cudaFree(devStates);
    //*solution = NULL;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

har*_*ism 8

如果较少数量的试验正常工作,并且如果您在没有NVIDIA Tesla计算群集(TCC)驱动程序的MS Windows上运行和/或您正在使用的GPU连接到显示器,那么您可能超出了操作系统的"看门狗" " 超时.如果内核占用显示设备(或没有TCC的Windows上的任何GPU)太长时间,操作系统将终止内核,以便系统不会变为非交互式.

解决方案是在非显示器连接的GPU上运行,如果您在Windows上,请使用TCC驱动程序.否则,您将需要减少内核中的试验次数并多次运行内核以计算所需的试验次数.

编辑:根据CUDA 4.0 curand文档(第15页,"性能说明"),您可以通过将生成器的状态复制到内核中的本地存储,然后将状态存回(如果需要再次)来提高性能你完蛋了:

curandState state = states[i];

for(k = 0; k < trials; k++){
    x = curand_uniform(&state);
    y = curand_uniform(&state);
    z =(x*x + y*y);
    if (z <= 1.0f) incircle++;
}
Run Code Online (Sandbox Code Playgroud)

接下来,它提到设置很昂贵,并建议您将curand_init移动到单独的内核中.这可能有助于降低MC内核的成本,因此您不会遇到监视器.

我建议阅读文档的那一部分,有几个有用的指南.

  • 我从文档中添加了一些性能提示到我的答案 - 我打赌你可以把时间缩短,这不应该是一个昂贵的内核 - curand_uniform只有几个翻牌,如果你把状态保存在局部变量中,它将保存在一个登记册中.我猜测真正的费用是curand_init(),当你注释掉curand_uniform()时,编译器可能会死掉代码,使得看起来像curand_uniform很贵.将curand_init移动到一个单独的内核并将状态转换为局部变量,你应该好多了.你可能想要x和y的单独状态... (2认同)

Mic*_*ala 6

对于那些拥有不支持TCC驱动程序的geforce GPU的人来说,有另一种解决方案基于:

http://msdn.microsoft.com/en-us/library/windows/hardware/ff569918(v=vs.85).aspx

  1. 开始注册,
  2. 导航到HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GraphicsDrivers
  3. 创建名为TdrLevel的新DWORD键,将值设置为0,
  4. 重启电脑.

现在你的长期运行的内核不应该被终止.这个答案基于:

修改注册表以增加GPU超时,Windows 7

我只是觉得在这里提供解决方案可能也很有用.