Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

slotd

slotd

slotd 是一个使用 Rust 实现的单节点、单用户、具备 Slurm 风格命令界面的调度器。

其他语言文档:

它面向的是一台工作站,而不是集群。目标是在保留常见 Slurm 命令名和主要选项的同时,显著简化运行模型。

  • 一个本地 daemon
  • 一个 SQLite 数据库
  • 一个执行主机
  • 一个本地用户工作流

你通过下面这些熟悉的命令来使用 slotd

  • sbatch
  • srun
  • salloc
  • squeue
  • sacct
  • scontrol
  • scancel
  • sinfo

适合的场景

slotd 适合以下用途。

  • 本地实验队列
  • 长时间运行的 CPU / GPU 作业
  • 单机批处理流水线
  • 带资源预留的交互式工作
  • 工作站上的轻量级 Slurm 风格接口

它不打算提供以下能力。

  • 多节点调度
  • 集群管理
  • account、QoS 或 fairshare
  • 跨主机 federation 或 reservation

主要特性

  • 作为单一 Rust 二进制程序构建
  • 使用 daemon 与 Unix domain socket
  • 使用 SQLite 持久化状态
  • 调度 CPU、内存和 GPU 预留
  • 支持批处理作业、数组作业、交互执行、allocation 与 step
  • 支持延迟启动、单次 requeue、依赖关系以及本地 feature constraint

文档目录

安装

运行要求

  • Linux 或 WSL
  • cargo 的 Rust toolchain
  • 如果希望自动管理 daemon,则需要 systemd --user
  • 如果希望自动检测 GPU,则需要 nvidia-smi

克隆仓库

git clone https://github.com/ymgaq/slotd.git
cd slotd

使用附带脚本安装

在仓库根目录运行:

./scripts/install.sh

默认会执行以下操作:

  • 以 release 模式构建 slotd
  • slotd 安装到 ~/.local/bin
  • 创建 sbatchsqueue 等命令别名
  • ~/.local/share/slotd 下创建 runtime root
  • 写入 ~/.config/slotd/slotd.env
  • 安装并启动 systemd --user 服务

安装脚本选项

选项说明默认值
--repo-root PATH从其他仓库根目录构建当前仓库
--profile NAME使用的 Cargo profilerelease
--install-bin-dir PATH二进制和别名安装目录~/.local/bin
--runtime-root PATH作为 SLOTD_ROOT 的 runtime root~/.local/share/slotd
--config-dir PATH配置目录~/.config/slotd
--systemd-user-dir PATHuser unit 目录~/.config/systemd/user
--cpu-partitions VALUE写入 SLOTD_CPU_PARTITIONS 的值cpu
--gpu-partitions VALUE写入 SLOTD_GPU_PARTITIONS 的值gpu
--features VALUE写入 SLOTD_FEATURES 的值未设置
--notify-cmd VALUE写入 SLOTD_NOTIFY_CMD 的值未设置
--cgroup-base PATH写入 SLOTD_CGROUP_BASE 的值未设置
--skip-build复用已有构建产物off
--skip-systemd不安装或启动 user serviceoff
--uninstall删除已安装内容off
--purge-runtime卸载时删除持久化状态off

示例:

./scripts/install.sh \
 --features cpu,gpu \
  --notify-cmd 'notify-send "slotd" "$SLOTD_JOB_ID $SLOTD_JOB_STATE"'

如果使用 --cgroup-base,请传入一个可写的 cgroup v2 subtree。若保持未设置, CPU 与内存仍然只按预留值参与调度。

卸载

删除安装内容:

./scripts/install.sh --uninstall

删除安装内容和 runtime 状态:

./scripts/install.sh --uninstall --purge-runtime

手动安装

如果不想使用安装脚本,也可以直接构建并运行 slotd

cargo build --release
SLOTD_ROOT="$HOME/.local/share/slotd" ./target/release/slotd daemon

