多个GPU上的CUDA上下文,流和事件

时间:2012-03-08 02:29:27

标签: cuda pycuda

TL; DR版本:“使用Python / PyCUDA对多个GPU进行内核调用的最佳方法是什么,以便CPU和GPU可以并行工作?”并且“我不可能是第一个问这个的人;我应该读什么?”

完整版:

我想知道在具有多个GPU的系统上使用CUDA的应用程序中设计上下文等的最佳方法。我一直在努力寻找能够讨论上下文重用与娱乐时间的指导原则的文献,但到目前为止还没有找到任何概述最佳实践,经验法则等的文献。

我们需要做的一般概述是:

  • 请求进入中央流程。
  • 该流程分叉处理单个请求。
  • 数据从DB加载(相对昂贵)。

根据请求(数十个)重复以下任意次数:

  • 一些快速内核调用来计算后来内核所需的数据。
  • 一个缓慢的内核调用(10秒)。

最后:

  • 内核调用的结果在CPU上收集和处理,然后存储。

目前,每个内核调用都会创建然后销毁一个看起来很浪费的上下文。安装程序每个上下文和内核负载大约需要0.1秒,虽然这不是很大,但它阻止我们将其他更快的任务移到GPU上。

我正在尝试找出管理上下文等的最佳方法,以便我们可以有效地使用机器。我认为在单gpu的情况下,它相对简单:

  • 在开始任何GPU工作之前创建一个上下文。
  • 启动第一组数据的内核。
  • 在系列中的最终内核调用之后记录一个事件。
  • 准备CPU上的第二组数据,而第一组数据是在GPU上进行计算。
  • 启动第二组,重复。
  • 在收集结果并存储之前,确保每个事件都已同步。

假设正确使用重叠的内存副本,这似乎应该可以解决问题。

但是,我不确定在想要循环处理多个GPU中的每个项目时,我应该做些什么。

主机程序是Python 2.7,使用PyCUDA访问GPU。目前它不是多线程的,虽然我宁愿保持这种方式(“现在你有两个问题”等),如果答案意味着线程,它意味着线程。类似地,能够在阻塞数据时在主线程中调用event.synchronize()会很好,但是对于我们的需求,有效地使用硬件更为重要。由于我们可能一次为多个请求提供服务,因此在此过程不使用GPU时让其他进程使用GPU非常重要。

我认为我们没有任何明确的理由使用独占计算模式(即我们没有用一个工作项填满卡的内存),所以我不认为涉及长的解决方案不合时宜的情况已不在考虑之列。

请注意,只要他们详细了解了为什么,而不仅仅是API,那么以其他内容链接形式的答案完全可以接受(鼓励,甚至鼓励)。谢谢你的阅读!

1 个答案:

答案 0 :(得分:1)

警告:我还不是PyCUDA用户。

使用CUDA 4.0+,您甚至不需要每个GPU的显式上下文。您可以在执行每个设备之前调用cudaSetDevice(或等效的PyCUDA)(cudaMalloccudaMemcpy,启动内核等。)

如果需要在GPU之间进行同步,则需要创建流和/或事件,并使用cudaEventSynchronize(或等效的PyCUDA)。您甚至可以让一个流等待插入另一个流中的事件来执行复杂的依赖。

所以我怀疑今天的答案比talonmies的优秀pre-CUDA-4.0 answer要简单得多。

您可能还会发现this answer有用。

(重新)OP编辑:根据我的理解,PyCUDA支持4.0之前的CUDA版本,因此仍然使用旧的API /语义(驱动程序API?),所以talonmies的答案仍然相关。