# Hpc Slurm

> 当用户需要向 Slurm 集群提交计算作业，说"提交集群任务""写个 sbatch 脚本""作业还在排队吗""批量跑一组参数""作业超时被杀了""GPU 作业怎么交"时使用。本技能规定 Slurm 集群的统一操作规程：sbatch 脚本模板（分区/时长/内存/GPU 指令 + set -euo pipefail + 环境导出 + 结束自动 rsync 产物）、squeue/sacct 状态查询口径、数组任务批量提交、超时与重排队策略、产物抓回与 record_run 登记。同义触发场景：Slurm、HPC、集群、超算、排队、批处理、job array、机时。连接与主机认知纪律沿用 remote-compute（别名、画像合同），本技能只规定作业生命周期。

- Skill: `minimax-ai/hpc-slurm` (Agent Skill)
- Install (CLI): `npx skillmds@latest add minimax-ai/hpc-slurm`
- Raw SKILL.md: https://api.skillmd.com/api/skills/minimax-ai/hpc-slurm/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: MiniMax AI (https://skillmd.com/u/minimax-ai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/minimax-ai/hpc-slurm

---


# hpc-slurm：Slurm 集群作业规程

## 目的

Slurm 集群的算力是排队共享的：脚本写错浪费机时，资源虚报挤占同门队列，作业跑完不抓回等于没跑。本技能规定作业生命周期的五个环节：

1. 提交前：脚本模板化，资源申请有依据；
2. 队列中：状态查询口径统一，不盲目刷屏；
3. 批量时：数组任务替代循环提交；
4. 异常时：超时与失败有明确的重排队策略；
5. 完成后：产物自动 rsync 抓回 + record_run 登记。

**前置约束**：连接一律走 remote-compute 的别名与 ControlMaster 纪律；目标主机的分区、GPU、配额信息以 `.openscience/hosts/<alias>.yaml` 画像为准——画像没有的信息（如分区名）先探测（`sinfo`）再写进脚本，不臆造。

## 前置检查

1. 画像 `scheduler: slurm` 已确认；画像缺失或过期时先按 remote-compute 第 2 节探测。
2. 查可用分区与节点：`ssh <alias> 'sinfo -o "%P %a %l %D %N"'`，把目标分区、单作业时长上限写进画像 notes。
3. 提交计算作业消耗机时与队列资源，属 guardrail 第 8 条危险操作：**首次提交前向用户说明作业规模（核数、时长、分区、预计机时）并获得确认**；数组任务说明总任务数。
4. 数据与代码已同步到远程（rsync 上传），脚本内路径全部是远程路径。

## 1 · sbatch 脚本模板

作业脚本放本地 `scripts/slurm/<job-name>.sbatch`（纳入工作区管理），模板：

```bash
#!/bin/bash
#SBATCH --job-name=cycle-fit        # 短而可读，squeue 里认得出
#SBATCH --partition=gpu             # 以画像/sinfo 为准，不臆造分区名
#SBATCH --time=08:00:00             # 预留 20-50% 余量，不写分区上限
#SBATCH --mem=32G
#SBATCH --cpus-per-task=8
#SBATCH --gres=gpu:1                # 无 GPU 作业删掉此行；型号需求以画像 gpu_summary 为准
#SBATCH --output=%x-%j.out          # <job-name>-<jobid>.out，便于归档
#SBATCH --error=%x-%j.err

set -euo pipefail                   # 任何命令失败立即终止作业，不带着错误继续跑

# ---- 环境导出（三选一，与画像 notes 中该集群的习惯一致）----
# module load cuda/12.2 anaconda/2024.02 && source activate myenv
# source "$HOME/.venv/bin/activate"
export PYTHONUNBUFFERED=1           # 日志实时可见，便于中途检查

# ---- 任务本体 ----
JOB_DIR="$HOME/runs/${SLURM_JOB_NAME}-${SLURM_JOB_ID}"
mkdir -p "$JOB_DIR"
cd "$JOB_DIR"
python3 "$HOME/code/analyze_cycle.py" --seed 42 --out "$JOB_DIR"

# ---- 结束自动 rsync 产物回本地工作区 ----
# 仅在登录节点可反向访问本地时可用；多数集群不通，改用完成后手动抓回（第 5 节）
rsync -avz "$JOB_DIR/" "<local-alias>:<工作区路径>/results/${SLURM_JOB_NAME}-${SLURM_JOB_ID}/" \
  || echo "WARN: auto rsync failed, fetch manually" >&2

echo "JOB_DONE $(date -Is)"
```