然后在另一个 shell 中使用相同的 SLOTD_ROOT

SLOTD_ROOT="$HOME/.local/share/slotd" ./target/release/slotd sbatch --wrap 'echo hello'

Runtime 文件

默认的 runtime root 为:

~/.local/share/slotd

重要文件和目录:

  • run/slotd.sock
  • lib/state.db
  • lib/jobs/<job_id>/

client 与 daemon 必须使用相同的 SLOTD_ROOT

快速开始

1. 验证 daemon

如果你通过脚本安装,并且没有使用 --skip-systemd,daemon 应该已经启动。

先检查基础命令:

sinfo
squeue
sacct

首次运行时的典型结果:

  • sinfo 会为每个已配置分区显示一行
  • squeue 为空
  • sacct 为空

2. 提交一个简单的批处理作业

sbatch --wrap 'echo hello from slotd'

典型输出:

Submitted batch job 1

3. 查看队列

squeue

作业运行时的典型输出:

JOBID | PARTITION | NAME | USER | ST | TIME | NODELIST(REASON)
1     | cpu       | wrap | ...  | R  | 0:00 | localhost

4. 查看已完成作业

sacct

作业完成后的典型输出:

JobID | Partition | JobName | User | State     | ExitCode
1     | cpu       | wrap    | ...  | COMPLETED | 0:0

5. 查看详细作业信息

scontrol show job 1

这里会显示:

  • 作业标识与所有者
  • 作业状态与 reason
  • 请求的资源
  • 输出路径
  • 工作目录
  • 各类时间戳

6. 试一下交互执行

srun --label --unbuffered -- echo hello

典型输出:

0: hello

运行模型

高层模型

slotd 是一个单主机调度器。它的运行模型刻意保持简单:

  • 一个本地 daemon
  • 一个本地 SQLite 数据库
  • 一个本地执行主机
  • 一个本地用户工作流

没有 controller/worker 拆分,也没有远程节点启动协议。

核心资源

slotd 调度三类资源:

  • CPU
  • 内存
  • GPU

当前行为:

  • CPU 预留量等于 ntasks * cpus-per-task
  • ntasks 会在 batch 和前台执行中按 task rank 启动一个本地进程
  • 总内存默认从 /proc/meminfoMemTotal 检测,失败时回退到 16384 MB
  • 内存以 MB 保存
  • GPU 以整数 slot 表示
  • 准入基于预留量,而不是实际使用量
  • 如果 SLOTD_CGROUP_BASE 未设置,CPU 和内存仍然只是预留值
  • 如果 SLOTD_CGROUP_BASE 指向可写的 cgroup v2 subtree,slotd 会写入 memory.maxcpu.max
  • 显式启用后如果 cgroup 设置失败,作业启动会失败,而不是静默跳过 enforcement

分区

通过环境变量配置:

  • SLOTD_CPU_PARTITIONS
  • SLOTD_GPU_PARTITIONS

规则:

  • 只接受已配置的分区名称
  • 如果没有 GPU,则不会暴露 GPU 分区
  • 如果选择了 GPU 分区且省略 --gpus,默认 GPU 请求为 1
  • 否则默认 GPU 请求为 0
  • CPU/GPU 分区是为了使用方便而划分的同一台本地主机的虚拟视图
  • CPU 和内存容量在分区之间共享,分区差异主要体现在 GPU 可见性和默认值

GPU 检测

如果没有设置 SLOTD_GPU_COUNTslotd 会尝试通过 nvidia-smi 检测 GPU。

当前实现会检查:

  • nvidia-smi
  • /usr/bin/nvidia-smi
  • /usr/lib/wsl/lib/nvidia-smi
  • /bin/nvidia-smi

作业类型

持久化记录分为以下几类:

  • 顶层 batch job
  • 仅 allocation 的 job
  • array task
  • allocation 下的 step

作业状态

