Slurm 支持定义和调度任意通用 RESources 的功能 (GRES)。为特定 GRES 类型启用了其他内置功能, 包括图形处理单元 (GPU)、CUDA 多进程服务 (MPS) 设备,并通过可扩展的插件机制进行分片。
默认情况下,群集的配置中未启用任何 GRES。 您必须在 slurm.conf 配置文件中明确指定要管理的 GRES。的配置参数 兴趣是 GresTypes 和 Gres。
有关详细信息,请参见 slurm.conf 手册页中的 GresTypes 和 Gres。
请注意,每个节点的 GRES 规范以相同的方式工作 作为其他资源管理。发现资源较少的节点 than configured 将置于 DRAIN 状态。
示例 slurm.conf 文件的片段:
# Configure four GPUs (with MPS), plus bandwidth
GresTypes=gpu,mps,bandwidth
NodeName=tux[0-7] Gres=gpu:tesla:2,gpu:kepler:2,mps:400,bandwidth:lustre:no_consume:4G
每个具有通用资源的计算节点通常都包含一个 gres.conf 文件,该文件描述节点上可用的资源、它们的计数、 应与这些资源一起使用的关联设备文件和内核。
在某些情况下,您可能希望在节点上定义通用资源 而未指定该 GRES 的数量。例如,文件系统类型 当作业在该节点上运行时,节点的值不会减少。 可以使用 no_consume 标志允许用户请求 GRES 没有定义的计数,该计数在请求时使用。
要查看可用的 gres.conf 配置参数,请参见 gres.conf 手册页。
除非有明确规定,否则不会为作业分配任何通用资源 在作业提交时使用以下选项请求:
--gres 每个节点所需的通用资源
--gpus 每个作业所需的 GPU
--gpus-per-node 每个节点需要的 GPU数。等效于 GPU 的 --gres 选项。
--gpus-per-socket 每个线程需要的 GPU数据。要求作业指定任务套接字
--gpus-per-task 每个任务需要的 GPU数。要求作业指定任务计数。
salloc、sbatch 和 srun 命令支持所有这些选项。 请注意,所有 --gpu* 选项仅受 Slurm 的支持 选择/cons_tres插件。 在未配置 select/cons_tres 插件时请求这些选项的作业将被拒绝。 --gres 选项需要一个参数来指定哪些通用资源 是必需的,以及有多少资源使用 name[:type:count] 形式,而所有 --gpu* 选项都需要 [type]:count 形式的参数。 名称与 由 GresTypes 和 Gres 配置参数指定。type 标识该通用资源的特定类型(例如 GPU的特定型号)。count 指定需要多少资源,并具有默认值 值为 1。例如:
sbatch --gres=gpu:kepler:2 ...
在工作中对类型化泛型资源与非类型化泛型资源的请求必须一致 。例如,如果您使用 sbatch 请求 --gres=gpu:2,则无法使用 srun 请求 --gres=gpu:tesla:2 来创建作业步骤。反之亦然, 如果请求类型化 GPU 来创建作业分配,则应请求 用于创建作业步骤的相同类型的 GPU。
此外,还提供了一些其他资源需求规格 专门针对 GPU 和有关这些选项的详细说明是 在作业提交命令的手册页中可用。 至于 --gpu* 选项,这些选项只有 Slurm 的 选择/cons_tres插件。
--cpus-per-gpu 每个 GPU 分配的 CPU 数
--gpu-bind 定义任务如何绑定到 GPU
--gpu-freq 指定 GPU 频率和/或 GPU 内存频率
--mem-per-gpu 为每个 GPU 分配的内存
将根据需要为作业分配特定的通用资源以满足 请求。如果作业挂起,这些资源将不可用 供其他作业使用。
作业步骤可以从分配给 将 --gres 选项与 srun 命令结合使用作业,如所述 以上。默认情况下,作业步骤将分配所有通用资源 工作已请求的,但当 工作是排他性的。如果需要,作业步骤可以明确指定一个 与作业不同的通用资源计数。 此设计选择基于一个场景,即每个作业执行许多 作业步骤。如果作业步骤被授予对所有通用资源的访问权限,则由 默认情况下,某些作业步骤需要明确指定零通用资源 计数,我们认为这更令人困惑。可以分配作业步骤 特定的通用资源,而这些资源将不对其他人可用 作业步骤。下面显示了一个简单的示例。
#!/bin/bash
#
# gres_test.bash
# Submit as follows:
# sbatch --gres=gpu:4 -n4 -N1-1 gres_test.bash
#
srun --gres=gpu:2 -n2 --exclusive show_device.sh &
srun --gres=gpu:1 -n1 --exclusive show_device.sh &
srun --gres=gpu:1 -n1 --exclusive show_device.sh &
wait
如果 AutoDetect=nvml、AutoDetect=rsmi、AutoDetect=nrt、 或 AutoDetect=oneapi 在 gres.conf 中设置,配置详细信息 将自动为任何系统检测到的 GPU 填充。这将删除 需要在 gres.conf 中显式配置 GPU,尽管 Gres= 行 仍然需要 slurm.conf 才能告诉 slurmctld 预期有多少 GRE。 请注意,AutoDetect=nvml、AutoDetect=rsmi 和 AutoDetect=oneapi 需要其对应的 GPU 管理库 安装在节点上,并在 Slurm 配置期间找到以便工作。
默认情况下,所有系统检测到的设备都会添加到节点中。 但是,如果 gres.conf 中的 Type 和 File 与 GPU 匹配 系统,明确指定的任何其他属性(例如核心或链接)都可以对其进行双重检查。 如果系统检测到的 GPU 与其匹配的 GPU 配置不同,则 GPU 从节点中省略,并出现错误。 这使得 gres.conf 可以作为可选的健全性检查并通知 GPU 属性中任何意外更改的管理员。
如果不是所有系统检测到的设备都由 slurm.conf 指定 配置,然后相关的 slurmd 将被排空。然而,它仍然是 可以使用在系统上找到的设备子集(如果是) 在 gres.conf 中手动指定(禁用 AutoDetect)。
gres.conf 文件示例:
# Configure four GPUs (with MPS), plus bandwidth
AutoDetect=nvml
Name=gpu Type=gp100 File=/dev/nvidia0 Cores=0,1
Name=gpu Type=gp100 File=/dev/nvidia1 Cores=0,1
Name=gpu Type=p6000 File=/dev/nvidia2 Cores=2,3
Name=gpu Type=p6000 File=/dev/nvidia3 Cores=2,3
Name=mps Count=200 File=/dev/nvidia0
Name=mps Count=200 File=/dev/nvidia1
Name=mps Count=100 File=/dev/nvidia2
Name=mps Count=100 File=/dev/nvidia3
Name=bandwidth Type=lustre Count=4G Flags=CountOnly
在此示例中,由于指定了 AutoDetect=nvml,因此将根据系统上找到的相应 GPU 检查每个 GPU 的核心数 匹配指定的“类型”和“文件”。 由于未指定 Links,因此将自动填充 根据在系统上找到的内容。 如果未找到匹配的系统 GPU,则不会进行验证,并且 GPU 为 假设如配置所示。
要使 Type 与系统检测到的设备匹配,它必须与系统检测到的设备完全匹配 匹配或成为 slurmd 通过 AutoDetect 报告的 GPU 名称的子字符串 机制。此 GPU 名称将用下划线替换所有空格。看 GPU 名称,在 slurm.conf 中设置 SlurmdDebug=debug2,然后 重新启动或重新配置 slurmd 并检查 slurmd 日志。例如 使用 AutoDetect=nvml:
debug: gpu/nvml: init: init: GPU NVML plugin loaded
debug2: gpu/nvml: _nvml_init: Successfully initialized NVML
debug: gpu/nvml: _get_system_gpu_list_nvml: Systems Graphics Driver Version: 450.36.06
debug: gpu/nvml: _get_system_gpu_list_nvml: NVML Library Version: 11.450.36.06
debug2: gpu/nvml: _get_system_gpu_list_nvml: Total CPU count: 6
debug2: gpu/nvml: _get_system_gpu_list_nvml: Device count: 1
debug2: gpu/nvml: _get_system_gpu_list_nvml: GPU index 0:
debug2: gpu/nvml: _get_system_gpu_list_nvml: Name: geforce_rtx_2060
debug2: gpu/nvml: _get_system_gpu_list_nvml: UUID: GPU-g44ef22a-d954-c552-b5c4-7371354534b2
debug2: gpu/nvml: _get_system_gpu_list_nvml: PCI Domain/Bus/Device: 0:1:0
debug2: gpu/nvml: _get_system_gpu_list_nvml: PCI Bus ID: 00000000:01:00.0
debug2: gpu/nvml: _get_system_gpu_list_nvml: NVLinks: -1
debug2: gpu/nvml: _get_system_gpu_list_nvml: Device File (minor number): /dev/nvidia0
debug2: gpu/nvml: _get_system_gpu_list_nvml: CPU Affinity Range - Machine: 0-5
debug2: gpu/nvml: _get_system_gpu_list_nvml: Core Affinity Range - Abstract: 0-5
在此示例中,GPU 的名称报告为 geforce_rtx_2060
。所以在你的 slurm.conf 和 gres.conf,GPU 类型可以设置为 geforce
、rtx
、2060
、 geforce_rtx_2060
或任何其他 子字符串,并且 slurmd 应该能够将其与系统检测到的匹配 geforce_rtx_2060
设备。
在Slurm的GPU GRES插件的情况下,环境变量CUDA_VISIBLE_DEVICES会针对每个作业步骤进行设置,以确定每个节点上可供其使用的GPU。这一环境变量仅在特定计算节点上启动任务时设置(对于salloc命令未设置全局环境变量,而对于sbatch命令设置的环境变量仅反映该节点(即分配中的节点零)上分配给该作业的GPU)。CUDA版本3.1(或更高)使用此环境变量,以便在具有GPU的节点上运行多个作业或作业步骤,并确保分配给每个作业的资源是独一无二的。在上述示例中,所分配的节点可能有四个或更多的图形设备。在这种情况下,CUDA_VISIBLE_DEVICES将引用每个文件的唯一设备,输出可能类似于以下内容:
JobStep=1234.0 CUDA_VISIBLE_DEVICES=0,1
JobStep=1234.1 CUDA_VISIBLE_DEVICES=2
JobStep=1234.2 CUDA_VISIBLE_DEVICES=3
注意:请务必在gres.conf文件中指定文件参数,并确保它们按数字递增顺序排列。
CUDA_VISIBLE_DEVICES环境变量也会在作业的Prolog和Epilog程序中设置。请注意,作业的环境变量与Prolog和Epilog中设置的环境变量可能会有所不同,尤其是在Slurm配置为使用Linux cgroup限制作业可见的设备文件的情况下。这是因为Prolog和Epilog程序在任何Linux cgroup之外运行,而作业则在cgroup内部运行,因此可能会有不同的可见设备集合。例如,如果某个作业分配了设备"/dev/nvidia1",那么在Prolog和Epilog中,CUDA_VISIBLE_DEVICES的值将设置为"1",而作业的CUDA_VISIBLE_DEVICES的值则设为"0"(即作业可见的第一个GPU设备)。有关更多信息,请参阅Prolog和Epilog指南。
在可能的情况下,Slurm会自动使用NVML确定系统上的GPU。NVML(它支持nvidia-smi工具)按照它们的PCI总线ID顺序给GPU编号。为了使此编号与CUDA报告的编号匹配,必须将CUDA_DEVICE_ORDER环境变量设置为CUDA_DEVICE_ORDER=PCI_BUS_ID。
GPU设备文件(例如/dev/nvidia1)基于Linux小号分配,而NVML的设备编号是通过PCI总线ID从低到高进行分配的。这两者之间的映射是非确定性的,并且依赖于系统,甚至在硬件或操作系统更改后,在不同的启动之间可能会有所不同。在大多数情况下,这种分配似乎相当稳定。然而,需要在启动后进行检查,以确保GPU设备分配到特定的设备文件中。
有关CUDA_VISIBLE_DEVICES和CUDA_DEVICE_ORDER环境变量的更多信息,请查阅NVIDIA CUDA文档。
CUDA多进程服务(MPS)提供了一种机制,可以让多个作业共享GPU,每个作业分配一定比例的GPU资源。在节点上可用的MPS资源总数应该在slurm.conf文件中配置(例如,“NodeName=tux[1-16] Gres=gpu:2,mps:200”)。以下是在gres.conf文件中配置MPS的几种选项,后面会附上示例:
无MPS配置:在slurm.conf中定义的gres/mps元素数量将均匀分配到节点上配置的所有GPU上。例如,“NodeName=tux[1-16] Gres=gpu:2,mps:200”将为每个GPU配置100个gres/mps资源。
MPS配置仅包括名称和数量参数:gres/mps元素的数量将在节点上配置的所有GPU之间均匀分配。这与第一种情况类似,但在gres.conf文件中重复了配置。
MPS配置包括名称、文件和数量参数:每个文件(File)参数应标识GPU的设备文件路径,而数量(Count)应标识该特定GPU设备可用的gres/mps资源数量。这在异构环境中可能会很有用。例如,节点上的某些GPU可能比其他GPU更强大,因此与更高的gres/mps数量相关联。另一种使用场景是防止某些GPU用于MPS(即它们的MPS数量为零)。
需要注意的是,gres/mps的类型(Type)和核心(Cores)参数会被忽略。这些信息是从gres/gpu配置中复制过来的。
请注意,Count参数会转换为百分比,因此该值通常为100的倍数。
需要注意的是,如果安装了NVIDIA的NVML库,GPU配置(即类型、文件、核心和链接数据)将自动从库中收集,而无需在gres.conf文件中记录。
默认情况下,MPS的作业请求需要适合每个节点上的单个GPU。这可以通过在slurm.conf配置文件中使用标志进行覆盖。请参见OPT_MULTIPLE_SHARING_GRES_PJ。
请注意,同一GPU可以分配为GPU类型的GRES或MPS类型的GRES,但不能同时分配。换句话说,一旦GPU被分配为gres/gpu资源,它将不再作为gres/mps可用。同样,一旦GPU被分配为gres/mps资源,它将不再作为gres/gpu可用。然而,具有相同GPU的MPS通用资源可以分配给属于多个用户的多个作业,只要分配给作业的MPS总数不超过配置的数量。此外,由于共享GRES(MPS)不能与共享GRES(GPU)同时分配,因此该选项仅分配所有共享GRES,而不分配任何底层共享GRES。以下是Slurm的gres.conf文件的一些示例配置。
# Example 1 of gres.conf
# Configure four GPUs (with MPS)
AutoDetect=nvml
Name=gpu Type=gp100 File=/dev/nvidia0 Cores=0,1
Name=gpu Type=gp100 File=/dev/nvidia1 Cores=0,1
Name=gpu Type=p6000 File=/dev/nvidia2 Cores=2,3
Name=gpu Type=p6000 File=/dev/nvidia3 Cores=2,3
# Set gres/mps Count value to 100 on each of the 4 available GPUs
Name=mps Count=400
# Example 2 of gres.conf
# Configure four different GPU types (with MPS)
AutoDetect=nvml
Name=gpu Type=gtx1080 File=/dev/nvidia0 Cores=0,1
Name=gpu Type=gtx1070 File=/dev/nvidia1 Cores=0,1
Name=gpu Type=gtx1060 File=/dev/nvidia2 Cores=2,3
Name=gpu Type=gtx1050 File=/dev/nvidia3 Cores=2,3
Name=mps Count=1300 File=/dev/nvidia0
Name=mps Count=1200 File=/dev/nvidia1
Name=mps Count=1100 File=/dev/nvidia2
Name=mps Count=1000 File=/dev/nvidia3
注意:gres/mps需要使用select/cons_tres插件。
MPS的作业请求将与其他任何GRES请求一样处理,唯一不同的是每个节点的请求必须仅使用一个GPU来满足,并且每个节点只能配置一个GPU用于MPS。例如,对于“--gres=mps:50”的作业请求,不能通过在单个节点上使用一个GPU的20%和第二个GPU的30%来满足。来自不同用户的多个作业可以同时在同一节点上使用MPS。请注意,GPU和MPS的GRES类型不能在同一作业中请求。此外,请求MPS资源的作业不能指定GPU频率。
应该使用一个Prolog程序根据需要启动和停止MPS服务器。一个示例Prolog脚本与Slurm发行版一起包含在etc/prolog.example位置。其操作模式是,如果一个作业被分配了gres/mps资源,那么Prolog将设置CUDA_VISIBLE_DEVICES、CUDA_MPS_ACTIVE_THREAD_PERCENTAGE和SLURM_JOB_UID环境变量。Prolog应确保为该GPU和用户(UID == User ID)启动MPS服务器。它还会将GPU设备ID记录在本地文件中。如果一个作业被分配了gres/gpu资源,则Prolog将设置CUDA_VISIBLE_DEVICES和SLURM_JOB_UID环境变量(不设置CUDA_MPS_ACTIVE_THREAD_PERCENTAGE)。Prolog应终止与该GPU关联的任何MPS服务器。根据本地环境的需要,可能需要修改此脚本。有关更多信息,请参阅Prolog和Epilog指南。
请求MPS资源的作业将设置CUDA_VISIBLE_DEVICES和CUDA_DEVICE_ORDER环境变量。设备ID是相对于MPS服务器控制下的这些资源的,并且在当前实现中始终为零(每个节点在MPS模式下仅可使用一个GPU)。该作业还将设置CUDA_MPS_ACTIVE_THREAD_PERCENTAGE环境变量,以反映分配给所分配GPU的MPS资源百分比。该百分比将基于配置的Count中分配给作业步骤的部分进行计算。例如,请求“--gres=mps:200”的作业如果使用上面示例2的配置,将被分配:
另一种操作模式是允许作业分配整个GPU,然后根据作业中的注释触发MPS服务器的启动。例如,如果一个作业分配了整个GPU,则可以在作业中搜索“mps-per-gpu”或“mps-per-node”的注释(使用“scontrol show job”命令),并以此为依据,为每个GPU或所有GPU分别启动一个MPS守护进程。
请查阅NVIDIA多进程服务(MPS)文档,以获取有关MPS的更多信息。
请注意,早期版本的NVIDIA驱动程序存在一个漏洞,可能会影响用户在共享GPU时的使用情况。更多信息可以在CVE-2018-6260和安全公告:NVIDIA GPU显示驱动程序 - 2019年2月。
NVIDIA MPS在不同用户之间的GPU共享方面存在内置限制。系统中只有一个用户可以拥有一个活跃的MPS服务器,而MPS控制守护进程将对来自不同用户的MPS服务器激活请求进行排队,从而导致用户之间的GPU访问序列化(请参见MPS文档中的第2.3.1.1节 - MPS文档中的限制)。因此,不同用户无法在GPU上真正并发运行,而是GPU将根据时间切分在用户之间分配(有关该过程的示意图,请参见MPS文档中的第3.3节 )。
从版本21.08开始,Slurm现在支持NVIDIA多实例GPU(MIG)设备。这项功能允许某些较新的NVIDIA GPU(如A100)将一个GPU拆分为多达七个独立的、隔离的GPU实例。Slurm可以将这些MIG实例视为单独的GPU,配备cgroup隔离和任务绑定功能。
要在Slurm中配置MIG,请在包含MIG的节点的gres.conf中指定AutoDetect=nvml,并在slurm.conf中像对待常规GPU一样指定Gres,例如:NodeName=tux[1-16] gres=gpu:2。可以指定一个可选的GRES类型,以区分不同大小的MIG与集群中的其他GPU。这种类型必须是节点在其slurmd日志中以debug2日志级别报告的“MIG Profile”字符串的子字符串。以下是一个示例slurm.conf,用于一个具有2个GPU的系统,其中一个被划分为2个MIG,且“MIG Profile”为nvidia_a100_3g.20gb:
AccountingStorageTRES=gres/gpu,gres/gpu:a100,gres/gpu:a100_3g.20gb
GresTypes=gpu
NodeName=tux[1-16] gres=gpu:a100:1,gpu:a100_3g.20gb:2
MultipleFiles 参数 允许您为 GPU 卡指定多个设备文件。
MIG 不支持健全性检查自动检测模式。 Slurm 期望 MIG 设备已分区,并且不支持 MIG 设备 动态 MIG 分区。
有关 NVIDIA MIG 的更多信息(包括如何对它们进行分区),请参阅 MIG 用户指南。
分片提供了一种通用机制,允许多个作业共享 GPU。虽然它确实允许多个作业在给定的 GPU 上运行,但并不限制在 GPU 上运行的进程,它仅允许 GPU 被共享。因此,分片最适合于同质工作流。建议将节点上的分片数量限制为可以同时在该节点上运行的最大作业数(即核心数)。节点上可用的分片总数应在 slurm.conf 文件中进行配置(例如,“NodeName=tux[1-16] Gres=gpu:2,shard:64”)。在 gres.conf 文件中有几种配置分片的选项,以下是列出的选项及其示例:
无分片配置:在 slurm.conf 中定义的 gres/shard 元素的数量将在节点上配置的所有 GPU 之间均匀分配。例如,“NodeName=tux[1-16] Gres=gpu:2,shard:64”将在两个 GPU 上配置 32 个 gres/shard 资源。
分片配置仅包括名称和数量参数:gres/shard 元素的数量将在节点上配置的所有 GPU 之间均匀分配。这与情况 1 类似,但在 gres.conf 文件中放置了重复的配置。
分片配置包括名称、文件和数量参数:每个文件参数应标识 GPU 的设备文件路径,数量应标识该特定 GPU 设备可用的 gres/shard 资源数量。这在异构环境中可能很有用。例如,节点上的某些 GPU 可能比其他 GPU 更强大,因此与更高的 gres/shard 数量相关联。另一个用例是防止某些 GPU 被用于分片(即它们的分片数量为零)。
请注意,gres/shard 的类型和核心参数会被忽略。这些信息是从 gres/gpu 配置中复制的。
请注意,如果安装了 NVIDIA 的 NVML 库,GPU 配置(即类型、文件、核心和链接数据)将自动从库中收集,无需在 gres.conf 文件中记录。
请注意,同一 GPU 可以被分配为 GRES 的 GPU 类型或 GRES 的分片类型,但不能同时作为两者。换句话说,一旦 GPU 被分配为 gres/gpu 资源,它将不再作为 gres/shard 可用。同样,一旦 GPU 被分配为 gres/shard 资源,它将不再作为 gres/gpu 可用。然而,同一 GPU 可以作为分片通用资源分配给多个属于多个用户的作业,只要分配给作业的 SHARD 总数不超过配置的数量。
默认情况下,作业请求的分片需要适合每个节点上的单个 GPU。这可以通过 slurm.conf 配置文件中的标志进行覆盖。请参见 OPT_MULTIPLE_SHARING_GRES_PJ。
为了正确配置,适当的节点需要将分片关键字添加为相关节点的 GRES,并添加到 GresTypes 参数中。如果希望在会计中跟踪分片,则还需要将分片添加到 AccountingStorageTRES。请参见示例 slurm.conf 中的相关设置:
AccountingStorageTRES=gres/gpu,gres/shard
GresTypes=gpu,shard
NodeName=tux[1-16] Gres=gpu:2,shard:64
下面显示了 Slurm 的 gres.conf 文件的一些示例配置。
# Example 1 of gres.conf
# Configure four GPUs (with Sharding)
AutoDetect=nvml
Name=gpu Type=gp100 File=/dev/nvidia0 Cores=0,1
Name=gpu Type=gp100 File=/dev/nvidia1 Cores=0,1
Name=gpu Type=p6000 File=/dev/nvidia2 Cores=2,3
Name=gpu Type=p6000 File=/dev/nvidia3 Cores=2,3
# Set gres/shard Count value to 8 on each of the 4 available GPUs
Name=shard Count=32
# Example 2 of gres.conf
# Configure four different GPU types (with Sharding)
AutoDetect=nvml
Name=gpu Type=gtx1080 File=/dev/nvidia0 Cores=0,1
Name=gpu Type=gtx1070 File=/dev/nvidia1 Cores=0,1
Name=gpu Type=gtx1060 File=/dev/nvidia2 Cores=2,3
Name=gpu Type=gtx1050 File=/dev/nvidia3 Cores=2,3
Name=shard Count=8 File=/dev/nvidia0
Name=shard Count=8 File=/dev/nvidia1
Name=shard Count=8 File=/dev/nvidia2
Name=shard Count=8 File=/dev/nvidia3
注意:gres/shard 需要使用 select/cons_tres 插件。
请求分片的作业无法指定 GPU 频率。
请求分片资源的作业将设置 CUDA_VISIBLE_DEVICES、ROCR_VISIBLE_DEVICES 或 GPU_DEVICE_ORDINAL 环境变量,这与它作为 GPU 的状态相同。
具有分片的步骤会设置 SLURM_SHARDS_ON_NODE,指示分配的分片数量。