是否可以在多 GPU 机器上执行 CUDA 程序的多个实例?
Is it possible to execute multiple instances of a CUDA program on a multi-GPU machine?
背景:
我编写了一个 CUDA 程序,可以对符号序列执行处理。该程序并行处理所有符号序列,并规定所有序列的长度相同。我正在将我的数据分组,每组完全由相同长度的序列组成。程序一次处理1组。
问题:
我运行在一台有 4 个 GPU 的 Linux 机器上使用我的代码,我想通过 运行我的程序的 4 个实例(每个 GPU 一个)来利用所有 4 个 GPU ).是否可以让程序 select 一个未被另一个 CUDA 应用程序使用的 GPU 打开 运行?当程序在具有更多或更少 GPU 数量的不同硬件上 运行 时,我不想硬编码任何会导致问题的东西。
environment variable CUDA_VISIBLE_DEVICES
是你的朋友。
我假设您打开的终端数量与 GPU 数量一样多。假设您的应用程序名为 myexe
然后在一个终端中,你可以这样做:
CUDA_VISIBLE_DEVICES="0" ./myexe
在下一个终端:
CUDA_VISIBLE_DEVICES="1" ./myexe
等等。
然后第一个实例将 运行 在 CUDA 枚举的第一个 GPU 上。第二个实例将 运行 在第二个 GPU 上(仅),依此类推。
假设 bash,对于给定的终端会话,您可以通过导出变量来实现此 "permanent":
export CUDA_VISIBLE_DEVICES="2"
此后,该会话中的所有 CUDA 应用程序 运行 将仅观察第三个枚举的 GPU(枚举从 0 开始),并且它们将观察那个 GPU ,就好像它是设备 0 在他们的会话中。
这意味着您无需为此方法对您的应用程序进行任何更改,假设您的应用程序使用默认 GPU 或 GPU 0。
您还可以扩展它以提供多个 GPU,例如:
export CUDA_VISIBLE_DEVICES="2,4"
意味着通常枚举为 2 和 4 的 GPU 现在将是该会话中唯一的 GPU "visible",它们将枚举为 0 和 1。
在我看来,上述方法是最简单的。选择 "isn't in use" 的 GPU 是有问题的,因为:
- 我们需要 "in use"
的定义
- 在特定时刻使用的 GPU 之后可能不会立即使用
- 最重要的是,不是 "in use" 的 GPU 可能会异步变为 "in use",这意味着您会面临竞争条件。
所以最好的建议 (IMO) 是明确管理 GPU。否则,您需要某种形式的作业调度程序(超出此问题的范围,IMO)才能查询未使用的 GPU,并且 "reserve" 在另一个应用程序尝试这样做之前,以有序的方式进行查询。
有一种更好(更自动)的方法,我们在 PIConGPU 中使用它 运行 在巨大的(和不同的)集群上。
在此处查看实现:https://github.com/ComputationalRadiationPhysics/picongpu/blob/909b55ee24a7dcfae8824a22b25c5aef6bd098de/src/libPMacc/include/Environment.hpp#L169
基本上:调用 cudaGetDeviceCount
获取 GPU 的数量,遍历它们并调用 cudaSetDevice
将其设置为当前设备并检查是否有效。由于 CUDA 中的某些错误使 setDevice 成功但所有后续调用都失败,因此此检查可能涉及测试创建流,因为设备实际正在使用中。
注意:您可能需要将 GPU 设置为独占模式,这样一个 GPU 只能由一个进程使用。如果您没有足够的 "batch" 数据,您可能需要相反的方法:多个进程将工作提交到一个 GPU。所以根据你的需要调整。
其他想法是:启动一个 MPI 应用程序,每个等级的进程数与 GPU 的数量相同,并使用与本地等级号相同的设备号。这也有助于像您这样有不同数据集要分发的应用程序。所以你可以,例如具有 MPI 级别 0 进程 length1-data 和 MPI 级别 1 进程 length2-data 等
背景:
我编写了一个 CUDA 程序,可以对符号序列执行处理。该程序并行处理所有符号序列,并规定所有序列的长度相同。我正在将我的数据分组,每组完全由相同长度的序列组成。程序一次处理1组。
问题:
我运行在一台有 4 个 GPU 的 Linux 机器上使用我的代码,我想通过 运行我的程序的 4 个实例(每个 GPU 一个)来利用所有 4 个 GPU ).是否可以让程序 select 一个未被另一个 CUDA 应用程序使用的 GPU 打开 运行?当程序在具有更多或更少 GPU 数量的不同硬件上 运行 时,我不想硬编码任何会导致问题的东西。
environment variable CUDA_VISIBLE_DEVICES
是你的朋友。
我假设您打开的终端数量与 GPU 数量一样多。假设您的应用程序名为 myexe
然后在一个终端中,你可以这样做:
CUDA_VISIBLE_DEVICES="0" ./myexe
在下一个终端:
CUDA_VISIBLE_DEVICES="1" ./myexe
等等。
然后第一个实例将 运行 在 CUDA 枚举的第一个 GPU 上。第二个实例将 运行 在第二个 GPU 上(仅),依此类推。
假设 bash,对于给定的终端会话,您可以通过导出变量来实现此 "permanent":
export CUDA_VISIBLE_DEVICES="2"
此后,该会话中的所有 CUDA 应用程序 运行 将仅观察第三个枚举的 GPU(枚举从 0 开始),并且它们将观察那个 GPU ,就好像它是设备 0 在他们的会话中。
这意味着您无需为此方法对您的应用程序进行任何更改,假设您的应用程序使用默认 GPU 或 GPU 0。
您还可以扩展它以提供多个 GPU,例如:
export CUDA_VISIBLE_DEVICES="2,4"
意味着通常枚举为 2 和 4 的 GPU 现在将是该会话中唯一的 GPU "visible",它们将枚举为 0 和 1。
在我看来,上述方法是最简单的。选择 "isn't in use" 的 GPU 是有问题的,因为:
- 我们需要 "in use" 的定义
- 在特定时刻使用的 GPU 之后可能不会立即使用
- 最重要的是,不是 "in use" 的 GPU 可能会异步变为 "in use",这意味着您会面临竞争条件。
所以最好的建议 (IMO) 是明确管理 GPU。否则,您需要某种形式的作业调度程序(超出此问题的范围,IMO)才能查询未使用的 GPU,并且 "reserve" 在另一个应用程序尝试这样做之前,以有序的方式进行查询。
有一种更好(更自动)的方法,我们在 PIConGPU 中使用它 运行 在巨大的(和不同的)集群上。 在此处查看实现:https://github.com/ComputationalRadiationPhysics/picongpu/blob/909b55ee24a7dcfae8824a22b25c5aef6bd098de/src/libPMacc/include/Environment.hpp#L169
基本上:调用 cudaGetDeviceCount
获取 GPU 的数量,遍历它们并调用 cudaSetDevice
将其设置为当前设备并检查是否有效。由于 CUDA 中的某些错误使 setDevice 成功但所有后续调用都失败,因此此检查可能涉及测试创建流,因为设备实际正在使用中。
注意:您可能需要将 GPU 设置为独占模式,这样一个 GPU 只能由一个进程使用。如果您没有足够的 "batch" 数据,您可能需要相反的方法:多个进程将工作提交到一个 GPU。所以根据你的需要调整。
其他想法是:启动一个 MPI 应用程序,每个等级的进程数与 GPU 的数量相同,并使用与本地等级号相同的设备号。这也有助于像您这样有不同数据集要分发的应用程序。所以你可以,例如具有 MPI 级别 0 进程 length1-data 和 MPI 级别 1 进程 length2-data 等