已实现的状态:

  • PENDING
  • RUNNING
  • COMPLETING
  • COMPLETED
  • FAILED
  • CANCELLED
  • TIMEOUT
  • OUT_OF_MEMORY

终态:

  • COMPLETED
  • FAILED
  • CANCELLED
  • TIMEOUT
  • OUT_OF_MEMORY

调度规则

daemon 循环每 300ms 运行一次。

pending job 可能被以下条件阻塞:

  • dependency
  • array concurrency limit
  • delayed start time
  • exclusive host use
  • 预留资源不足
  • user hold state

排序规则:

  • 基础规则是提交顺序
  • 显式 job priority 可以覆盖纯提交顺序
  • array task 会按 array group 交错执行

Runtime 文件

SLOTD_ROOT 下:

  • run/slotd.sock: daemon socket
  • lib/state.db: SQLite 状态库
  • lib/jobs/<job_id>/script.sh: batch 脚本
  • lib/jobs/<job_id>/runner.sh: daemon wrapper
  • lib/jobs/<job_id>/exit_status: wrapper 退出状态

通知

如果设置了 SLOTD_NOTIFY_CMDslotd 会在顶层 job 进入终态时执行它。

导出的变量:

  • SLOTD_JOB_ID
  • SLOTD_JOB_NAME
  • SLOTD_JOB_STATE
  • SLOTD_JOB_PARTITION
  • SLOTD_JOB_REASON

sbatch 批处理作业

形式

sbatch [options] <script>
sbatch [options] --wrap '<command>'

sbatch 的作用

sbatch 会创建一个持久化的 batch job 记录,并把它提交给本地 daemon。

在 script 模式下:

  • 从磁盘读取脚本
  • 将脚本内容保存到 job 目录
  • 解析前导 #SBATCH 指令

--wrap 模式下:

  • 为命令生成一个内部 shell 脚本
  • --ntasks 大于 1 时,会按 task rank 启动一个本地进程

典型输出:

Submitted batch job 1

使用 --parsable 时:

1

主要选项

选项含义
--wrap <command>提交内联 shell 命令
-J, --job-name <name>设置作业名
-p, --partition <partition>选择分区
-c, --cpus-per-task <n>每个 task 的 CPU 数
-n, --ntasks <n>并发启动的本地 task 数量
--mem <size>请求内存,例如 512M8G
-t, --time <time>时间限制
-G, --gpus <n>请求 GPU slot 数
-o, --output <path>stdout 路径模式
-e, --error <path>stderr 路径模式
-D, --chdir <path>工作目录
--constraint <feature>要求匹配的本地 feature
-d, --dependency <spec>dependency 表达式
-a, --array <spec>array 规格
--export <spec>向作业环境导出变量
--export-file <path>从文件加载环境变量
--open-mode append|truncate选择追加或截断输出文件
--signal <spec>在超时前发送 warning signal
--begin <time>延迟作业进入可运行状态
--exclusive不与其他顶层作业共享主机
--requeue某些失败状态下只重排一次
--parsable仅输出 job ID
-W, --wait等待作业完成

默认值

未指定时:

  • cpus-per-task = 1
  • ntasks = 1
  • mem = 512M
  • partition = 已配置的默认分区
  • GPU 默认值在 GPU 分区为 1,否则为 0

#SBATCH 支持

支持的指令:

  • -J, --job-name
  • -p, --partition
  • -c, --cpus-per-task
  • -n, --ntasks
  • --mem
  • -t, --time
  • -G, --gpus
  • -o, --output
  • -e, --error
  • -D, --chdir
  • --constraint
  • --begin
  • --exclusive
  • --requeue
  • -d, --dependency
  • -a, --array

优先级:

  1. 命令行选项
  2. SBATCH_* 环境变量
  3. #SBATCH 指令
  4. 内建默认值

示例 batch script:

