为啥我的 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 **) &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 <helper_cuda.h>
。
所以,如果你的源文件命名为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 页面上无法正常工作?
为啥我的 JavaScript 在 Safari 的严格模式下无法正常工作?