在Slurm中有两种分配GPU的方法:一般的--gres=gpu:N
参数,或者像--gpus-per-task=N
这样的特定参数。在批处理脚本中启动MPI任务还有两种方法:要么使用srun
,要么使用通常的mpirun
(当使用Slurm支持编译OpenMPI时)。我发现这些方法在行为上有一些惊人的差异。
我使用sbatch
提交了一个批处理作业,其中基本脚本如下:
#!/bin/bash
#SBATCH --job-name=sim_1 # job name (default is the name of this file)
#SBATCH --output=log.%x.job_%j # file name for stdout/stderr (%x will be replaced with the job name, %j with the jobid)
#SBATCH --time=1:00:00 # maximum wall time allocated for the job (D-H:MM:SS)
#SBATCH --partition=gpXY # put the job into the gpu partition
#SBATCH --exclusive # request exclusive allocation of resources
#SBATCH --mem=20G # RAM per node
#SBATCH --threads-per-core=1 # do not use hyperthreads (i.e. CPUs = physical cores below)
#SBATCH --cpus-per-task=4 # number of CPUs per process
## nodes allocation
#SBATCH --nodes=2 # number of nodes
#SBATCH --ntasks-per-node=2 # MPI processes per node
## GPU allocation - variant A
#SBATCH --gres=gpu:2 # number of GPUs per node (gres=gpu:N)
## GPU allocation - variant B
## #SBATCH --gpus-per-task=1 # number of GPUs per process
## #SBATCH --gpu-bind=single:1 # bind each process to its own GPU (single:<tasks_per_gpu>)
# start the job in the directory it was submitted from
cd "$SLURM_SUBMIT_DIR"
# program execution - variant 1
mpirun ./sim
# program execution - variant 2
#srun ./sim
第一个块中的#SBATCH
选项非常明显,也很乏味。接下来,当作业至少在两个节点上运行时,我将描述的行为是可以观察到的。我在每个节点运行2个任务,因为我们每个节点有2个GPU。最后,有两个变体的GPU分配(A和B)和两个变体的程序执行(1和2)。因此,总共有4个变体: A1、A2、B1、B2。
变量A1 (--gres=gpu:2,mpirun)
变量A2 (-gres=gpu:2,srun)
在两个变体A1和A2中,作业以最佳性能正确执行,日志中有以下输出:
Rank 0: rank on node is 0, using GPU id 0 of 2, CUDA_VISIBLE_DEVICES=0,1
Rank 1: rank on node is 1, using GPU id 1 of 2, CUDA_VISIBLE_DEVICES=0,1
Rank 2: rank on node is 0, using GPU id 0 of 2, CUDA_VISIBLE_DEVICES=0,1
Rank 3: rank on node is 1, using GPU id 1 of 2, CUDA_VISIBLE_DEVICES=0,1
变体B1 (-gpus每个任务=1,mpirun)
由于第二个节点上的CUDA_VISIBLE_DEVICES=0
,作业未正确执行,GPU未正确映射:
Rank 0: rank on node is 0, using GPU id 0 of 2, CUDA_VISIBLE_DEVICES=0,1
Rank 1: rank on node is 1, using GPU id 1 of 2, CUDA_VISIBLE_DEVICES=0,1
Rank 2: rank on node is 0, using GPU id 0 of 1, CUDA_VISIBLE_DEVICES=0
Rank 3: rank on node is 1, using GPU id 0 of 1, CUDA_VISIBLE_DEVICES=0
请注意,这个变体的行为与不含--gpu-bind=single:1
的情况相同。
变体B2 (--gpu-每个任务=1,-gpu=单:1,srun)
GPU被正确地映射(由于--gpu-bind=single:1
,每个进程只看到一个GPU):
Rank 0: rank on node is 0, using GPU id 0 of 1, CUDA_VISIBLE_DEVICES=0
Rank 1: rank on node is 1, using GPU id 0 of 1, CUDA_VISIBLE_DEVICES=1
Rank 2: rank on node is 0, using GPU id 0 of 1, CUDA_VISIBLE_DEVICES=0
Rank 3: rank on node is 1, using GPU id 0 of 1, CUDA_VISIBLE_DEVICES=1
但是,当级别开始通信时会出现MPI错误(对于每个级别重复一次类似的消息):
--------------------------------------------------------------------------
The call to cuIpcOpenMemHandle failed. This is an unrecoverable error
and will cause the program to abort.
Hostname: gp11
cuIpcOpenMemHandle return value: 217
address: 0x7f40ee000000
Check the cuda.h file for what the return value means. A possible cause
for this is not enough free device memory. Try to reduce the device
memory footprint of your application.
--------------------------------------------------------------------------
虽然它说“这是一个无法恢复的错误”,但执行似乎进行得很好,除非日志中到处都是这样的消息(假设每个MPI通信调用都有一条消息):
[gp11:122211] Failed to register remote memory, rc=-1
[gp11:122212] Failed to register remote memory, rc=-1
[gp12:62725] Failed to register remote memory, rc=-1
[gp12:62724] Failed to register remote memory, rc=-1
显然,这是一个OpenMPI错误消息。我发现了一个关于这个错误的旧螺纹,它建议使用--mca btl_smcuda_use_cuda_ipc 0
来禁用CUDA IPC。但是,由于在本例中使用srun
启动程序,我不知道如何将这些参数传递给OpenMPI。
注意,在这个变体中,--gpu-bind=single:1
只影响可见的GPU (CUDA_VISIBLE_DEVICES
)。但是即使没有这个选项,每个任务仍然能够选择正确的GPU和错误仍然出现。
知道发生了什么以及如何解决变体B1和B2中的错误吗?理想情况下,我们希望使用--gpus-per-task
,它比--gres=gpu:...
更灵活(当我们更改--ntasks-per-node
时,它可以更改的参数少了一个)。对我们来说,使用mpirun
和srun
并不重要。
我们有Slurm 20.11.5.1,OpenMPI 4.0.5 ( --with-cuda
和--with-slurm
)和CUDA 11.2.2。操作系统是Arch。网络是10G以太网(没有InfiniBand或OmniPath)。如果我应该包括更多的信息,请告诉我。
发布于 2022-02-03 14:17:24
我有个相关的问题。同跑
#SBATCH --nodes=1
#SBATCH --ntasks=4
#SBATCH --gres=gpu:1
将导致进程共享一个GPU。
"PROCID=2: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360)"
"PROCID=1: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360)"
"PROCID=0: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360)"
"PROCID=3: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360)"
我想这是正确的。
同跑
#SBATCH --nodes=1
#SBATCH --ntasks=4
#SBATCH --gpus-per-task=1
将只导致最后一个接收GPU的进程。
"PROCID=2: No devices found."
"PROCID=3: No devices found."
"PROCID=0: No devices found."
"PROCID=1: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-02348a17-a825-300c-0336-48e33d0dadb2)"
注意连续运行中的不同ID。
"PROCID=2: No devices found."
"PROCID=1: No devices found."
"PROCID=3: No devices found."
"PROCID=0: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360)"
同跑
#SBATCH --nodes=1
#SBATCH --ntasks=4
#SBATCH --gres=gpu:4
将导致每个进程都可以访问所有4个GPU。
"PROCID=3: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360) GPU 1: NVIDIA A100-SXM4-40GB (UUID: GPU-02348a17-a825-300c-0336-48e33d0dadb2) GPU 2: NVIDIA A100-SXM4-40GB (UUID: GPU-fbd9a227-e473-b993-215f-8f39b3574fd0) GPU 3: NVIDIA A100-SXM4-40GB (UUID: GPU-7843f55f-a15b-1d4c-229c-39b5c439bd5e)"
"PROCID=1: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360) GPU 1: NVIDIA A100-SXM4-40GB (UUID: GPU-02348a17-a825-300c-0336-48e33d0dadb2) GPU 2: NVIDIA A100-SXM4-40GB (UUID: GPU-fbd9a227-e473-b993-215f-8f39b3574fd0) GPU 3: NVIDIA A100-SXM4-40GB (UUID: GPU-7843f55f-a15b-1d4c-229c-39b5c439bd5e)"
"PROCID=2: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360) GPU 1: NVIDIA A100-SXM4-40GB (UUID: GPU-02348a17-a825-300c-0336-48e33d0dadb2) GPU 2: NVIDIA A100-SXM4-40GB (UUID: GPU-fbd9a227-e473-b993-215f-8f39b3574fd0) GPU 3: NVIDIA A100-SXM4-40GB (UUID: GPU-7843f55f-a15b-1d4c-229c-39b5c439bd5e)"
"PROCID=0: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-715daa1d-db6f-9e69-ab48-190158bd5360) GPU 1: NVIDIA A100-SXM4-40GB (UUID: GPU-02348a17-a825-300c-0336-48e33d0dadb2) GPU 2: NVIDIA A100-SXM4-40GB (UUID: GPU-fbd9a227-e473-b993-215f-8f39b3574fd0) GPU 3: NVIDIA A100-SXM4-40GB (UUID: GPU-7843f55f-a15b-1d4c-229c-39b5c439bd5e)"
同跑
#SBATCH --ntasks=4
#SBATCH --gres=gpu:4
#SBATCH --gpu-bind=single:1
将再次导致最后一个接收GPU的进程。
"PROCID=1: No devices found."
"PROCID=0: No devices found."
"PROCID=3: No devices found."
"PROCID=2: GPU 0: NVIDIA A100-SXM4-40GB (UUID: GPU-fbd9a227-e473-b993-215f-8f39b3574fd0)"
https://stackoverflow.com/questions/67091056
复制相似问题