#!/usr/bin/env bash
#SBATCH -J script-demo
#SBATCH -p cpu
#SBATCH -c 2
#SBATCH --mem 1G
#SBATCH -t 00:05:00
#SBATCH -o logs/%j.out

echo "hello from script mode"
echo "job=$SLURM_JOB_ID cpus=$SLURM_CPUS_PER_TASK"

提交方式:

sbatch ./script-demo.sh

预期结果:

  • sbatch 会读取脚本并应用开头的 #SBATCH 指令
  • 作业会按指定的作业名、分区、CPU 数、内存和输出路径运行
  • logs/<jobid>.out 会包含脚本正文输出的内容

Dependencies

支持的 dependency 表达式:

  • after:<jobid>[,<jobid>...]
  • afterany:<jobid>[,<jobid>...]
  • afterok:<jobid>[,<jobid>...]
  • afternotok:<jobid>[,<jobid>...]
  • singleton

Arrays

支持的 array 形式:

  • 单个 ID
  • 范围,例如 0-7
  • 带步长的范围,例如 0-15:2
  • 并发限制,例如 0-31%4

示例:

sbatch -a 0-9%2 --wrap 'echo task=$SLURM_ARRAY_TASK_ID'

预期结果:

  • 会持久化多个 task 记录
  • 同一 array 同时最多运行两个 task

Delayed Start

--begin 支持:

  • epoch 秒
  • YYYY-MM-DD
  • YYYY-MM-DDTHH:MM:SS
  • now+<duration>

示例:

sbatch --begin now+00:10:00 --wrap 'echo delayed'

Requeue Once

--requeue 改变失败后的处理方式:

  • FAILED 只重排一次
  • TIMEOUT 只重排一次
  • OUT_OF_MEMORY 只重排一次
  • COMPLETED 不重排
  • CANCELLED 不重排

示例:

sbatch --requeue --wrap 'exit 1'

Output Paths

路径模式中的 token:

  • %j: job ID
  • %A: array job ID
  • %a: array task ID
  • %x: job name
  • %u: user name
  • %N: hostname
  • %%: 字面 %

默认值:

  • 非 array 的 stdout: slurm-%j.out
  • array 的 stdout: slurm-%A_%a.out
  • 如果未设置 --error,stderr 默认与 stdout 相同

Environment Export

--export 支持:

  • ALL
  • NONE
  • KEY=VALUE,...

示例:

sbatch --export FOO=bar,HELLO=world --wrap 'echo "$FOO $HELLO"'

预期结果:

  • 输出中包含 bar world

srun 交互执行

形式

srun [options] -- <command...>

srun 的行为

srun 默认以前台方式运行命令。

行为取决于你是否已经位于某个 allocation 内部:

  • 在 allocation 内部:
    • 创建一个 step 记录
    • 直接前台运行命令
  • 在 allocation 外部:
    • 创建一个类似 allocation 的顶层记录
    • 等待其可以运行
    • 创建一个 step 记录
    • 前台运行命令

只有 --no-wait 会提交一个由 daemon 管理的 run job。

--ntasks 大于 1 时,前台 srun 会在同一台主机上按 task rank 启动一个 本地进程,并导出 SLURM_PROCIDSLURM_LOCALID

主要选项

选项含义
-J, --job-name <name>设置作业名
-p, --partition <partition>选择分区
-c, --cpus-per-task <n>每个 task 的 CPU 数
-n, --ntasks <n>并发启动的本地 task 数量
--mem <size>请求内存
-t, --time <time>时间限制
-G, --gpus <n>请求 GPU slot 数
-o, --output <path>前台 stdout 输出路径
-e, --error <path>前台 stderr 输出路径
-D, --chdir <path>工作目录
--immediate如果资源不能立即可用则直接失败
--pty为 PTY 支持保留;当前会明确报错拒绝
--constraint <feature>要求匹配的本地 feature
--cpu-bind <mode>设置 CPU affinity
--label在输出前加上 <task_id>: 前缀
--unbuffered积极 flush 转发输出
--no-wait提交 daemon 管理的 run job

