cuda学习笔记五 cuda stream及 unified memory使用问题

      cuda通过多个stream可以降低host到Device的数据传输延时,这个没问题。但是通过stream传输就需要通过cudaHostAlloc等重新分配内存,那么这时候就有一个问题,就是这个内存需要重新赋值,问题就在于很有可能这段重新赋值的时间会超出接受的范围。如果用cudaMemcpy就可以直接用原始数据往Device上传输了。

      本人在实际项目中遇到的问题,印象非常深刻,测试环境是NVIDIA TX2嵌入式板子。因为数据量比较大,原始程序测试通过cudaMemcpy拷贝数据需要20~40ms,那么很自然就想到用stream。但是现在通过stream,异步拷贝的时间确实少了,但是时间都消耗在了如下所示的第三步,也就是Host端内存的初始化上了,而且时间比cudaMemcpy还要多。
cudaHostAlloc((void **)&h_a, sizeof(float)*N, cudaHostAllocDefault);
cudaMalloc((void **)&d_a, sizeof(float)*N);
/**step3**/
for(int i=0; i<N; i++)
{
        h_a[i] = src_a[i];
}
/**step3**/

cudaMemcpyAsync(d_a, h_a, sizeof(float)*N/nstreams, cudaMemcpyHostToDevice, stream[i]);

可以说为了屏蔽这段cudaMemcpy数据传输时间,各种方法都尝试了,最终都是不尽如人意。后来求助于gpu world和nvidia的开发者论坛。在屠戮人神的提示下,

(1)如果确定是cudaMemcpy本身消耗了20-40ms,而不是CUDA Runtime初始化之类的因素。可以考虑在TX2上使用managed memory (Unified memory).  一定情况下可以规避传输。因为你的TX2本身并不存在单独的显存或者内存,只有实质的一体的存储器,所以常规情况下的cudaMemcpy实质上是在做无用功。

(2)可以对第二次后或者以后的cudaMemcpy进行计时以测试到较为更实际的传输时间(不是说你之前的数据是告诉我是错误的, 只是为了以防万一)。确定时间正确的话可以无视这条,直接考虑上面(1)条。

(3)TX2上使用managed memory不建议同时进行CPU和GPU访问。

我继续做了相关测试。其实我之前想到过使用cudaMallocManaged,但是当时传的参数是cudaMemAttachGlobal,导致cpu端初始化的时候存在同样的问题。在cpu端初始化时用cudaMallocManaged加cudaMemAttachHost参数,然后cpu端计算对这段内存赋值,在gpu核函数调用之前用cudaStreamAttachMemAsync( stream, gPointI+iRation*i, sizeof(float)*iRation, cudaMemAttachGlobal );将这段内存转换为gpu device可以访问的。效果确实不错。

猜你喜欢

转载自blog.csdn.net/lucky_greenegg/article/details/81913253