背景
我编写了一个CUDA程序,对一系列符号进行处理。该程序并行处理所有符号序列,并规定所有序列具有相同的长度。我将我的数据分组成组,每组完全由相同长度的序列组成。该计划一次处理1个小组。
问题:
我在具有4个GPU的Linux机器上运行我的代码,并希望通过运行我的程序的4个实例(每个GPU 1个)来利用所有4个GPU。是否可以让程序选择另一个CUDA应用程序无法运行的GPU?当程序在具有更多或更少GPU的不同硬件上运行时,我不想硬编码会导致问题的任何事情。
答案 0 :(得分:5)
environment variable 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 一样。 / p>
这意味着您不必对此方法的应用程序进行任何更改,假设您的应用使用默认的GPU或GPU 0。
您还可以对此进行扩展以使多个GPU可用,例如:
export CUDA_VISIBLE_DEVICES="2,4"
表示通常枚举为2和4的GPU现在是该会话中唯一“可见”的GPU,它们将枚举为0和1。
在我看来,上述方法最简单。选择“未使用”的GPU是有问题的,因为:
所以最好的建议(IMO)是明确管理GPU。否则,您需要某种形式的作业调度程序(在此问题的范围之外,IMO)才能查询未使用的GPU并在另一个应用程序尝试之前“保留”一个,以有序的方式。
答案 1 :(得分:0)
有一种更好(更自动)的方式,我们在PIConGPU中使用这种方式在大型(和不同)群集上运行。 请参阅此处的实施:https://github.com/ComputationalRadiationPhysics/picongpu/blob/909b55ee24a7dcfae8824a22b25c5aef6bd098de/src/libPMacc/include/Environment.hpp#L169
基本上:调用cudaGetDeviceCount
获取GPU的数量,迭代它们并调用cudaSetDevice
将其设置为当前设备并检查是否有效。此检查可能涉及测试创建流,因为CUDA中的某些错误使setDevice成功,但所有后来的调用都因设备实际使用而失败。
注意:您可能需要将GPU设置为独占模式,以便GPU只能由一个进程使用。如果你没有足够的数据来批量生产一批"批次"你可能想要相反:多个进程提交工作到一个GPU。所以根据你的需要调整。
其他想法是:启动MPI应用程序,每个等级的进程数与GPU相同,并使用相同的设备号作为本地等级号。这也有助于像您这样的应用程序分发不同的数据集。所以你可以,例如具有MPI等级0进程长度1数据和MPI等级1进程长度2数据等。