输出行为

示例:

srun --label --unbuffered -- echo hello

典型输出:

0: hello

CPU Binding

支持的值:

  • none
  • cores
  • map_cpu:<id,id,...>

示例:

srun --cpu-bind map_cpu:0,2 -- python train.py

Immediate Mode

--immediate 会在资源无法立即获得时直接失败,而不是等待。

示例:

srun --immediate -p gpu -G 1 -- nvidia-smi

--no-wait

--no-wait 会把 run job 提交给 daemon,而不是在前台等待。

典型输出:

Submitted run job 12

限制:

  • --label--unbuffered 不能与 --no-wait 一起使用
  • --pty 为兼容性保留并会被解析,但在真正的 PTY 路径实现之前,当前会以明确的 “not implemented yet” 错误退出

salloc 资源分配

形式

salloc [options] [command...]

salloc 的作用

salloc 会创建一个仅 allocation 的顶层 job,等待其变为可运行,然后在该 allocation 内启动一个前台命令。

如果没有提供命令,则启动你的 shell。

--ntasks 大于 1 时,前台命令会按 task rank 启动一个本地进程。

典型输出:

Granted job allocation 4

主要选项

选项含义
-J, --job-name <name>设置 allocation 名称
-p, --partition <partition>选择分区
-c, --cpus-per-task <n>每个 task 的 CPU 数
-n, --ntasks <n>并发启动的本地 task 数量
--mem <size>请求内存
-t, --time <time>时间限制
-G, --gpus <n>请求 GPU slot 数
-D, --chdir <path>工作目录
--constraint <feature>要求匹配的本地 feature
--immediateallocation 无法立即启动时直接失败

示例

salloc -p gpu -c 4 --mem 8G -G 1 -t 00:30:00

预期结果:

  • 创建一个 allocation 记录
  • 命令会等待 allocation 进入运行状态
  • 在 allocation 内启动你的 shell
  • 之后的 srun 会成为该 allocation 下的 step
  • allocation 命令会按 allocation 的 task 数执行本地 multi-task 启动

队列与记账信息

squeue

squeue 显示顶层排队作业和运行中的作业。

常用选项

选项含义
--all显示所有状态
-t, --states按状态过滤
-j, --jobs按 job ID 过滤
-u, --user按 user 过滤
-p, --partition按 partition 过滤
-o, --format选择输出字段
-S, --sort指定排序方式
-l, --long使用长格式默认视图
--start显示预计开始时间
--array显示数组风格的 job ID
--noheader省略表头

默认视图

JOBID | PARTITION | NAME | USER | ST | TIME | NODELIST(REASON)

长视图

JOBID | PARTITION | NAME | USER | ST | TIME | TIME_LIMIT | NTASKS | CPUS | REQ_MEM | REQ_GPU | NODELIST(REASON)

开始时间视图

当使用 --start 且未显式指定 format 时:

JOBID | PARTITION | NAME | USER | ST | START_TIME | NODELIST(REASON)

Format Fields

支持的字段名:

  • JobID
  • Partition
  • Name, JobName
  • User
  • ST, State
  • Time, Elapsed
  • TimeLimit, Time_Limit
  • NTasks
  • CPUS, ReqCPUS
  • ReqMem
  • ReqGPU, ReqGPUS
  • Start, StartTime
  • NodeList(Reason), NodeListReason, Reason, NodeList

支持的 % 代码:

  • %i
  • %P
  • %j
  • %u
  • %t, %T
  • %M
  • %S
  • %R, %N

sacct

sacct 显示持久化的记账数据,包括已完成的作业和 step。

常用选项

