在多 GPU 系统中,给定 PCI 供应商、设备和总线 ID,如何将 OpenCL 设备与特定 GPU 匹配?

Posted

技术标签:

【中文标题】在多 GPU 系统中,给定 PCI 供应商、设备和总线 ID,如何将 OpenCL 设备与特定 GPU 匹配?【英文标题】:How to match OpenCL devices with a specific GPU given PCI vendor, device and bus IDs in a multi-GPU system? 【发布时间】:2011-11-08 18:08:05 【问题描述】:

我希望能够在由 PCI ID 标识的多 GPU 系统上将 OpenCL 设备与系统中的 GPU 进行匹配。

例如,如果我有一个带有多个 GPU 的系统,可能来自不同的供应商,我可以通过枚举 PCI 总线来列出设备。这给了我 PCI 供应商、设备和总线 ID。如果我根据某些选择标准选择这些 (GPU) PCI 设备之一用于 OpenCL 计算,如何将其与 OpenCL 设备匹配?

我可以使用 clGetDeviceIDs() 在 OpenCL 中枚举 GPU 设备,但是没有明显的方法可以将 OpenCL 设备与 PCI 设备匹配。 OpenCL 函数 clGetDeviceInfo() 提供对 PCI 供应商 ID 和设备名称的访问,但不提供对 PCI 设备或总线 ID 的访问。我可以尝试将 PCI 设备名称与 OpenCL 设备名称进行匹配,但您可能拥有多个相同类型的设备,而且名称并不总是相同。

为什么这是必要的?假设我知道程序 X 在 GPU A 上运行 CUDA 或其他东西。我想避免也将 GPU A 用于 OpenCL 操作,所以我选择 GPU B。然后我需要确定哪个 OpenCL 设备是 GPU A,哪个是 GPU B. PCI ID 似乎是识别 GPU 设备的唯一一致且跨平台的方式。

顺便说一句,CUDA API 确实为您提供了 PCI、总线和插槽 ID(CU_DEVICE_ATTRIBUTE_PCI_BUS_ID、CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID),但 CUDA 仅适用于 NVidia 设备。

理想情况下,我需要使用 C 或 C++ 的解决方案。

【问题讨论】:

规范说 CL_DEVICE_VENDOR_ID “可能是 PCIe ID”。如果这不能得到你想要的,那么我认为规范中没有任何东西可以。不过,仍然不确定为什么需要这个。听起来像是过早的优化。 @vocaro:是的,我可以获得供应商 ID。我认为你没有理解这个问题。 您说您想知道 PCI 设备 ID 以避免与可能正在使用特定 PCI 设备 ID 的另一个进程发生争用。我想知道您如何知道正在使用哪些 PCI 设备?我猜你没有为此使用 OpenCL? 最近它添加了一个新的 Khronos 扩展,可以在这里提供帮助:khronos.org/registry/OpenCL/specs/3.0-unified/html/… 【参考方案1】:

这样做的方法是使用两个特定于供应商的扩展。对于 AMD,您必须使用CL_DEVICE_TOPOLOGY_AMD,它适用于 Windows 和 Linux,并将返回 PCIe 总线 ID,这是 GPU 独有的。在 NVIDIA 上,查询设备以获取 CL_DEVICE_PCI_BUS_ID_NV。另见:https://anteru.net/2014/08/01/2483/

【讨论】:

我还没有尝试过,但这似乎是正确的答案。太棒了,感谢您的回答和近 3 年的等待。 抱歉拖了这么久,我之前没有遇到问题 :) 感谢您将此标记为正确答案。 CL_DEVICE_PCI_BUS_ID_NV 是否适用于 Windows 上的 Nvidia 驱动程序?我正在 PyOpenCL 中尝试此操作,但不断收到错误提示它是无效值。 应该做,不知道那里发生了什么。很遗憾,我现在无法检查。【参考方案2】:

