c++ - 混合隐式和显式 CUDA 流
问题描述
我有一些 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 不那么幸运吗?
解决方案
不要依赖隐式/默认流和操作及其同步行为的拐杖。对于您的第一个“Hello world”级程序 - 这可能很方便,但正如您自己所注意到的,您必须成为 API 律师或通灵者才能猜测在某些复杂场景中究竟会发生什么。
只需确保您在内核中使用的每个缓冲区都是:
由同一命令队列上的先前操作填充或
2.1 如果它是一个输入缓冲区 - 有一个事件对确保在内核启动另一个流之前发生任何影响缓冲区的事情,并且2.2 如果它是一个输出缓冲区 - 有一个事件对确保内核在输出缓冲区用于其他地方之前执行
推荐阅读
- c# - EF 在测试之间删除数据库
- ruby-on-rails - 如何在与多种类型的用户的多态关联中创建记录
- javascript - 按钮在由 JavaScript 操作的 HTML 中不起作用
- javascript - JavaScript - 从消息数组中获取天数,不包括没有消息的天数
- json - 如何在 JsonConvert 期间剥离名称空间和 xml 版本
- php - 将 Amphp 与用户定义的函数并行使用时出错
- sqlite - 如何从一个表中删除以前属于另一个表的行?
- javascript - Three.js 通过鼠标单击切换对象位置
- json - 读取 json col 和直接数据值列
- python - 光栅双序列相关