选项含义
-j, --jobs按 job ID 过滤
-s, --state按状态过滤
-S, --starttime按开始时间过滤
-E, --endtime按结束时间过滤
-u, --user按 user 过滤
-p, --partition按 partition 过滤
-o, --format选择输出字段
-P, --parsable2使用 `
-n, --noheader省略表头

默认视图

JobID | Partition | JobName | User | State | ExitCode

记录类型

sacct 包含:

  • 顶层 job
  • allocation 记录
  • step 记录
  • 已完成记录

ID 展示规则:

  • step ID 显示为 <job_id>.<step_id>
  • array task 显示为 <array_job_id>_<task_id>

Format Fields

支持的字段名:

  • JobID
  • ArrayJobID
  • ArrayTaskID
  • JobName
  • Partition
  • User
  • State
  • Reason
  • ExitCode
  • Elapsed
  • AllocCPUS
  • ReqMem
  • ReqTRES
  • AllocTRES
  • NodeList
  • Submit
  • Start
  • End
  • WorkDir
  • BatchFlag
  • MaxRSS

支持的 % 代码:

  • %i
  • %F
  • %K
  • %j
  • %P
  • %u
  • %t, %T
  • %R
  • %X
  • %M
  • %C
  • %m
  • %b
  • %B
  • %N
  • %V
  • %S
  • %E
  • %Z

作业控制

scontrol

支持的形式:

scontrol show job <job_id>
scontrol hold job <job_id>
scontrol release job <job_id>
scontrol update job <job_id> KEY=VALUE...

show job

显示详细作业信息,包括:

  • 作业标识与所有者
  • 状态与 reason
  • 请求的资源
  • 时间限制
  • dependency 字符串
  • submit、start、end 时间戳
  • command 与 working directory
  • stdout 与 stderr 路径
  • array 元数据
  • ReqTRES
  • AllocTRES
  • MaxRSS
  • step 摘要

hold job

把 pending job 移动到 held 状态。

结果:

  • job 仍保持 PENDING
  • reason 变为 JobHeldUser

release job

将 held 的 pending job 释放回正常调度。

update job

支持的更新键:

规则
JobName / Name仅能在 job 为 PENDING 时修改
Partition仅能在 job 为 PENDING 时修改
TimeLimit / Time只要 job 尚未进入终态就可以修改
Priority仅能在 job 为 PENDING 时修改

示例:

scontrol update job 10 TimeLimit=02:00:00

scancel

支持的形式:

scancel <job_id>
scancel <job_id.step_id>
scancel --signal <sig> <job_id>
scancel --signal <sig> <job_id.step_id>

默认取消行为

  • pending job 会立即变为 CANCELLED
  • running job 会先进入 COMPLETING
  • runner 会发送 SIGTERM
  • 如果需要,宽限期后再发送 SIGKILL

记录的取消原因是:

CancelledByUser

Signal 模式

--signal 只发送指定信号,而不是执行默认取消流程。

示例:

scancel --signal TERM 12

节点与分区视图

sinfo

sinfo 显示本地节点的分区与主机状态。

常用选项

选项含义
-p, --partition过滤分区
-N, --Node切换到单节点汇总视图
-l, --long使用长格式默认视图
-o, --format选择输出字段
--noheader省略表头

默认视图

典型输出:

PARTITION | HOSTNAMES | STATE | FEATURES | GRES_USED
cpu*      | localhost | idle  | cpu      | N/A
gpu       | localhost | idle  | cpu,generic_gpu | gpu:0

说明:

  • 每个已配置分区显示一行
  • 默认分区会标记为 *
  • CPU partition 的 FEATURES 只显示 cpu
  • GPU partition 的 FEATURES 显示 cpu 和检测到的 GPU 型号 feature,不显示通用 gpu
  • CPU/GPU 分区只是同一台本地主机上的便捷虚拟视图
  • CPU 和内存容量在这些分区之间共享,并不是彼此独立的资源池

节点视图

sinfo -N 会把分区行折叠为单个本地节点汇总行。

典型输出:

PARTITION | HOSTNAMES | STATE
cpu,gpu*  | localhost | idle

说明:

  • PARTITION 列会变成用逗号连接的分区列表
  • 其中默认分区仍然保留 * 标记
  • 长视图或自定义格式中的容量和分配字段会按可见分区聚合

长视图

sinfo -l 会增加容量与分配情况的细节:

PARTITION | HOSTNAMES | STATE | FEATURES | CPUS | CPU_ALLOC | MEMORY | MEM_ALLOC | GPUS | GPU_ALLOC | RUNNING | PENDING | GRES_USED

支持的格式字段

字段名:

  • Partition
  • Hostnames, Hostname, NodeList
  • State
  • Features
  • CPUS
  • CPU_ALLOC, CPUSLOAD, CPUALLOC
  • Memory, Mem
  • MEM_ALLOC, MemoryAllocated, MemAlloc
  • GPUS
  • GPU_ALLOC, GpusAllocated, GpuAlloc
  • Running, RunningJobs
  • Pending, PendingJobs
  • GRES_USED, GresUsed

支持的 % 代码:

  • %P
  • %N
  • %t, %T
  • %f
  • %G

测试

slotd 主要通过 tests/ 下的 Rust 集成测试进行验证。 每个测试都会创建一个独立的临时运行环境,启动专用 daemon,然后通过编译后的 slotd 二进制去驱动公开的 Slurm 风格命令。 因此测试不会污染你平时使用的 SLOTD_ROOT

如何运行

运行完整测试套件:

cargo test

只运行某一个集成测试文件:

cargo test --test scheduling

只运行某一个具名测试用例:

cargo test dependency_job_waits_for_prerequisite_before_running --test scheduling

当前测试覆盖内容

当前测试套件重点覆盖对使用者有影响的行为:

  • sbatchsrunsallocsinfosqueuesacctscontrol 的核心命令流程
  • 依赖、数组作业、延迟启动、constraint、resource flag、requeue 等调度规则
  • srun --pty--label--unbuffered 以及 allocation / step 等交互式与前台执行路径
  • cancellation、warning signal、update 处理、输出文件落盘等生命周期与恢复行为
  • SLOTD_NOTIFY_CMD 与 parsable 查询输出等通知和报表相关路径

有代表性的测试文件包括:

  • cli_basic.rs, sbatch_options.rs, srun.rs, srun_options.rs, srun_modes.rs, salloc.rs, sinfo.rs, control.rs, query_squeue.rs, query_sacct.rs
  • scheduling.rs, compound_scheduling.rs, dependency_variants.rs, array.rs, begin.rs, constraint.rs, resource_flags.rs, requeue.rs, timeout.rs
  • srun_interactive.rs, srun_allocation.rs, cpu_bind.rs, output_files.rs, cancellation.rs, recovery.rs, update.rs, warning_signal.rs, notify.rs

手动冒烟测试

如果只想做一次快速手动验证,可以先启动 daemon:

cargo run -- daemon

然后在另一个使用同一 SLOTD_ROOT 的 shell 中提交一个小作业:

cargo run -- sbatch --wrap 'echo hello'

示例

CPU 批处理作业

sbatch \
  -J hello \
  -p cpu \
  -c 1 \
  --mem 512M \
  -t 00:05:00 \
  -o logs/%j.out \
  --wrap 'echo hello'

预期结果:

  • Submitted batch job <id>
  • logs/<id>.out 中包含 hello

GPU 批处理作业

sbatch \
  -J gpu-demo \
  -p gpu \
  -c 4 \
  --mem 8G \
  -G 1 \
  -t 01:00:00 \
  -o logs/%j.out \
  --wrap 'nvidia-smi'

预期结果:

  • 作业会在 GPU 分区运行
  • 输出中包含 nvidia-smi 信息

交互式前台运行

srun --label --unbuffered -- echo hello

预期结果:

0: hello

交互式 allocation

salloc -p gpu -c 4 --mem 8G -G 1 -t 00:30:00

预期结果:

  • Granted job allocation <id>
  • 在 allocation 内启动一个 shell

Array Job

sbatch \
  -J array-demo \
  -a 0-9%2 \
  -o logs/%A_%a.out \
  --wrap 'echo task=$SLURM_ARRAY_TASK_ID'

预期结果:

  • 会创建多个 task 记录
  • 生成类似 logs/<array_id>_0.out 的日志文件

单次 Requeue

sbatch --requeue --wrap 'exit 1'

预期结果:

  • 第一次失败后作业回到 PENDING
  • 第二次失败后最终状态为 FAILED

延迟启动

sbatch --begin now+00:10:00 --wrap 'echo delayed'

预期结果:

  • 作业会在 begin 时间之前保持 pending
  • squeue --start 会显示未来的开始时间

显式导出环境变量

sbatch \
  --export FOO=bar,HELLO=world \
  --wrap 'echo "$FOO $HELLO"'

预期结果:

  • 输出中包含 bar world

手动运行 daemon

SLOTD_ROOT="$HOME/.local/share/slotd" ./target/release/slotd daemon

然后在另一个 shell 中执行:

SLOTD_ROOT="$HOME/.local/share/slotd" ./target/release/slotd sbatch --wrap 'echo hello'

故障排查

Connection refused

症状:

error: io error: Connection refused (os error 111)

含义:

  • client 找到了 socket 路径
  • 但该路径上当前没有 daemon 在接受连接

检查项:

  • daemon 是否真的在运行
  • client 与 daemon 是否使用相同的 SLOTD_ROOT
  • 是否残留了旧运行产生的过期 socket 文件

有用的检查命令:

ls -l "$SLOTD_ROOT/run/slotd.sock"
sinfo

Runtime Root 不一致

如果 daemon 使用一个 runtime root,而 client 使用另一个,命令看起来会随机失败。

常见原因:

  • daemon 由 systemd --user 启动
  • client 从一个没有相同 SLOTD_ROOT 的 shell 中启动

最稳妥的修复方式:

  • 使用 scripts/install.sh 安装
  • 使用 ~/.local/bin 下的 wrapper 命令

看不到 GPU 分区

如果 sinfo 只显示 cpu,请检查:

  • nvidia-smi 是否在 daemon 环境中可用
  • SLOTD_GPU_PARTITIONS 是否按预期配置
  • 修改 GPU 配置后是否已经重启 daemon

手动检查:

nvidia-smi
sinfo

重装时出现 Text file busy

安装脚本现在会以原子方式替换二进制。如果仍然遇到问题:

  • 停止或重启 daemon
  • 再次运行安装脚本

命令:

systemctl --user restart slotd.service
./scripts/install.sh

作业一直处于 PENDING

可能原因:

  • 资源不足
  • dependency 未满足
  • array 并发限制
  • 尚未到达 delayed start time
  • 作业处于 held 状态
  • 已有 exclusive job 正在运行

排查方式:

squeue
scontrol show job <job_id>

cgroup 设置失败

如果设置了 SLOTD_CGROUP_BASE,但它并不是可写的 cgroup v2 subtree,作业启动会 直接以明确的 cgroup error 失败。

检查:

  • 该路径在 daemon 环境中确实存在
  • 它是 cgroup v2 subtree,而不是普通目录或文件
  • daemon 用户可以在其中创建每个作业的子目录并写入 control file

作业被取消但最终状态是 OUT_OF_MEMORY

如果在终止过程中 cgroup 内存事件表明发生了 OOM,最终状态可能优先记录为 OUT_OF_MEMORY

找不到输出文件

请检查:

  • 作业的 working directory
  • -o/--output-e/--error 路径
  • %j%A_%a 等模式展开

排查命令:

scontrol show job <job_id>