Программа CUDA вызывает сбой драйвера nvidia - PullRequest
4 голосов
/ 31 мая 2011

Моя программа 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;
}

Ответы [ 2 ]

8 голосов
/ 31 мая 2011

Если меньшее количество испытаний работает правильно, и если вы работаете в MS Windows без драйвера NVIDIA Tesla Compute Cluster (TCC) и / или используемого вами графического процессора, подключенного к дисплею, то вы, вероятно, превышаете рабочуюТайм-аут системы.Если ядро ​​слишком долго занимает устройство отображения (или любой графический процессор в Windows без TCC), ОС уничтожит ядро, чтобы система не стала неинтерактивной.

Решение заключается в запуске нане подключенный к дисплею графический процессор, и если вы работаете в Windows, используйте драйвер TCC.В противном случае вам нужно будет уменьшить количество испытаний в вашем ядре и запустить ядро ​​несколько раз, чтобы вычислить необходимое количество испытаний.

РЕДАКТИРОВАТЬ: Согласно CUDA 4.0 curand docs (стр. 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++;
}

Далее упоминается, что установка дорогая, и предлагается переместить curand_init в отдельное ядро.Это может помочь снизить стоимость вашего ядра MC, чтобы вы не столкнулись со сторожевым таймером.

Я рекомендую прочитать этот раздел документации, есть несколько полезных рекомендаций.

6 голосов
/ 23 июня 2014

Для тех из вас, у кого GeForce GPU не поддерживает драйвер TCC, есть другое решение, основанное на:

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

  1. start regedit,
  2. перейдите к HKEY_LOCAL_MACHINE \ System \ CurrentControlSet \ Control \ GraphicsDrivers
  3. создайте новый ключ DWORD с именем TdrLevel, установите значение 0,
  4. перезагрузите ПК.

Теперь вашдолго работающие ядра не должны быть прекращены.Этот ответ основан на:

Изменение реестра для увеличения времени ожидания GPU, windows 7

Я просто подумал, что здесь также может быть полезно найти решение.

...