--- name: hpc-slurm description: >- 当用户需要向 Slurm 集群提交计算作业,说"提交集群任务""写个 sbatch 脚本""作业还在排队吗""批量跑一组参数""作业超时被杀了""GPU 作业怎么交"时使用。本技能规定 Slurm 集群的统一操作规程:sbatch 脚本模板(分区/时长/内存/GPU 指令 + set -euo pipefail + 环境导出 + 结束自动 rsync 产物)、squeue/sacct 状态查询口径、数组任务批量提交、超时与重排队策略、产物抓回与 record_run 登记。同义触发场景:Slurm、HPC、集群、超算、排队、批处理、job array、机时。连接与主机认知纪律沿用 remote-compute(别名、画像合同),本技能只规定作业生命周期。 argument-hint: '[作业描述或作业号]' metadata: domains: [compute] last_reviewed: '2026-08-19' --- # hpc-slurm:Slurm 集群作业规程 ## 目的 Slurm 集群的算力是排队共享的:脚本写错浪费机时,资源虚报挤占同门队列,作业跑完不抓回等于没跑。本技能规定作业生命周期的五个环节: 1. 提交前:脚本模板化,资源申请有依据; 2. 队列中:状态查询口径统一,不盲目刷屏; 3. 批量时:数组任务替代循环提交; 4. 异常时:超时与失败有明确的重排队策略; 5. 完成后:产物自动 rsync 抓回 + record_run 登记。 **前置约束**:连接一律走 remote-compute 的别名与 ControlMaster 纪律;目标主机的分区、GPU、配额信息以 `.openscience/hosts/.yaml` 画像为准——画像没有的信息(如分区名)先探测(`sinfo`)再写进脚本,不臆造。 ## 前置检查 1. 画像 `scheduler: slurm` 已确认;画像缺失或过期时先按 remote-compute 第 2 节探测。 2. 查可用分区与节点:`ssh 'sinfo -o "%P %a %l %D %N"'`,把目标分区、单作业时长上限写进画像 notes。 3. 提交计算作业消耗机时与队列资源,属 guardrail 第 8 条危险操作:**首次提交前向用户说明作业规模(核数、时长、分区、预计机时)并获得确认**;数组任务说明总任务数。 4. 数据与代码已同步到远程(rsync 上传),脚本内路径全部是远程路径。 ## 1 · sbatch 脚本模板 作业脚本放本地 `scripts/slurm/.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 # -.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/" ":<工作区路径>/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 'squeue -u $USER' # 在队作业:R=运行 PD=排队 ssh 'sacct -j --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 :~/runs/-/ results/-/ python <插件包路径>/skills/provenance-record/scripts/record_run.py \ --path results/-/ \ --tool "slurm job (.sbatch)" \ --note "分区

,8 核 32G 1×GPU,实际耗时 ,ExitCode 0:0,节点 " ``` 不记录的运行等于不存在: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 - \ --tag slurm --tag \ --cmd "ssh 'sacct -j --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 ` 让 `run_task list` 把集群作业与本地任务一眼分开;多集群、多作业并发时按 tag 认作业,不靠记忆。补充背景(分区、资源、预计时长)用 `--note` 写一句。 4. **终态与抓回纪律不变**:sacct 显示 COMPLETED/FAILED/TIMEOUT 后,产物抓回与 record_run 登记仍按第 5 节执行,一个字不改;Run 替代的是"人机空等",不替代 provenance。 ## 输出模板 ```markdown ## Slurm 作业已提交( @ ) - jobid:,分区:

,资源:<核/内存/GPU/时长> - 预计排队:;查询:ssh 'squeue -j ' - 完成后:自动 rsync 至 results/-/ 或按第 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,形成可追溯的试错链。