版主您好
//滤波,RGB转Lab
GaussFilterAndRGBToLabkernel<<<Dimgrid,Dimblock>>>(dev_img3f,width,height,dev_tImg);
getLastCudaError(“call GaussFilterkernel faile”);
//求取均值
BlockMeankernel<<<Dimgrid,Dimblock>>>(dev_tImg,width,height,dev_block_mean);//per block mean value
getLastCudaError(“call BlockMeankernel fail”);
Meankernel<<<1,512>>>(dev_block_mean,widthheight,Grid_wGrid_h,dev_mean);//total mean value
getLastCudaError(“call Meankernel fail”);
//求方差
SquaresKernel<<<Dimgrid,Dimblock>>>(dev_tImg,dev_mean,width,height);
getLastCudaError(“SquaresKernel Kernel execution failed”);
我使用了多个kernel函数,第一个kernel函数的结果存在dev_tImg中,第二第三个kernel函数式求取dev_tImg中的均值,第三个又将dev_tImg作为输入进行处理,请问这样一起做会不会影响dev_tImg的值,毕竟是在显存中处理,结果会不会受影响
LZ您好:
请问您为何认定“在显存中处理”就会导致“出问题”?
对显存不太熟悉,已经分配好的显存是不是如果在中期不进行修改和释放,只有到最后释放显存空间是这部分数据才不可以用呢?
因为我是使用了多个kernel函数,担心会不会一个kernel函数运行结束,这部分数据就会销毁
还有请问连个kernel函数之间可不可以夹着一个C编的函数,将这个C函数的计算结果传入第二个kernel函数中,这其中只在第一个kernel函数前进行,第二个kernel之后进行数据拷贝。
也就是说可不可以在内存和显存上交叉着运算
[
LZ您好:
请问一段申请成功的缓冲区,没有主动释放,凭什么会自己失效?
[
请您给出您的代码摘要或者伪码示意。我未能看明白您的叙述。
好的,因为我这么做最后的结果出现了问题,我详细的说一下
就是说,我首先对一幅图像进行高斯滤波处理,RGB转灰度,后求取其统计直方图,再根据某一算法对直方图处理,求出一个阈值,最后根据这个阈值进行二值化
对图像的高斯滤波,求取直方图是用的CUDA代码,求取这个阈值使用的是C代码,(因为直方图就256个数据未使用CUDA程序)最后二值化用的是CUDA代码,可不可以两个kernel函数之间夹着一个C函数,再将这个C函数的结果作为最后一个kernel函数的输入
代码如下
kernel函数 GaussFilterRGBToGraykernel<<<Dimgrid,Dimblock>>>(dev_img3f,width,height,dev_tImg);
getLastCudaError(“call GaussFilterkernel faile”);
Histkernel<<<Dimgrid,Dimblock>>>(dev_tImg,width,height,dev_Hist);
getLastCudaError(“Histkernel Kernel execution failed”);
dev_img3f是输入的RGB图像
dev_tImg输出的灰度图像
dev_Hist输出的直方图
C代码求阈值
thresh(dev_Hist,thresh);
阈值为threshold = i;
二值化kernel函数
binkernel<<<Dimgrid,Dimblock>>>(dev_tImg,width,height,thresh,dev_bin_Img);
dev_bin_Img最后的二值化图像
LZ您好:
在回答您的具体问题之前,我认为有必要先说两点关于方法论的内容。
1:如果一个流程的最后结果是错误的,那么通行的解决方法是逐步骤调试,先保证每个环节都正常运行了,没有挂掉,没有越界什么的;再观察每步的结果,检查有没有逻辑问题。这样逐一排查,才能解决问题。而不是仅凭主观去猜测问题所在,主观猜测可以提供思路,但需要客观实测的结果来支持才可以。
2:两个kernel之间当然可以插入一个普通的C函数,以及该函数当然可以做一些辅助的处理工作,配合适当的数据交换机制,host端结果当然可以被kernel继续使用的。但可以使用不代表您的实现是正确的,您没有检查自己实现的正确与否,而是始终质疑这个机制是否可行,这是不合适的,也是不解决问题的。
具体到您的问题,根据您提供的信息加上我的脑补(因为您的函数没有给出定义,而只是给出了调用,我无法得知函数内部实现以及参数类型,所以只能加上脑补)。
OK,假定您前两个kernel调用时参数是正确的,调用是成功的,那么您的dev_Hist这个参数应该是一个指针,它自身是存储在host端的,它指向的地址则是device端存储空间的地址。
在Histkernel执行之后,您调用了host端的C函数thresh(),并使用了dev_Hist作为参数。
根据您的叙述,这只是一个直接的使用,而不是您对cuda提供的API函数的封装。
那么您在host端的代码里面直接使用一个指向deice端的地址,这地址还是有效的么?您的这个函数难道不会因为指针指飞而挂掉么?以及即便运气足够好,这段地址可以读取,您的函数能读到正确的数据么?
以及,如果您调试过您的这个host端的函数的话,这一切应该都是显然的,您可以立即发现这里有问题。
(反之,如果dev_Hist是指向host端的存储空间(虽然这样一来这个命名就显得十分奇葩了),那么您前面的第二个kernel就会因为参数问题而直接挂掉了。也就是说您这里的问题逻辑上是有固有矛盾的。)
此外,如果您的thresh(dev_Hist,thresh);调用是为了将结果写入thresh这个变量,以便后面作为kernel的参数使用,那么您这样用thresh变量作为参数传个值进去是无法改变thresh变量自身的,您需要传指针进去才行。
大致如上,在介绍一般方法之外,还在您提供的信息的基础上,为您指出了一个必然BUG和一个可能BUG。
以及并不能保证没有其他的问题,因为您提供的信息有限。
祝您DEBUG顺利~
以及补充说明一些通行的做法:
1:如果在kernel执行之间需要插入一个普通的C函数做一些辅助处理,而同时这个函数又需要之前kernel的处理结果作为输入。那么一般需要先将这个host函数所有依赖的device端数据copy回host端,然后这个函数使用host端的数据副本。如果这个host端的函数的结果是一个或者数个变量,那么可以通过kernel参数的方式,传递给后面需要使用的kernel。如果数据较多,依然需要将结果复制回device端。
也就是说,您需要理解这里的数据传递机制。
2:在前述机制下,您一般需要至少一次cudaMemcpy(),由于数据复制带来的开销可能会完全抵消CPU处理一些问题带来的好处。而此时,推荐改写为一个kernel实现,虽然这个计算属性和规模可能在GPU上效率很差,但是因为减少了至少一次数据复制,或许总体上还是划算的。
所以一般建议尽量在device端折腾,尽量少倒腾数据。
以及具体的实现方案,请您根据您的实际情况,评估后酌情选择。
祝您好运~