不幸的是,由于 openCL 的抽象性质,您正在寻找的答案并不漂亮。

我发现可靠地做到这一点的唯一方法是在 openCL 中将要求苛刻的工作负载分配给平台 + 设备 ID,然后通过 AMD 的 ADL 和 Nvidia 的 NVML 等工具监控进程使用情况。即使是像 cgminer 这样的成熟应用程序也有这个问题,并且经常将 openCL 工作负载与卡指标混为一谈,以至于他们分配配置变量来手动更正它(“gpu-map”)。

我希望现在有一个更好的答案,因为通过 openCL 知道端点后面的设备会很棒!这可能会在未来发生变化,正如 arsenm 指出的那样,AMD 正在努力将此层添加到 openCL。

【讨论】:

【参考方案3】:

似乎 Anteru 的答案是正确的,但前提是您运行的是 linux/mac。 经过我做的一些测试,Windows 似乎无法识别这些供应商特定的扩展。 (我已经在 Geforce GTX Titan 和 ATI Radeon R9 上测试过)

我对您的解决方案是使用带有“CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR”参数的 clGetGLContextInfoKHR() 函数(自 openCL 规范 1.1 起可用),这将确保您获得与执行渲染的同一 GPU 匹配的 openCL 设备 ID。

没错,这不会为您提供物理总线插槽,但可以确保渲染的 GPU 与计算的 GPU 相同!

另外,假设一个人使用 Nvidia Quadro 卡,那么他可以使用 wgl_nv_gpu_affinity 来确保 openGL 访问特定的 GPU,然后使用 GL 上下文并从中获取 openCL 设备 ID。

【讨论】:

【参考方案4】:

最新的 AMD 版本在 Linux 上具有 cl_device_topology_amd 扩展,它将 CL_DEVICE_TOPOLOGY_AMD 选项添加到 clGetDeviceInfo(),但这是一个非常狭窄的解决方案。

【讨论】:

是的,还需要覆盖 NVidia 卡。【参考方案5】:

我为此开发了一个库:防止 OpenCL 模拟相互踩踏。

你会在这里找到它:https://github.com/nbigaouette/oclutils/

它首先枚举机器上存在的每个平台的所有平台和每个设备。您选择想要的平台,它将选择可用的最佳设备。我在带有 3 个 nvidia 卡的工作站上使用它:两个 GTX 580 用于 OpenCL 计算,一个 GT 210 用于显示。同时运行两个模拟将分别在两个 GTX 上运行。无需干预。

还有一个很好的类可以保持两个缓冲区同步:一个在主机上,一个在设备上。调用 OpenCL_Array::Host_to_Device() 和 OpenCL_Array::Device_to_Host() 使来回传输变得简单。

它适用于这些平台:

nvidia(仅限 GPU) amd(CPU 和/或 GPU) 英特尔(仅限 CPU) 苹果(CPU 和/或 GPU)

请注意,它不会让您选择使用哪个设备,而是为您选择一个。如果一个程序的两个实例使用该库,它们会知道它并且不会在同一设备上运行(当然,如果你也有的话)。目前,它也无法检测视频卡是否用于显示。但至少这是一个开始!

【讨论】:

据我了解,您的回答并未解决将 PCI 设备 ID 与 OpenCL 计算设备匹配的问题。你正在解决一个相关的问题,但它对我需要的没有帮助。如果我错了,请解释。请记住,我还希望能够使用 CUDA 并仍然跟踪哪个设备是哪个。

以上是关于在多 GPU 系统中,给定 PCI 供应商、设备和总线 ID,如何将 OpenCL 设备与特定 GPU 匹配?的主要内容,如果未能解决你的问题,请参考以下文章

2-GPU 卡上的 PCI-e 通道分配?

linux中lspci命令的作用是啥?

如何在 Linux 上获取连接到 gpu 的显示器数量?

os.environ

什么是PCI—E接口

PCI 设备详解一