堆栈空间错误(堆栈溢出错误)

时间:2015-12-06 22:24:12

标签: c++ cuda

我试图计算大小为N(方阵)的矩阵乘法,但我得到了堆栈溢出错误(我是Cuda的新手):

如果我测试N< 300一切都很好,但如果我用N>测试它300它不起作用,并显示堆栈溢出错误,但有足够的内存。在我的显卡GF 820M。 如果N = 300则300 * 300 * 4(浮点大小)= 360000字节:设备中为float类型数组分配的必要空间。这里必须分配3表来进行乘法。因此360000 * 3 = 1080000字节,如果我控制CudaMalloc,则不显示任何内容。

我告诉你,我的主要目标是测试足够大的N.我该如何解决?提前感谢您提供的任何帮助。

#include <stdio.h>
#include<device_launch_parameters.h>
#include<cuda.h>
#include<time.h>
#include<cuda_runtime.h>
#include <math.h>

__global__ void MatrixMul( float *Md , float *Nd , float *Pd , const int WIDTH )
{   // calculate thread id
          unsigned  int row = blockIdx.y*blockDim.y+threadIdx.y;
          unsigned  int col = blockIdx.x*blockDim.x+threadIdx.x;
for (int k = 0 ; k<WIDTH ; k++ )
         { Pd[row*WIDTH + col]+= Md[row * WIDTH + k ] * Nd[ k * WIDTH + col] ;  }}


int main ()
{       const int i=64 ;
       cudaEvent_t start, stop;
        float time;
       cudaEventCreate(&start);
       cudaEventCreate(&stop);
       const int WIDTH =300;
       cudaError_t cudaStatus;

   float array1_h[WIDTH][WIDTH] ,array2_h[WIDTH][WIDTH] ,M_result_array_h[WIDTH][WIDTH];
   float *array1_d , *array2_d ,*M_result_array_d ; // device array



  // Allocate GPU buffers for 2 vectors (two input, one output) 

    cudaStatus = cudaMalloc((void **) &array1_d , WIDTH*WIDTH*sizeof (float));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!"); }  


    cudaStatus = cudaMalloc((void **) &array2_d , WIDTH*WIDTH*sizeof (float));
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!"); }  




       for ( int i = 0 ; i<WIDTH ; i++ ) { 
           for (int j = 0 ; j<WIDTH ; j++ )
           { array1_h[i][j] = 1 ; array2_h[i][j] = 2 ; }}


  //copy host array to device array; cudaMemcpy ( dest , source , WIDTH , direction )



  cudaMemcpy ( array1_d , array1_h , WIDTH*WIDTH*sizeof (float) , cudaMemcpyHostToDevice ) ;

  cudaMemcpy ( array2_d , array2_h , WIDTH*WIDTH*sizeof (float) , cudaMemcpyHostToDevice ) ;



  //allocating memory for resultent device array

  cudaStatus = cudaMalloc((void **) &M_result_array_d , WIDTH*WIDTH*sizeof (float) ) ;
    if (cudaStatus != cudaSuccess) {
        fprintf(stderr, "cudaMalloc failed!"); }  

  //calling kernal

  dim3 dimBlock( i,i, 1 ) ;
  dim3 dimGrid ( ((WIDTH-1)/i) +1 , ((WIDTH-1)/i)+1 ,1 ) ;

  cudaEventRecord(start, 0);
MatrixMul <<<dimGrid,dimBlock>>> ( array1_d , array2_d ,M_result_array_d , WIDTH) ;
    cudaEventRecord(stop, 0);
   cudaEventSynchronize(stop);
   cudaEventElapsedTime(&time, start, stop);
   printf ("taille du probleme:%d Time for the kernel: %f \n",WIDTH,time);


  //copy back result_array_d to result_array_h

  cudaMemcpy(M_result_array_h , M_result_array_d , WIDTH*WIDTH*sizeof(float) , cudaMemcpyDeviceToHost) ;


  //printf the result array
  for (int i = 0 ; i<WIDTH ; i++ )
  { for (int j = 0 ; j < WIDTH ; j++ )
     {   printf ("%f   ",M_result_array_h[i][j] ) ; }
              printf ("\n") ; } 


    cudaFree(array1_d);
    cudaFree(array2_d);
    cudaFree(M_result_array_h);


  system("pause") ; }

2 个答案:

答案 0 :(得分:1)

  1. 堆栈溢出问题与CUDA无关。这些分配:

    float array1_h[WIDTH][WIDTH] ,array2_h[WIDTH][WIDTH] ,M_result_array_h[WIDTH][WIDTH];
    

    由堆栈上的编译器创建。堆栈空间有限。 (这是主机代码,因此这里的堆栈与GPU无关。)

    解决此问题的一种可能方法是为这些变量创建动态分配,这些变量将在堆上进行,而堆的限制与堆栈没有相同的限制。

    所以一个可能的解决办法是替换它:

    float array1_h[WIDTH][WIDTH] ,array2_h[WIDTH][WIDTH] ,M_result_array_h[WIDTH][WIDTH];
    

    用这个:

    typedef float ar_type[WIDTH];
    ar_type *array1_h, *array2_h, *M_result_array_h;
    array1_h = (ar_type *)malloc(WIDTH*WIDTH*sizeof(float));
    array2_h = (ar_type *)malloc(WIDTH*WIDTH*sizeof(float));
    M_result_array_h = (ar_type *)malloc(WIDTH*WIDTH*sizeof(float));
    
  2. 另请注意:

    const int i=64 ;
    ...
    dim3 dimBlock( i,i, 1 ) ;
    

    无效。您正在请求64x64线程块(总共4096个线程),这对任何CUDA GPU都不合法。您可以通过将i更改为32来解决此特定问题。

  3. 在修复之后,似乎你的内核没有线程检查来防止越界线程执行和生成越界访问。您可以通过在内核中的for循环之前立即添加此线程检查来解决此问题:

    if ((row < WIDTH) && (col < WIDTH))
    
  4. 最后,这一行有一个拼写错误:

    cudaFree(M_result_array_h);
    

    我认为你的意思是:

    cudaFree(M_result_array_d);
    
  5. 如果您在代码中添加proper cuda error checking和/或使用cuda-memcheck运行代码,则可以发现其他错误(2-4)。

答案 1 :(得分:0)

使用rtContextGetStackSize / rtContextSetStackSize查找堆栈的大小,并根据需要将其设置得更大。 请记住,图形卡上的内存与其他图形处理程序共享,您无法全部使用它。

此外,您可以对矩阵进行分区,并使用逐块算法计算Partitioned Matrix Multiplication,而不是整个矩阵。