CUDA:在GPU代码并行执行的同时运行CPU代码

3

我有一个程序,在GPU上进行一系列计算,然后在CPU上对这些结果进行内存操作,接着取下一批数据,重复以上步骤。现在如果我能够在CPU处理内存操作的同时开始处理第二批数据,那么程序将会更快。如何实现这个功能呢?


“内存操作” - 您是指将数据传输到/从卡中,还是与卡无关的某些操作?您只需要一个线程来管理卡,然后就可以随意使用CPU的其余部分了吗? - Rup
嗯,两者都有吧。我将结果传输到主机上,然后对数据进行处理,所以它并不是完全独立的。 - foges
2个回答

5
所有的CUDA内核调用(例如function<<<blocks, threads>>>())都是异步的,它们会立即返回控制权给调用主机线程。因此,只需在内核调用后放置CPU工作,就可以始终并行执行CPU工作和GPU工作。
如果您还需要同时从GPU传输数据到CPU,则需要一个将deviceOverlap字段设置为true的GPU(使用cudaGetDeviceProperties()进行检查),并且您需要在单独的CUDA流中使用cudaMemcpyAsync()
NVIDIA CUDA SDK中有示例来演示这个功能,例如“simpleStreams”和“asyncAPI”示例。

好的,谢谢你告诉我这个。那么如果我有以下代码:<<<grid,block>>myCUDAfunc(); cudaMemcpy();在 cudaMemcpy 开始复制结果之前,我怎样知道 myCUDAfunc() 已经完成了呢? - foges
有一些同步函数,如cudaDeviceSynchronize、cudaStreamSynchronize和cudaEventSynchronize。这些函数很容易使用,但你应该查看nVidia的CUDA C编程指南,该指南可在CUDA下载页面上获得。它只有187页,为您提供了与CUDA工作所需的重要信息。 - jmsu
@user810045,明确一下:CUDA有“流”的概念。流是按照发出顺序执行的CUDA运行时API命令序列。如果您不向内核指定流标识符(<<<>>>中的可选第4个参数),它将在默认流中运行,该流始终与其他默认流CUDA命令同步。因此,如果在内核之后调用,则cudaMemcpy也是同步的,将始终在内核之后执行。如果要进行异步复制,则必须使用cudaMemcpyAsync,并需要一个流标识符参数。 - harrism

2
基本思路可以像这样:
  • 在GPU上进行第一批计算

  • 进入循环:{

    将结果从设备内存复制到主机内存

    在GPU中执行下一批计算(核的启动是异步的,控制立即返回到CPU)

    处理上一次迭代的结果

    }

  • 从设备内存中复制最后一次迭代的结果到主机内存

  • 处理最后一次迭代的结果
您可以使用cudaMemcpyAsync、cudaStream和cudaEvent来获得更精细的控制CPU和GPU之间的异步工作。
正如@harrism所说,您需要使设备支持deviceOverlap以同时进行内存传输和核函数执行,但即使没有该选项,您仍然可以异步地执行与CPU上的其他计算。
编辑:deviceOverlap已经被弃用了,现在应该使用asyncEngineCount属性。

是的,jmsu,那正是我想做的。很高兴知道那会起作用 :) - foges

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接