从设备到主机的cudaMemcpy错误

从设备到主机的cudaMemcpy错误,cuda,Cuda,在内核上计算之后,我返回一个二维结构,从设备到主机 HANDLE_ERROR(cudaMemcpy(Pixel,Pixel_gpu,img_wd*img_ht*sizeof(pixel),cudaMemcpyDeviceToHost)); 像素在主机上声明,像素gpu在设备上分配,如下所示: **Pixel_gpu; HANDLE_ERROR(cudaMalloc(&Pixel_gpu,img_wd*img_ht*sizeof(pixel))); pixel **Pixel = (p

在内核上计算之后,我返回一个二维结构,从设备到主机

HANDLE_ERROR(cudaMemcpy(Pixel,Pixel_gpu,img_wd*img_ht*sizeof(pixel),cudaMemcpyDeviceToHost));
像素在主机上声明,像素gpu在设备上分配,如下所示:

**Pixel_gpu;
HANDLE_ERROR(cudaMalloc(&Pixel_gpu,img_wd*img_ht*sizeof(pixel)));

pixel **Pixel = (pixel**)malloc((img_ht)*sizeof(pixel*));
for(int i=0;i<(img_ht);i++)
    Pixel[i]=(pixel*)malloc((img_wd)*sizeof(pixel));
内核启动:

cudaDeviceProp prop;
HANDLE_ERROR(cudaGetDeviceProperties(&prop, 0));


int thread_block=sqrt(prop.maxThreadsPerBlock);
dim3 DimGrid(ceil(img_wd/thread_block),ceil(img_ht/thread_block),1);
dim3 DimBlock(sqrt(prop.maxThreadsPerBlock),sqrt(prop.maxThreadsPerBlock),1);

//allocating gpu memory


pixel **Pixel_tmp_gpu, **Pixel_gpu;


HANDLE_ERROR(cudaMalloc(&Pixel_tmp_gpu,img_wd*img_ht*sizeof(pixel)));
HANDLE_ERROR(cudaMalloc(&Pixel_gpu,img_wd*img_ht*sizeof(pixel)));


float **kernel0_gpu, **kernel1_gpu;

HANDLE_ERROR(cudaMalloc(&kernel0_gpu,k*1*sizeof(float)));
HANDLE_ERROR(cudaMalloc(&kernel1_gpu,1*k*sizeof(float)));

cout<<"memory allocated"<<endl;

//copying needed data

HANDLE_ERROR(cudaMemcpy(Pixel_tmp_gpu,Pixel_tmp,img_wd*img_ht*sizeof(pixel),cudaMemcpyHostToDevice));
HANDLE_ERROR(cudaMemcpy(Pixel_gpu,Pixel,img_wd*img_ht*sizeof(pixel),cudaMemcpyHostToDevice));
HANDLE_ERROR(cudaMemcpy(kernel0_gpu,kernel0,k*1*sizeof(float),cudaMemcpyHostToDevice));
HANDLE_ERROR(cudaMemcpy(kernel1_gpu,kernel1,1*k*sizeof(float),cudaMemcpyHostToDevice));

cout<<"memory transfers done"<<endl;

vertical_conv<<<DimGrid,DimBlock>>>(Pixel_gpu, Pixel_tmp_gpu,img_wd, img_ht,kernel0_gpu,k);
time_t vertical_convolution=time(NULL);

cout<<" vertical_convolution time: "<<double(vertical_convolution - reading_file)<<"sec"<<endl;


horizontal_conv<<<DimGrid,DimBlock>>>(Pixel_tmp_gpu, Pixel_gpu, img_wd, img_ht, kernel1_gpu, k);
time_t horizontal_convolution=time(NULL);

cout<<" horizontal convolution time:" <<double(horizontal_convolution-vertical_convolution)<<" sec"<<endl;

pixel *Pixel_res = (pixel*)malloc(img_wd*img_ht*sizeof(pixel));

HANDLE_ERROR(cudaMemcpy(Pixel_res,Pixel_gpu,img_wd*img_ht*sizeof(pixel),cudaMemcpyDeviceToHost));
cudaDeviceProp道具;
句柄_错误(cudaGetDeviceProperties(&prop,0));
int thread_block=sqrt(属性maxThreadsPerBlock);
dim3 DimGrid(ceil(img\U wd/螺纹块),ceil(img\U ht/螺纹块),1);
dim3 DimBlock(sqrt(属性maxThreadsPerBlock),sqrt(属性maxThreadsPerBlock),1);
//分配gpu内存
像素**像素\u tmp\u gpu,**像素\u gpu;
句柄错误(cudamaloc(&Pixel_tmp_gpu,img_wd*img_ht*sizeof(Pixel));
句柄错误(cudaMalloc(&Pixel_gpu,img_wd*img_ht*sizeof(Pixel));
浮点**内核0\gpu,**内核1\gpu;
HANDLE_错误(cudamaloc(&kernel0_gpu,k*1*sizeof(float));
HANDLE_错误(cudamaloc(&kernel1_gpu,1*k*sizeof(float));

coutPixel\u gpu
是一个连续内存块,由
w*h
类型的
Pixel
元素组成。它的大小是

sizeOfDeviceMemory = img_wd * img_ht * sizeof(pixel)
sizeOfHostMemory = img_ht * sizeof(pixel*)
与此相反,CPU端的
Pixel
是一个“指针数组”:
Pixel
指针指向
h
类型的
Pixel*
元素。它的大小是

sizeOfDeviceMemory = img_wd * img_ht * sizeof(pixel)
sizeOfHostMemory = img_ht * sizeof(pixel*)
显然,这些大小是不同的,尝试将
sizeOfDeviceMemory
字节写入此指针会导致非法访问


通常,您还应将主机上的内存分配为一个连续块:

pixel* Pixel = (pixel*)malloc(img_wd * img_ht * sizeof(pixel));
然后可以使用已有的
cudaMemcpy
调用将内存复制到此指针



如果主机上有一个
像素*
不适合您,并且您迫切需要一个
像素**
(例如,将其传递给其他函数),那么您可以像以前一样创建一个“指针数组”,但不为每一行分配新内存,而是让每个指针指向一行中的一行,连续像素块

我尝试将主机内存分配为一个块,但仍然得到相同的错误。非法内存访问错误可能发生在内核中。你还没有表现出一点,所以人们只是在猜测。Marco13指出的当然是代码中的一个缺陷,但是由于您没有展示完整的代码,没有人能告诉您所有的问题可能是什么。如果您以双指针(
**
)的形式传递
Pixel\gpu
,那么您的内核几乎肯定会有问题看起来也有点奇怪。它应该声明为
pixel*pixel\gpu
。然后,您可以使用
cudamaloc(&Pixel\gpu,…)
分配它,并使用
cudaMemcpy(…,Pixel\gpu,…)
。如何声明
Pixel\gpu
?正如Robert指出的那样,由于异步的性质,很难猜测现在可能出现了什么错误。对于调试,您可以在
cudaMemcpy
调用之前和之后添加
cudaDeviceSynchronize()
,以确保此调用是问题的根源。您不能将平面、单指针(
*
)分配传递给内核,并期望将其用作双指针(
***
)数组。在主机和设备之间传递双指针数组需要特殊编码,而您缺少这种编码。这是一个经常被误解的话题,因此有很多问题在讨论它。您只需搜索
cuda 2D array
cuda
标记信息页面链接,即可找到讨论如何处理2D array的典型问题。我相信这仍然不是一个好消息。它应该是其他人可以编译和运行的东西,而无需大量的组装工作。如果您只需将所有内容转换为具有模拟2D访问的单指针数组(即
[row*width+col]
),您的工作将大大简化。我将研究cuda上的2D数组处理,感谢您的建议。
sizeOfHostMemory = img_ht * sizeof(pixel*)
pixel* Pixel = (pixel*)malloc(img_wd * img_ht * sizeof(pixel));