我有一些 CUDA 8.0 代码(编辑:我继承的,不是我写的),基本上是这样的:
cudaMemcpy(devInputData, ..., cudaMemcpyHostToDevice);
kernelThings<<<GRIDS, BLOCKS, 0, myStream>>>(devInputData);
cudaDeviceSynchronize();
cudaMemcpy()
在没有流的情况下同步工作,因此据我所知,此代码是正确的。
如果我使用 CUDA_API_PER_THREAD_DEFAULT_STREAM
编译,这段代码还安全吗?我认为不,cudaMemcpy()
现在异步发生,因此内核有可能在 cudaMemcpy()
完成之前启动。但是,查看 Nsight
分析器,我发现没有重叠 - 从文字上我看到:
[Memcpy HtoD]
[kernelThings]
两个函数之间有 16 微秒的间隔。此行为在应用程序中多次重复。
然而,我接下来删除了 cudaDeviceSynchronize()
,重新运行 Nsight
,发现它们现在重叠了:
[Memcpy HtoD]
[kernelThings]
内核现在在 cudaMemcpy
完成前 10 微秒启动。
显然,正确的解决方法是使用带有 cudaMemcpyAsync()
的流:
cudaMemcpyAsync(devInputData, ..., cudaMemcpyHostToDevice, myStream);
但是,我的问题是为什么我在使用 cudaDeviceSynchronize()
时没有看到进程重叠?一个简单的答案是,我可能没有那么幸运,使用不同版本的 CUDA 或 GPU?
答案 0 :(得分:-1)
不要依赖隐式/默认流和操作及其同步行为的拐杖。对于您的第一个“Hello world”级别的程序 - 这可能很方便,但正如您自己所注意到的,您必须成为 API 律师或通灵者才能猜测在某些复杂场景中究竟会发生什么。
只需确保您在内核中使用的每个缓冲区是:
由同一命令队列上的先前操作填充或
2.2 如果它是一个输出缓冲区 - 有一个事件对,确保在输出缓冲区在其他地方使用之前执行内核