Slurm 指定 GPU 卡:File=/dev/nvidiaX 映射的坑与修复
这配置不一定是正确的 ,存在一个关键的不确定性:File=/dev/nvidia0 和 /dev/nvidia1 的映射,并不保证 永久对应 nvidia-smi 中显示的 GPU 0(Bus-Id 17:00.0)和 GPU 1(Bus-Id CA:00.0)。
为什么说"不一定对"
Slurm 官方文档明确指出:GPU 设备文件(如 /dev/nvidia0)基于 Linux 次设备号分配,而 NVML(nvidia-smi 背后的库)按 PCI 总线 ID 排序。两者之间的映射关系是不确定的,且依赖于系统,在硬件或操作系统变更后、甚至重启后都可能改变。
你之前遇到的 Reason=gres/gpu count reported lower than configured (1 < 2) 错误,恰恰可能就是这个映射错位导致的:Slurm 通过你写的 File= 去匹配 GPU,但匹配结果与它在 slurm.conf 中期望的数量对不上。
如何验证当前映射是否正确
在你的节点上运行以下命令,检查 slurmd 实际看到的设备文件与 NVML 编号的对应关系:
bash
sudo slurmd -G
观察输出中每个 GPU 的 File= 字段是否与你期望的物理卡对应。如果 slurmd -G 显示它把 card0 匹配到了 /dev/nvidia1 而不是 nvidia0,你的配置就会导致调度错位。
更稳妥的做法
既然你的目标是在两块 A100 中指定使用卡零 ,而 File= 映射又不可靠,推荐:
-
在
gres.conf中启用自动探测,并只标记类型:AutoDetect=nvml Name=gpu Type=card0 Name=gpu Type=card1注意:
Type的值必须是 NVML 返回设备名的子串(A100 通常包含a100),但 Slurm 允许自定义Type作为调度标签,只要与slurm.conf中的Gres=一致即可。更简单的做法是直接让两块卡用同一个类型名(如Type=a100),然后在提交作业时通过--gres=gpu:a100:1请求,由 Slurm 分配任意一块空闲的。 -
如果你确实必须绑定到某一块物理卡 ,则不要依赖自动探测。保持
AutoDetect=off,用File=手动指定,但每次驱动重载或重启后 ,都必须用slurmd -G或nvidia-smi核对/dev/nvidiaX与 PCI Bus-Id 的对应关系是否仍然一致。一旦映射漂移,作业就可能被分配到错误的物理 GPU 上。
简单结论:你写的两行配置在语法上没问题,但能否稳定"指定卡零"取决于当前系统里 /dev/nvidia0 是否恰好对应 Bus-Id 17:00.0 的那块 A100。先跑 sudo slurmd -G 确认映射,再决定是否继续用 File= 方式。
根据 slurmd -G 的输出,你的配置在 Slurm 层面被正确解析了,但这并不能保证"卡零"的物理对应关系永久可靠。
输出解读
slurmd -G 显示 Slurm 已经接受了你的两条配置:
card0对应Index=0、File=/dev/nvidia0card1对应Index=1、File=/dev/nvidia1
这说明 Slurm 能够读取并映射这两个设备文件。如果之前导致节点不可用的"数量不匹配"错误(1 < 2)是因为配置语法或文件路径错误引起的,那么现在的输出表明这个问题可能已经解决,节点有希望恢复正常。
关键风险依然存在
你之前担心的"指定卡零"问题,核心不在于 Slurm 是否能解析配置,而在于 /dev/nvidia0 是否永远对应 nvidia-smi 里 Bus-Id 为 17:00.0 的那块 A100。
Slurm 官方文档明确指出,GPU 设备文件(/dev/nvidiaX)基于 Linux 次设备号分配,而 NVML(nvidia-smi)按 PCI 总线 ID 排序,两者之间的映射是不确定的且依赖于系统 ,在硬件变动或系统更新后可能改变。你的 slurmd -G 输出只能证明当前这一刻映射是成立的,但无法提供永久保证。
建议
- 先恢复节点 :既然
slurmd -G显示两块卡都被正确识别,你可以尝试sudo scontrol update NodeName=yin-PowerEdge-R750 State=RESUME让节点恢复可用,然后重新提交作业。 - 建立验证习惯 :不要假设
/dev/nvidia0永远是卡零。每次驱动重载、系统重启或硬件变动后,运行一次sudo slurmd -G,确认File=/dev/nvidia0那一行的Index和 PCI 顺序是否符合你的预期。 - 如果必须绝对锁定 :如果你无法接受映射漂移的风险,最稳妥的方式是放弃在 Slurm 层指定物理卡 。让 Slurm 管理两块卡,在提交作业时用
--gres=gpu:1请求任意一块空闲卡,然后在训练脚本内部通过CUDA_VISIBLE_DEVICES或代码逻辑选择你真正想用的那块。这样 Slurm 的分配和你的物理选择就解耦了。
你的gres.conf配置本身没有问题,slurmd -G也证明 Slurm 在节点本地 能正确识别两块卡。问题出在slurmctld(控制节点)与slurmd(计算节点)之间的信息同步上:控制端仍然拿着旧的"只上报了 1 块卡"的记录,没有更新。
你看到的 Reason=gres/gpu count reported lower than configured (1 < 2),时间戳停留在 04:31:36,说明这个错误状态是之前 留下的,不会因为你执行了 scontrol reconfig 就自动消失。scontrol reconfig 只是让控制端重新读取配置,并不会强制节点重新注册它当前的实际 GPU 数量。
怎么修
直接把这个节点从错误状态里"推"出来,让它重新向控制端注册一次:
bash
sudo scontrol update NodeName=yin-PowerEdge-R750 State=DOWN
sudo scontrol update NodeName=yin-PowerEdge-R750 State=RESUME
执行后,用 scontrol show node yin-PowerEdge-R750 | grep -E "State|Reason" 确认。如果 State 变成 IDLE 或 MIXED,并且 Reason 那一行消失或变成 none,就说明节点已恢复,可以重新提交作业。
如果上面两步做完 Reason 仍然不变,可以尝试重启该节点上的 slurmd 服务,强制它重新上报 GPU 信息:
bash
sudo systemctl restart slurmd
为什么 reconfig 不够
slurmd -G 只检查本地配置解析,它成功只代表 slurmd 自己知道有两块卡。但节点在 Slurm 里的状态是由 slurmctld 维护的,如果 slurmctld 之前已经因为"只收到 1 块卡"的报告把节点标记为无效,它需要一次新的节点注册事件才会刷新认知。DOWN → RESUME 或重启 slurmd 就是触发这次重新注册的手段。
节点已经恢复正常了。从你最后的输出看:
State=MIXED,说明节点已可用,且部分资源被占用(MIXED表示有作业在跑但还有空闲资源,对你这种单节点场景是正常状态)。Reason那一行在grep State|Reason的输出里已经消失了,说明之前的错误原因被清除了。squeue显示作业 118 状态为R(Running),正在节点上运行,已经跑了 24 秒。
也就是说,虽然 grep -i gres 那条命令的输出里还残留着旧的 Reason 行(那是 gres 相关的字段展示,可能带了历史缓存),但节点的实际调度状态已经恢复,作业也成功启动,问题解决了。
关于那两条命令的报错
State=DOWN 被拒绝是因为 Slurm 要求 DOWNING 节点时必须带 --reason,比如:
bash
sudo scontrol update NodeName=yin-PowerEdge-R750 State=DOWN Reason="maintenance"
不过你直接执行 State=RESUME 就成功了,说明节点当时已经不在 DOWN/DRAINED 状态,RESUME 起到了刷新作用,这就够了。以后如果确实需要手动 DOWN 节点,记得加上 Reason="..." 即可。
后续建议
- 验证作业确实用到了你指定的卡 :作业跑起来后,可以
scontrol show job 118 | grep -i gres确认它拿到的是card1(你脚本里写的是--gres=gpu:card1:1),同时看作业日志里CUDA_VISIBLE_DEVICES是否正确映射到了预期的物理 GPU。 - 保持对
/dev/nvidiaX映射的警惕 :slurmd -G目前显示card0→/dev/nvidia0、card1→/dev/nvidia1,但如前面所说,这个映射在重启或驱动变动后可能漂移。每次重启后跑一次sudo slurmd -G核对一下即可。 - 如果再次出现
1 < 2:同样的套路------先RESUME刷新,不行就sudo systemctl restart slurmd强制重新上报。
现在作业已经在跑了,可以去看日志确认训练是否正常启动。