为什么我的CUDA代码无法正常填充大型矩阵?

时间:2015-01-08 02:24:49

标签: c++ matrix cuda parallel-processing nvidia

这是一个简单的CUDA代码,用于初始化一个大矩阵(填充零)。

如果代码有效,我输出第一个1 * 3矩阵。它应该全是零。

如果我将矩阵大小设置得很小,那么程序就能正常工作。但是当我把尺寸变大(> 43200 * 2400)时,矩阵里面的东西都是垃圾。

我已经在每个CUDA函数的末尾追加了cudaDeviceSynchronize()。

我使用的是NVIDIA Quadro K4200,Xeon E5-2630和Ubuntu 14.04。

感谢有人在这里帮助我。

以下是我的完整代码。

#include <stdio.h>
#include <math.h>
#include <iostream>
#include <cuComplex.h>

#define BLOCK_SIZE 16 // change it to 16 to get maximum performance


// populate the matrix using first row
__global__ void RepmatKernel (cuComplex *Mat, const unsigned int N, const unsigned int Cols) 
{
    unsigned int i = (unsigned int)blockIdx.x * (unsigned int)blockDim.x + (unsigned int)threadIdx.x;
    if (i < N) 
    {
        Mat[i].x = 0;
        Mat[i].y = 0;
    }
}

// main routine
int main ()
{

  const unsigned int Rows = 43200;
  const unsigned int Cols = 2400;

  const unsigned int Num_thrd = 256; // max threads per block 

  unsigned int Mat_size = Rows * Cols; // size of array

  cuComplex *vec; // supposedly the input

  cuComplex *mat_debug; // for debug

  vec = new cuComplex [Cols];

  mat_debug = new cuComplex [Rows*Cols];

  cuComplex *mat_in_d;  // device array

  //input in host array
  for(unsigned int i = 0; i < Cols; i++)
  {
      vec[i].x = 3*i+4;
      vec[i].y = 0.2*i+1;
  }

  const unsigned int size_mat_d =    Rows * Cols * sizeof(cuComplex); 

  //create device array cudaMalloc ( (void **)&array_name, sizeofmatrixinbytes) ;
  if (cudaMalloc((void **) &mat_in_d ,  size_mat_d) != cudaSuccess) std::cout<<"Error allocating GPU";
  cudaDeviceSynchronize() ;

  //copy host array to device array; cudaMemcpy ( dest , source , WIDTH , direction )
  cudaMemcpy ( mat_in_d , vec , Cols , cudaMemcpyHostToDevice ) ;
  cudaDeviceSynchronize() ;


// ========================================================================
  cudaMemcpy(mat_debug , mat_in_d , size_mat_d , cudaMemcpyDeviceToHost) ;
  cudaDeviceSynchronize() ;

  std::cout<<"before repmat="<<std::endl;
  std::cout<<"[";
  for(unsigned int i = 0; i < 3; i++)
  {
    std::cout<< mat_debug[i * Cols].x <<"+"<<mat_debug[i * Cols].y <<"i,  ";
    std::cout<<";"<<std::endl;
  }
  std::cout<<"]"<<std::endl;
// ==========================================================================

  RepmatKernel<<<(unsigned int)ceil((float)(Mat_size)/(float)(Num_thrd)),
               (Num_thrd)>>>(mat_in_d,
                     Mat_size,
                     Cols);
  cudaDeviceSynchronize();

// ========================================================================
  cudaMemcpy(mat_debug , mat_in_d , size_mat_d , cudaMemcpyDeviceToHost) ;
  cudaDeviceSynchronize() ;

  std::cout<<"after repmat="<<std::endl;
  std::cout<<"[";
  for(unsigned int i = 0; i < 3; i++)
  {

    std::cout<< mat_debug[i * Cols].x <<"+"<<mat_debug[i * Cols].y <<"i,  ";
    std::cout<<";"<<std::endl;
  }
  std::cout<<"]"<<std::endl;
// ==========================================================================



  cudaFree(mat_in_d);


  delete [] vec; 

  delete [] mat_debug;

  return 0;
}    

2 个答案:

答案 0 :(得分:1)

您对cudaMalloc 的调用声明存在问题,但实际上并未终止计算。你应该放一个

if (cudaMalloc((void **) &mat_in_d ,  size_mat_d) != cudaSuccess) 
{
    std::cout<<"Error allocating GPU\n";
    return 1;
}

这样当你溢出内存时计算实际上就停止了,而不是只用std::cout的警告来尝试工作。更好的方法是使用error handling macro

另一个问题是:

cudaMemcpy ( mat_in_d , vec , Cols , cudaMemcpyHostToDevice );

首先,mat_in_d的大小为Rows * Cols * sizeof(cuComplex),但您只是将Cols个字节复制到其中。即使您只想将vec复制到mat_in_d向量的第一部分,您也需要将其更改为

cudaMemcpy ( mat_in_d , vec , Cols*sizeof(cuComplex) , cudaMemcpyHostToDevice );

此时,您希望矩阵的第一个Cols条目合理,其余条件是垃圾。 (做出建议的更改表明情况确实如此;为什么你想这样做是一个更好的问题。)

接下来是内核调用,其目标是将Mat的条目设置为零。这应该使用cudaMemset完成,即只需使用

cudaMemset(mat_in_d, 0, Mat_size*sizeof(cuComplex));

我们可以更仔细地查看执行配置,看看你的内核调用出了什么问题,但是现在这可以解决你的问题。

答案 1 :(得分:0)

用于调试CUDA错误;我从样本helper_cuda.h找到一个标题,非常方便。我几乎总是在我的项目中包含这个标题,它位于样本的公共目录中。

然后,使用checkCudaErrors()包装所有CUDA调用,如checkCudaErrors(cudaMalloc((void **) &mat_in_d , size_mat_d));,会显示错误消息。

在我的情况下,因为只有mat_in_d接近1 GB且我的GPU的内存只有512 MB,所以它确实失败并抛出cudaErrorMemoryAllocation。但是,NVIDIA Quadro K4200不应该那么容易失败!

您是否使用cudaMemGetInfo检查了实际可用的内存信息?