为啥我的 CUDA 代码无法正常工作以零填充大型矩阵?

Posted

技术标签:

【中文标题】为啥我的 CUDA 代码无法正常工作以零填充大型矩阵?【英文标题】:Why is my CUDA code not working properly for zero filling a large matrix?为什么我的 CUDA 代码无法正常工作以零填充大型矩阵? 【发布时间】:2015-03-06 02:06:27 【问题描述】:

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

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

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

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

我在 Ubuntu 14.04 上使用 NVIDIA Quadro K4200、Xeon E5-2630。

感谢任何人在这里帮助我。

下面附上我的完整代码。

#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;
    

【问题讨论】:

所有 memcpy 和内核启动都返回成功状态吗? 我怎样才能明确地检查这个?像 cudaMalloc((void **) &mat_in_d , size_mat_d) != cudaSuccess 之类的东西?我会尝试发布结果。谢谢! 如果您包含helper_cuda.h,您可以使用checkCudaErrors() 将它们全部包装起来。 是的,您可能想熟悉一下运行时错误检查的概念。这样做始终是回答“为什么这段代码没有按预期工作?”问题的良好第一步。 看看proper cuda error checking。您还可以使用cuda-memcheck 运行您的代码,以快速了解任何错误。另外,请确保您使用适合您的 GPU 的拱形开关进行编译,例如 nvcc -arch=sm_30 ... 如果您不这样做,nvcc 将针对一些较低的架构进行编译,并且您的内核将不会启动,因为第一个启动配置参数 ( ceil((float)(Mat_size)/(float)(Num_thrd)) 足够大,需要一个 cc3.0 编译目标。如果您为较低的目标(4300x2400 大小)编译,它将无法启动。 【参考方案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));

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

【讨论】:

感谢您的帮助!我解决了这些问题。目前程序无法为那个大矩阵分配空间。 cudaMalloc 抛出错误。我使用了 -arch=sm_30 但这没有帮助。 我建议在调用cudaMalloc 之前使用cudaGetDeviceProperties 查询您的卡上有多少RAM。您的卡可能只是没有足够的 RAM。 要检查 malloc 上的错误,您应该获取错误字符串以获取更多信息。试试这个而不是你的 malloc... cudaError_t err = cudaMalloc((void **) &mat_in_d , size_mat_d); if(err != cudaSuccess) std::cout 【参考方案2】:

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

然后,使用 checkCudaErrors() 包装所有 CUDA 调用,例如 checkCudaErrors(cudaMalloc((void **) &amp;mat_in_d , size_mat_d));,会给出明确的错误消息。

在我的例子中,由于 mat_in_d 接近 1 GB,而我的 GPU 内存只有 512 MB,它肯定会失败并抛出 cudaErrorMemoryAllocation。但是,NVIDIA Quadro K4200 不应该那么容易失败!

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

【讨论】:

非常感谢您的回答!我正在尝试添加 helper_cuda.h,但看起来找不到该文件。我应该如何安装这个?再次感谢! 它应该与您的 cuda 工具包安装(示例)一起提供,您的操作系统是什么? 它是 Ubuntu 14.04。我关注r-tutor.com/gpu-computing/cuda-installation/…,目前正在安装。希望我可以直接包含 。如果我有进一步的问题,我会在这里发布。谢谢! 好的,在你的编译步骤中,包含标志-I/usr/local/cuda/samples/common/inc-I/usr/local/cuda-6.5/samples/common/inc,并在你的.cu文件中,添加行#include &lt;helper_cuda.h&gt; 所以,如果你的源文件命名为test.cu,你可以编译成:/usr/local/cuda/bin/nvcc -m64 -gencode arch=compute_30,code=sm_30 -I/usr/local/cuda/samples/common/inc test.cu

以上是关于为啥我的 CUDA 代码无法正常工作以零填充大型矩阵?的主要内容,如果未能解决你的问题,请参考以下文章

成功构建后,带有 Cuda 的 Python OpenCV 无法正常工作

为啥我的 javascript 在 github 页面上无法正常工作?

为啥我的 web3 导入无法正常工作?

为啥我的 JavaScript 在 Safari 的严格模式下无法正常工作?

为啥重新安装我的 iOS 应用后 Firebase Messaging 无法正常工作?

为啥我的邮递员基本身份验证无法正常工作?