我试图计算大小为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") ; }
答案 0 :(得分: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));
另请注意:
const int i=64 ;
...
dim3 dimBlock( i,i, 1 ) ;
无效。您正在请求64x64线程块(总共4096个线程),这对任何CUDA GPU都不合法。您可以通过将i
更改为32来解决此特定问题。
在修复之后,似乎你的内核没有线程检查来防止越界线程执行和生成越界访问。您可以通过在内核中的for循环之前立即添加此线程检查来解决此问题:
if ((row < WIDTH) && (col < WIDTH))
最后,这一行有一个拼写错误:
cudaFree(M_result_array_h);
我认为你的意思是:
cudaFree(M_result_array_d);
如果您在代码中添加proper cuda error checking和/或使用cuda-memcheck
运行代码,则可以发现其他错误(2-4)。
答案 1 :(得分:0)
使用rtContextGetStackSize / rtContextSetStackSize查找堆栈的大小,并根据需要将其设置得更大。 请记住,图形卡上的内存与其他图形处理程序共享,您无法全部使用它。
此外,您可以对矩阵进行分区,并使用逐块算法计算Partitioned Matrix Multiplication,而不是整个矩阵。