我们有一个多 GPU 框架(在 Windows 上),可以在其中指定“作业”(还指定它们应在哪个 GPU 上完成),然后在特定 GPU 上执行。目前,我们的方法是在启动框架时为每个 GPU 创建一个“工作线程”,然后等待作业被处理。具体来说,我们使用来自https://devtalk.nvidia.com/search/more/sitecommentsearch/GPUworker/的“GPUWorker”类
到目前为止它运行良好,但有一些严重的与性能相关的缺点:
在我们的框架中,一个特定的 GPU 在“作业”的整个时间内都被锁定,即使 GPU 实际上仅在 50% 的作业时间内使用。请注意,作业具有非常粗略的粒度,例如“进行光流计算”,这可能需要 50 - 100 毫秒。
不能指定不锁定 GPU 的“异步”作业(例如异步主机设备副本)
所以我现在正在考虑针对该问题的“更好”策略。我的想法如下:对于每个“启动”的新作业,我创建一个新的“临时”CPU 线程。CPU 线程然后设置要在其上完成工作的 GPU 的设备号(通过“cudaSetDevice”)。我想此时也(对我透明地)创建了一个 Cuda 上下文。在看到正确的设备后,作业的“doWork”功能由 CPU 线程执行。取决于作业是同步完成还是异步完成,是否完成了“加入”(等待 CPU 线程完成)。
我现在有几个问题:
这是一个“好”的策略,还是有人知道如何处理这个更好的方法?当然它必须是线程安全的策略。
在我提出的策略中,创建新 CPU 线程和(隐藏)创建 Cuda 上下文的典型开销(以毫秒为单位)是多少?此外,如果 Cuda 上下文的创建很重要,有没有办法(例如使用 cuda 设备 api 和某种“上下文迁移”)来减少这种开销?