模板纪律：

1. `set -euo pipefail` 不可省：没有它，中间步骤失败后作业继续跑，产出半截结果还显示"完成"。
2. 资源申请按画像与实际需求填，不虚报（虚报挤占队列、拖长全组排队），也不少报（OOM/超时被杀浪费机时）。
3. 产物目录名带 `${SLURM_JOB_ID}`，同一脚本多次提交互不覆盖。
4. 环境导出让作业自包含：不依赖登录节点的交互式 shell 状态。

## 2 · 状态查询：squeue / sacct

统一口径，避免凭印象判断：

```bash
ssh <alias> 'squeue -u $USER'                      # 在队作业：R=运行 PD=排队
ssh <alias> 'sacct -j <jobid> --format=JobID,JobName,State,Elapsed,MaxRSS,ExitCode'
```

解读要点：

1. `PD`（排队）看 `squeue` 的 `NODELIST(REASON)`：`Resources`/`Priority` 是正常排队；`ReqNodeNotAvail` 等多为资源请求超分区配置，应改脚本而不是干等。
2. 作业结束后一律 `sacct` 确认 `State` 与 `ExitCode`：`COMPLETED` + `0:0` 才算成功；`TIMEOUT`/`OUT_OF_MEMORY` 按第 4 节处理。
3. 不轮询刷屏：查询间隔不低于分钟级；长作业用 run-monitor 思路"提交后离开，定期回来查"，不让人机空等。

## 3 · 批量作业：数组任务

同脚本多参数（多 seed、多数据分片）一律用 job array，禁止 for 循环逐条 sbatch：

```bash
#SBATCH --array=0-99%10            # 100 个任务，最多同时 10 个（%10 限制并发，别挤爆队列）

python3 "$HOME/code/analyze.py" --seed "$SLURM_ARRAY_TASK_ID" \
    --out "$HOME/runs/${SLURM_JOB_NAME}-${SLURM_ARRAY_JOB_ID}/task-${SLURM_ARRAY_TASK_ID}"
```

纪律：

1. 每个数组元素产物独立目录（带 task id），互不覆盖；
2. 首次跑大批量前先用 `--array=0-2` 小规模试跑，确认单任务资源估算正确，再提交全量；
3. 抓回时按 `${SLURM_ARRAY_JOB_ID}` 整目录 rsync，record_run 一条登记、note 写数组范围与失败元素。

## 4 · 超时与重排队策略

1. **TIMEOUT**：先查日志判断是"差一步"还是"差很远"。差一步：加大 `--time` 重交；差很远：检查是否有死循环或规模估计错误，修复后重交。同一作业连续两次 TIMEOUT 不得原样重交，必须先改东西。
2. **OUT_OF_MEMORY**：按 `sacct` 的 `MaxRSS` 实测值上调 `--mem`（留 20% 余量）重交。
3. **FAILED（非零退出）**：读 `.err` 定位，修复后重交；失败作业同样登记 provenance（paths 指向抓回的日志）。
4. **可断点续算的任务**：脚本内支持 checkpoint（存在则续跑），超时重交即自动续算；长任务优先设计成可续算的。
5. 重排队是新的资源消耗：批量重交前向用户说明失败原因与新增机时。

## 5 · 产物抓回与 record_run

自动 rsync（模板末尾）不通时，完成后手动抓回：

