【发布时间】:2020-10-11 16:09:51
【问题描述】:
在调用 cudaMemcpy 时,我一直在尝试使用玩具程序修复分段错误(核心转储)错误消息。它适用于小图像,但对于较大的图像通常会失败;我说正常,因为在使用 valgrind 进行调试时它有时会成功(更多内容见下文)。我看过类似的问题,但一直找不到答案;抱歉,如果这是重复的!我只是在学习(并且正在学习大规模并行处理器的编程)。
这是我的代码,已清理:
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <cuda.h>
#include <iostream>
#include <cuda_runtime.h>
using namespace cv;
using namespace std;
__global__ void
colorToGreyKernel(unsigned char* outPic, unsigned char* inPic, unsigned int width, unsigned int height){
// printf("trying \n" );
int Col = blockDim.x * blockIdx.x + threadIdx.x;
int Row = blockDim.y * blockIdx.y + threadIdx.y;
if( Col < width && Row < height){
int greyOffset = Row * width + Col;
int rgbOffset = greyOffset * 3;
unsigned char b = inPic[rgbOffset];
unsigned char g = inPic[rgbOffset +1];
unsigned char r = inPic[rgbOffset +2];
outPic[greyOffset] = 0.21f*r + 0.71f*g + 0.07f*b;
}
}
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
bool test = code == cudaSuccess;
// cout << "code " << std::boolalpha<< test;
if (code != cudaSuccess)
{
// const char *errorStr = NULL;
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
int main(int argc, char** argv )
{
if ( argc != 2 )
{
printf("usage: DisplayImage.out <Image_Path>\n");
return -1;
}
Mat image;
unsigned int imSize[2] = {400,400};
unsigned char* inPic = NULL;
unsigned char* outPic = NULL;
gpuErrchk(cudaMalloc(&inPic, imSize[0] * imSize[1] * 3 * sizeof(CV_8U)));
gpuErrchk(cudaMalloc(&outPic, imSize[0] * imSize[1] * sizeof(CV_8U)));
image = imread( argv[1], IMREAD_COLOR );
resize(image, image, Size(imSize[0],imSize[1]));
Mat greyImg(image.rows, image.cols, CV_8U, Scalar(125));
size_t size = image.cols * image.rows * image.channels() * sizeof(CV_8U);
// This is where it always fails for bigger images
gpuErrchk(cudaMemcpy(inPic,(void*) &image.data[0], size, cudaMemcpyHostToDevice));
gpuErrchk(cudaMemcpy(outPic, (void*)&greyImg.data[0], size/3, cudaMemcpyHostToDevice));
dim3 dimGrid(ceil(image.rows/16.0),ceil(image.cols/16.0),1);
dim3 dimBlock(16,16,1);
colorToGreyKernel<<<dimGrid, dimBlock>>>(outPic, inPic,(int) image.rows,(int) image.cols);
cudaDeviceSynchronize();
gpuErrchk(cudaGetLastError());
gpuErrchk(cudaMemcpy(greyImg.data, outPic, size / 3, cudaMemcpyDeviceToHost));
namedWindow("Display Image", WINDOW_AUTOSIZE );
imshow("Display Image", greyImg);
waitKey(0);
cudaFree(&inPic[0]);
cudaFree(&outPic[0]);
return 0;
}
我可以在设备上进行分配,但是对于更大的图像,复制失败。我已经使用 opencv::cuda 进行了尝试,我可以加载任何图片并在设备上执行 cvtColor 而无需调整大小,所以我得出结论它不是内存(在查看 nvidia-smi 时类似)。
当我使用 valgrind 运行时,我收到很多 Invalid write of size 8 错误,所有这些都引用 libcuda。通过隔离它,我知道问题出在这个特定的内存副本上。有时它也适用于 valgrind,但我认为这是正常的。我还没有使用 valgrind 的经验,但是内存问题对我来说没有意义(我正在尝试将复制到设备,那么为什么会出现与主机相关的分段错误?)。
我的问题很简单,错误从何而来,如何解决?
NVCC = 11.1 gpu = GeForce GTX 960M(不是很多,但没关系)
再次,我是 Cuda 编程的新手,但尝试了我能想到的并且无法隔离问题!感谢您的帮助。
【问题讨论】:
-
这里的问题是您对 OpenCV 的使用,而不是 CUDA。像
CV_8U这样的项目是not a type,它是一个编译器#define。因此sizeof(CV_8U)没有做你认为它正在做的事情。因此,您对size的计算是错误的。因此,当cudaMemcpy操作尝试访问&image.data[0]以获取size字节时,您将超出缓冲区的末尾。对于足够大的size计算(足够大的图像),您将遇到段错误。这基本上与CUDA无关。 -
作为一个简单的修复方法,只需在您拥有
* sizeof(CV_8U)的所有位置删除它,您的代码就可以正常工作。 -
该修复确实有效,并解释了我的代码存在的问题。 sizeof(CV_8U) 的大小为 4,而不是 sizeof(unsigned int) == 1。谢谢!
-
sizeof(unsigned int)不是 1。 -
对不起,意思是无符号字符。
标签: c++ cuda segmentation-fault