我已使用 cudaMalloc 在设备上分配内存并将其传递给内核函数。是否可以在内核完成执行之前从主机访问该内存?
4 回答
我能想到的在内核仍在执行时启动 memcpy 的唯一方法是在与内核不同的流中提交异步 memcpy。(如果您将默认 API 用于内核启动或异步 memcpy,NULL 流将强制这两个操作被序列化。)
但是由于无法将内核的执行与流同步,因此该代码将受到竞争条件的影响。即复制引擎可能会从尚未被内核写入的内存中提取。
提到映射固定内存的人很喜欢:如果内核写入映射固定内存,它实际上是在完成处理数据时将数据“复制”到主机内存。这个习惯用法很好,只要内核不会再次接触数据。
这是可能的,但不能保证您以这种方式检索的内存内容,因为您不知道内核的进度是什么。
您想要实现的是重叠数据传输和执行。这可以通过使用流来实现。您创建多个 CUDA 流,并在每个流中排队内核执行和设备到主机 cudaMemcpy。例如,将填充位置“0”的内核和 cudaMemcpy 从该位置返回到主机流 0,将位置填充“1”的内核和 cudaMemcpy 从“1”放入流 1,等等。然后会发生什么GPU将从“0”复制并执行“1”重叠。检查 CUDA 文档,它记录在某处(我认为在最佳实践指南中)。
无论内核是否正在运行,您都无法直接从主机访问 GPU 内存。
如果您正在谈论在内核完成写入之前将该内存复制回主机,那么答案取决于您设备的计算能力。但是除了最古老的芯片之外,所有芯片都可以在内核运行时执行数据传输。
不过,您似乎不太可能想要复制仍在由内核更新的内存。您将获得部分完成数据的一些随机快照。相反,您可能希望在设备上有两个缓冲区的情况下进行设置。您可以在 GPU 处理另一个缓冲区时复制其中一个缓冲区。
更新:
根据您的说明,我认为您可以获得的最接近的是使用映射页面锁定的主机内存,也称为零拷贝内存。使用这种方法,值在内核写入时被复制到主机。无法查询内核以查看它执行了多少工作,因此我认为您必须反复扫描内存以查找新写入的值。有关更多信息,请参阅 CUDA 编程指南 v4.2 中的第 3.2.4.3 节,映射内存。
我不会推荐这个。除非您有一些非常不寻常的要求,否则可能会有更好的方法来完成您的任务。
当您启动内核时,它是一个异步(非阻塞)调用。接下来调用 cudaMemcpy 将阻塞,直到内核完成。
如果您希望将结果用于调试目的,您可以使用 cudaDebugging 来单步执行内核并检查内存。
对于小的结果检查,您还可以在内核代码中使用 printf()。
或者,如果您对该特定结果感兴趣,则仅运行大小为 (1,1) 的线程块。