```bash
rsync -avz <alias>:~/runs/<job-name>-<jobid>/ results/<job-name>-<jobid>/
python <插件包路径>/skills/provenance-record/scripts/record_run.py \
  --path results/<job-name>-<jobid>/ \
  --tool "slurm job <jobid> (<job-name>.sbatch)" \
  --note "分区 <p>，8 核 32G 1×GPU，实际耗时 <Elapsed>，ExitCode 0:0，节点 <NodeList>"
```

不记录的运行等于不存在：note 里作业号、sacct 的 Elapsed/ExitCode/NodeList 缺一不可；远程环境版本（`module list` 摘要）有条件就附在 note 或抓回的日志里。

## 6 · 经 run_task 登记 Slurm 作业

sbatch 提交成功、拿到 jobid 后，立即把"盯这个作业"登记成一个本地 Run——用 run-monitor 的 Run 抽象统一管理本地与远程长任务：Run 只记录"任务叫什么、怎么查状态、查到了什么"，不关心任务跑在本机还是集群：

```bash
python <插件包路径>/skills/run-monitor/scripts/run_task.py \
  start --name <job-name>-<jobid> \
  --tag slurm --tag <cluster> \
  --cmd "ssh <alias> 'sacct -j <jobid> --format=State -n | head -1'"
```

模式说明：

1. **登记即交还**：start 把这条状态查询命令放到后台执行并立即返回，会话不空等；run.json 的 cmd 字段留下"当时用哪条命令查的"，口径与第 2 节一致，tags 与 note 一并落盘。
2. **轮询即重跑**：想看最新状态时同名再 start 一次（已 exited 的 run 允许被新 start 覆盖，日志随之重写），然后 `tail` 看这次查到的 State；查询间隔不低于分钟级的纪律不变，不写忙等循环。
3. **tags 即检索口径**：`--tag slurm --tag <cluster>` 让 `run_task list` 把集群作业与本地任务一眼分开；多集群、多作业并发时按 tag 认作业，不靠记忆。补充背景（分区、资源、预计时长）用 `--note` 写一句。
4. **终态与抓回纪律不变**：sacct 显示 COMPLETED/FAILED/TIMEOUT 后，产物抓回与 record_run 登记仍按第 5 节执行，一个字不改；Run 替代的是"人机空等"，不替代 provenance。

## 输出模板

```markdown
## Slurm 作业已提交（<job-name> @ <alias>）

- jobid：<id>，分区：<p>，资源：<核/内存/GPU/时长>
- 预计排队：<squeue 观察>；查询：ssh <alias> 'squeue -j <id>'
- 完成后：自动 rsync 至 results/<job-name>-<id>/ 或按第 5 节手动抓回 + record_run
```

## 本技能不做什么

- 不探测主机与管连接：别名、ControlMaster、画像合同、失败分支一律沿用 remote-compute，本文件不重复。
- 不保证队列策略最优：分区选择、机时估计给建议，最终以用户所在集群的实际规定（画像 notes）为准。
- 不自动 kill 作业：`scancel` 只建议不执行，除非用户当场明确确认（影响共享队列状态）。
- 不管非 Slurm 调度器：PBS/LSF 语法不同，本规程不套用；画像 scheduler 非 slurm 时按 remote-compute 的交互式方案。
- 不替用户盯梢：提交后告知查询命令即交还控制权，长周期作业由用户按节奏回来查（或按第 6 节用 run_task 登记）。

## 收尾与下一步

- 作业成功后：确认 rsync 完成、record_run 已登记、产物按契约归位（latest 刷新）。
- 批量作业：核对数组元素完整性（100 个任务 100 个产物目录），缺的按第 4 节补交。
- 结论进论文前：sbatch 脚本 + sacct 摘要 + 产物一并进 evidence-capsule 冻结。
- 作业失败：登记失败记录后诊断，诊断结论写进下一条 provenance note，形成可追溯的试错链。

