Claude Codeでsacct出力からSlurmのOOMとTIMEOUTを切り分ける
Slurmで落ちたジョブをsacctのState・Elapsed・Timelimit・MaxRSS・ReqMemで切り分け、claude -pに表を渡してsbatchのリソース指定を直す手順です。
Slurmのジョブが落ちたとき、手がかりが一番まとまっているのは sacct の出力です。State が OUT_OF_MEMORY なのか TIMEOUT なのか NODE_FAIL なのかで、直す場所が変わります。メモリなら --mem、時間なら --time、ノード障害ならジョブ側は直さずに再投入です。
Claude Codeに任せるなら、sacct の表を claude -p に渡して「どの型か」と「次の sbatch 指定」を聞く形が扱いやすい構成です。この記事は、渡す列の選び方、型ごとの見分け方、プロンプトの組み方の順に並べます。
sacctは「どの型で落ちたか」をStateで答える
State 列は、ジョブの状態を表します。落ちたジョブで見るのは次の4つです。
| State | 意味 | 直す場所 |
|---|---|---|
| OUT_OF_MEMORY | 意味ジョブがメモリ不足のエラーを起こした | 直す場所メモリ要求 |
| TIMEOUT | 意味制限時間に達して終了した | 直す場所時間要求、または処理の速度 |
| NODE_FAIL | 意味割り当てノードの障害で終了した | 直す場所ジョブは直さず再投入 |
| FAILED | 意味0以外の終了コードなどで終了した | 直す場所コードかスクリプト |
DEADLINE(締め切りで終了)や CANCELLED(ユーザーか管理者が取り消した)も別の状態として並びます。CANCELLED は「誰が」取り消したかの情報が + 付きで続くことがあり、幅が足りなければ %NUMBER の書式で State 列を広げられます。
ここで注意したいのは、FAILED を「メモリ不足かもしれない」と読まないことです。メモリ不足を明示する状態が OUT_OF_MEMORY として別にあるので、FAILED の原因は終了コードとログに戻って探します。
落とし穴
-Xを付けるとMaxRSSが0になる
-X(--allocations)はジョブ全体の行だけを出すオプションです。ステップを数えないため、使用量の統計は0として報告されます。MaxRSS を見たいときは -X を外します。
判別に使う列を5〜6本に絞る
sacct -o に渡す列は絞るほどClaudeが読み違えにくくなります。型の判別には次の列があれば足ります。
JobID: ジョブとステップを区別する(1234、1234.batch、1234.0)State: 上の4型の判定Elapsed: 実際の実行時間Timelimit: 要求した制限時間ReqMem: 要求したメモリ。末尾にMやGが付くMaxRSS: ジョブ内の全タスクの最大常駐メモリExitCode:終了コード:シグナル番号の形式NodeListとFailedNode: ノード障害の切り分け
ReqMem は注意が要ります。この値はジョブの割り当てから取られ、ステップのものではありません。MaxRSS はステップ行に出ます。つまり、同じジョブの ReqMem と MaxRSS は別の行に分かれて表示され、比べるには両方の行を並べて読む必要があります。
sacct -j 1234,1235,1236 -P \
-o JobID,State,Elapsed,Timelimit,ReqMem,MaxRSS,ExitCode,NodeList-P(--parsable2)は列を | 区切りで、行末の | なしで出します。空白で揃えた表よりも、プロンプトに渡したときに列がずれません。-n を足すと見出し行が消えますが、Claudeに渡すときは見出しを残すほうが列の意味を取り違えません。
-j を指定すると、--starttime の既定が最古(Epoch 0)になります。-j も --state も付けない場合は、既定の検索範囲が当日の0時から現在までです。昨日落ちたジョブを -j なしで探すと、何も出ません。その場合は -S で開始時刻を指定します。
出力の読み方: 型ごとの見分け
次は、読み方を示すために作った出力の例です(実在のクラスタの出力ではありません)。
JobID|State|Elapsed|Timelimit|ReqMem|MaxRSS|ExitCode|NodeList
1234|OUT_OF_MEMORY|00:41:12|04:00:00|16G||0:0|node012
1234.batch|OUT_OF_MEMORY|00:41:12|||15980M|0:0|node012
1235|TIMEOUT|04:00:00|04:00:00|16G||0:0|node031
1235.batch|CANCELLED|04:00:03|||6210M|0:0|node031
1236|NODE_FAIL|01:12:44|04:00:00|16G||0:0|node0441234は MaxRSS が ReqMem に近い値で終わっています。OUT_OF_MEMORY の状態と合わせて読み、メモリ要求を増やす候補になります。
1235は Elapsed が Timelimit と一致しています。TIMEOUT の典型で、MaxRSS は ReqMem に遠いので、メモリは原因ではありません。例のようにステップ行が CANCELLED と出ることもあるので、判定はジョブ行の State で行います。
1236は NODE_FAIL で、Elapsed は制限時間に達していません。ジョブ側の問題ではないので、FailedNode 列で障害ノードを確かめ、そのまま再投入する判断になります。
落ちたジョブの切り分け順
- QState は OUT_OF_MEMORY ですか?答えが次へ答えがはい
MaxRSSとReqMemを比べ、--memを増やします。 - QState は TIMEOUT ですか?答えが次へ答えがはい
ElapsedとTimelimitが同じなら、--timeを延ばすか、処理を速くします。 - QState は NODE_FAIL ですか?答えが次へ答えがはい
FailedNodeを控えてそのまま再投入します。
上のどれでもない
FAILED や CANCELLED は ExitCode とジョブのログに戻って探します。
claude -pに表を渡して判定させる
表は短いので、標準入力から渡せます。claude -p は標準入力を読み、パイプで渡したデータに対して答えます。
sacct -j 1234,1235,1236 -P \
-o JobID,State,Elapsed,Timelimit,ReqMem,MaxRSS,ExitCode \
| claude -p --bare "$(cat slurm-triage-prompt.txt)"ここで --bare を付ける点に意味があります。--bare は、フックやスキル、MCPサーバー、自動メモリー、CLAUDE.md の自動読み込みを飛ばして起動を速くし、スクリプト用途で推奨されるモードです。逆に言えば、CLAUDE.md に書いた判定ルールはこの呼び出しでは読まれません。ルールは slurm-triage-prompt.txt のようにプロンプト側へ置きます。
プロンプトの中身は、判定の規則と出力形式だけにします。
標準入力は sacct -P の出力です。ジョブ(JobID に . が無い行)ごとに、
次のどれか1つに分類してください。
- OOM: State が OUT_OF_MEMORY。MaxRSS と ReqMem を比べて増やす量を示す
- TIMEOUT: State が TIMEOUT。Elapsed と Timelimit を示す
- NODE_FAIL: State が NODE_FAIL。再投入でよいと書く
- OTHER: 上のどれでもない。ExitCode だけ示す
表に無い値は推測せず「不明」と書く。出力は1ジョブ1行。「表に無い値は推測しない」の一文は、MaxRSS が空のジョブ行を見たときの暴走を防ぎます。-X で取った表を渡すと MaxRSS が0になるので、Claudeが「メモリは使っていない」と読み違える危険があります。上の見出しの注意と同じ理由で、-X なしで渡します。
結果をスクリプトで受ける
分類結果を後続の処理に流すなら、--output-format json が使えます。応答に result フィールドが入り、jq -r '.result' で本文だけを取り出せます。コストは応答の total_cost_usd に含まれます(クライアント側の推定値で、請求額とずれることがあります)。
sacct -j 1234,1235,1236 -P \
-o JobID,State,Elapsed,Timelimit,ReqMem,MaxRSS,ExitCode \
| claude -p --bare --output-format json "$(cat slurm-triage-prompt.txt)" \
| jq -r '.result'標準入力の上限は10MBです。数千ジョブの sacct を丸ごと渡すより、-S と --state で対象を落ちたジョブに絞ってから渡すほうが、上限に収まり、判定も安定します。
sacct -S 2026-10-27 -E 2026-10-28 \
--state=OUT_OF_MEMORY,TIMEOUT,NODE_FAIL -P \
-o JobID,State,Elapsed,Timelimit,ReqMem,MaxRSS,ExitCode検索期間のずれと、sacctを呼ぶ回数
sacct は、-j と --state のどちらを付けるかで既定の検索期間が変わります。
| 指定 | 開始時刻の既定 | 終了時刻の既定 |
|---|---|---|
| どちらも無し | 開始時刻の既定当日の0時 | 終了時刻の既定現在 |
-j のみ | 開始時刻の既定最古(Epoch 0) | 終了時刻の既定現在 |
--state のみ | 開始時刻の既定現在 | 終了時刻の既定開始時刻(開始も無ければ現在) |
| 両方 | 開始時刻の既定最古(Epoch 0) | 終了時刻の既定開始時刻(開始も無ければ現在) |
--state だけを付けて -S を忘れると、開始が現在になって何も返りません。「落ちたジョブが無い」と読ませてしまうと誤判定になります。-v を付けると、実際に使われた時間窓が表示されます。
もう1つ、sacctのマニュアルは、シェルスクリプトのループから何度も呼ばないよう求めています。呼び出しはslurmdbdへのRPCになり、集中すると性能低下やサービス拒否に至る可能性があるためです。ジョブごとに sacct を呼んでClaudeに渡す書き方は避け、-j にIDのカンマ区切りを渡して1回で取ります。
ReqMem と MaxRSS の単位がそろわないときは、--units=G で表示を統一できます。ReqMem の末尾には M や G の単位文字が付くため、列ごとに単位が違うまま渡すと、比較のときに桁を読み違える元になります。
ジョブのログも読ませるときの権限
sacct の表だけなら、Claudeにツールを渡す必要はありません。標準入力で全部足ります。ジョブの標準出力ファイルまで読ませたいなら、--allowedTools "Read" で読み取りだけを許します。
claude -p --bare --allowedTools "Read" \
"slurm-1234.out の末尾を読み、メモリ不足の兆候があるか答えて"Bash や Edit まで許すと、Claudeが sbatch スクリプトを書き換えたり、sbatch を実行して再投入したりできる状態になります。再投入は共有クラスタの割り当てを消費する操作です。提案までをClaudeに任せ、実行は人が確かめてから行う分担にすると、取り返しのつかない操作を避けられます。
無人で回す場合は --permission-prompts none を付けると、許可の確認が必要な呼び出しは拒否され、Claudeは再試行しません(v2.1.259以降)。
直し方の目安: 値を決めるのは実測
OOMの修正で、--mem を倍にして終わらせたくなる場面があります。ただし判断材料は表にあります。
MaxRSSがReqMemにほぼ届いている: 要求が足りない。実測値に余裕を足した量を要求するMaxRSSがReqMemよりずっと小さいのにOUT_OF_MEMORY: 表だけでは説明がつかない。計測の仕組みはクラスタの設定に依存するので、管理者に確かめる
2つ目はsacctの仕様ではなく、表を読むときの注意点です。Claudeにも「説明がつかないときは不明と答える」と指示しておくと、無理な数字の提案を避けられます。
例の1234と1235をsbatchの指定に直す
先ほどの例を sbatch のスクリプトに戻すと、書き換える行は次の2か所です。値はこの例の数字から作った一例で、余裕の幅はジョブの性質とクラスタの上限で決まります。
OOMの1234: 要求メモリを実測の上へ
修正前(ReqMem 16G、MaxRSS 15980M)
#SBATCH --mem=16G修正後(実測に余裕を足した例)
#SBATCH --mem=24GMaxRSS の15980Mは16Gのほぼ全量で、要求が足りなかったことを示します。実測の少し上ではなく、データ量が増えたときの伸びも見込める値にするかは、ジョブごとに判断します。
TIMEOUTの1235: 制限時間を延ばす場合
修正前(Timelimit 04:00:00、Elapsed 04:00:00)
#SBATCH --time=04:00:00修正後(延ばした例)
#SBATCH --time=06:00:00時間を延ばすのは、ログの進捗行で「終わりに近づいていた」と確かめられたときの選択肢です。進捗が止まっていたなら、--time を延ばしても同じ時間だけ無駄に走ります。この場合はジョブの中身を直します。
Claudeに修正案まで出させるときは、プロンプトの末尾に「#SBATCH --mem または --time の変更案を1行で添え、根拠にした列名を書く」と足します。根拠の列を書かせると、MaxRSS が空の行から数字を作る誤りを見つけやすくなります。
MaxRSS と ReqMem の単位は、--units=G を足すとそろえて表示できます。
sacct -j 1234 -P --units=G \
-o JobID,State,Elapsed,Timelimit,ReqMem,MaxRSSこの表では、ステップ行(1234.batch)の MaxRSS と親行の ReqMem を同じ単位で並べて比べられます。
TIMEOUTも同じで、Elapsed が Timelimit と一致していても、「あと少しで終わる処理」と「無限に回っている処理」は区別できません。ログの進捗行を一緒に読ませて、判断してもらいます。同じ考え方は、分散学習のNCCL timeoutでランクごとのログの最終行を並べる手順にも出てきます。Claude Code torchrun NCCLのtimeoutを追うは、止まった原因を作った側を探す流れです。
コンテナ上のメモリ不足なら、SIGKILLで終わる exit code 137 の見分け方が近い題材です。Claude Codeでexit code 137のOOMを切り分ける手順では、docker inspect の OOMKilled とカーネルログを突き合わせます。Slurmでは State の OUT_OF_MEMORY がその役を担います。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。