程序启动时的堆栈溢出异常(CUDA Monte Carlo Pi)

时间:2011-05-30 01:02:35

标签: exception cuda stack-overflow montecarlo pi

我的问题是,当程序首次进入main时,我在程序启动时收到堆栈溢出异常。我的程序是使用CUDA的并行蒙特卡罗Pi计算器。当我尝试在Visual Studio中调试程序时,在我可以选择的任何断点之前会弹出异常。任何帮助表示赞赏。

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

#define NUM_THREAD 512
#define NUM_BLOCK 65534

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
// 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){
    extern __shared__ int sdata[];
//  unsigned int tid = threadIdx.x;
    unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
    unsigned int k, incircle;
    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 = sqrt(x*x + y*y);
    if (z <= 1) incircle++;
    else{}
    }
    __syncthreads();
    g_odata[i] = incircle;
}
///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
int main() {

    float* solution = (float*)calloc(100, sizeof(float));
    float *sumDev, sumHost[NUM_BLOCK*NUM_THREAD];
    int trials, total; 
    curandState *devStates;



    trials = 100;
    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
    cudaMalloc((void **) &sumDev, size); // Allocate array on device
    cudaMalloc((void **) &devStates, size*sizeof(curandState));
    // Do calculation on device by calling CUDA kernel
    monteCarlo <<<dimGrid, dimBlock, size>>> (sumDev, trials, devStates);
        // call reduction function to sum
    reduce0 <<<dimGrid, dimBlock, size>>> (sumDev);
    // Retrieve result from device and store it in host array
    cudaMemcpy(sumHost, sumDev, size, cudaMemcpyDeviceToHost);

    *solution = 4*(sumHost[0]/total);
    printf("%.*f\n", 1000, *solution);
    free (solution);
    //*solution = NULL;
    return 0;
}

2 个答案:

答案 0 :(得分:1)

您要声明共享内存的大小=大小;喜欢这里

monteCarlo <<<dimGrid, dimBlock, size>>>

size = 512 * 65534 * 4 = 2 ^ 9 * 2 ^ 16 * 2 ^ 2 = 2 ^ 27(超过我能想到的任何卡上共享内存的最大值)。

但是看看你的内核,我想你希望共享内存等于你拥有的线程数。

所以你要么做

1)
这用于启动你的内核

monteCarlo <<<dimGrid, dimBlock, (NUM_THREADS * sizeof(int))>>>

2)
或者使用它来启动内核

monteCarlo <<<dimGrid, dimBlock>>> 

这是在你的内核中声明你的共享内存。

__shared__ int sdata[NUM_THREADS]; // Note: no extern before __shared__

我个人更喜欢这两种内核的方法二,因为共享内存与线程数成正比,但已知线程数是常量。它也稍快一些。

修改

除了上述问题外,我怀疑这可能会导致问题。

 cudaMalloc((void **) &devStates, size*sizeof(curandState));

因为这个本身就是这个。

size = NUM_BLOCKS * NUM_THREADS * sizeof(float);

可能你想这样做吗?

cudaMalloc((void **) &devStates, (NUM_BLOCKS *NUM_THREADS)*sizeof(curandState));

至于实际的堆栈溢出问题,您可能需要查看talonmies post

答案 1 :(得分:1)

我认为问题是:

float *sumDev, sumHost[NUM_BLOCK*NUM_THREAD];

代表

#define NUM_THREAD 512
#define NUM_BLOCK 65534

这将为您留下大约130Mb的静态声明数组。我怀疑编译器运行时库可以处理如此大的静态分配,这就是你得到即时堆栈溢出的原因。用动态分配替换它,堆栈溢出问题就会消失。但仔细阅读Pavan's post,因为一旦你修复了堆栈溢出,CUDA代码本身也需要重新设计才能生效。