3

背景:

我编写了一个对一系列符号执行处理的 CUDA 程序。该程序并行处理所有符号序列,并规定所有序列具有相同的长度。我将我的数据分组,每组完全由相同长度的序列组成。该程序一次处理 1 个组。

问题:

我在具有 4 个 GPU 的 Linux 机器上运行我的代码,并希望通过运行我的程序的 4 个实例(每个 GPU 1 个)来利用所有 4 个 GPU。是否可以让程序选择另一个 CUDA 应用程序未使用的 GPU 来运行?当程序在具有更多或更少数量的 GPU 的不同硬件上运行时,我不想硬编码任何会导致问题的东西。

4

2 回答 2

5

环境变量 是你的CUDA_VISIBLE_DEVICES朋友。

我假设您打开的终端与 GPU 的数量一样多。假设您的应用程序被调用myexe

然后在一个终端中,您可以执行以下操作:

CUDA_VISIBLE_DEVICES="0" ./myexe

在下一个终端:

CUDA_VISIBLE_DEVICES="1" ./myexe

等等。

然后第一个实例将在 CUDA 枚举的第一个 GPU 上运行。第二个实例将(仅)在第二个 GPU 上运行,依此类推。

假设 bash,对于给定的终端会话,您可以通过导出变量来使其“永久”:

export CUDA_VISIBLE_DEVICES="2"

此后,在该会话中运行的所有 CUDA 应用程序将仅观察第三个枚举 GPU(枚举从 0 开始),并且它们将观察该 GPU ,就好像它是其会话中的设备 0。

这意味着您不必为此方法对应用程序进行任何更改,假设您的应用程序使用默认 GPU 或 GPU 0。

您还可以扩展它以使多个 GPU 可用,例如:

export CUDA_VISIBLE_DEVICES="2,4"

意味着通常枚举为 2 和 4 的 GPU 现在将是该会话中唯一“可见”的 GPU,它们将枚举为 0 和 1。

在我看来,上述方法是最简单的。选择“未使用”的 GPU 是有问题的,因为:

  1. 我们需要一个“使用中”的定义
  2. 在特定时刻使用的 GPU 在此之后可能不会立即使用
  3. 最重要的是,未“使用中”的 GPU 可能会异步变为“使用中”,这意味着您将面临竞争条件。

因此,最好的建议 (IMO) 是明确管理 GPU。否则,您需要某种形式的作业调度程序(在这个问题的范围之外,IMO)能够查询未使用的 GPU 并在另一个应用程序尝试这样做之前以有序的方式“保留”一个。

于 2015-06-18T20:42:53.543 回答
0

有一种更好(更自动化)的方式,我们在 PIConGPU 中使用,它在巨大(和不同的)集群上运行。在此处查看实现:https ://github.com/ComputationalRadiationPhysics/picongpu/blob/909b55ee24a7dcfae8824a22b25c5aef6bd098de/src/libPMacc/include/Environment.hpp#L169

基本上:调用cudaGetDeviceCount以获取 GPU 的数量,对其进行迭代并调用cudaSetDevice以将其设置为当前设备并检查是否有效。由于 CUDA 中的一些错误使 setDevice 成功,但由于设备实际在使用中,所有后来的调用都失败了,因此此检查可能涉及测试创建流。注意:您可能需要将 GPU 设置为独占模式,以便 GPU 只能由一个进程使用。如果您没有足够的一个“批次”数据,您可能想要相反的结果:多进程将工作提交给一个 GPU。所以根据你的需要调整。

其他想法是:启动一个 MPI 应用程序,每个 rank 的进程数与 GPU 的数量相同,并使用与本地 rank 号相同的设备号。这也有助于像您这样具有不同数据集要分发的应用程序。所以你可以让 MPI rank 0 处理 length1-data 和 MPI rank 1 处理 length2-data 等。

于 2016-10-07T09:18:11.187 回答