slurm-job-script-generator について
HPC利用者向けに、SLURMのジョブスクリプトを生成し、リソース設定のよくある誤りを検査するスキルです。入力を検証し、CPU・GPUの割り当てを算出して、投入前に警告を示します。
主な機能
- 01.sbatchジョブスクリプトの生成
- 02実行時間とメモリ指定の検査
- 03タスクとGPU配置の算出
- 04過剰割り当てとランチャー競合の警告
- 05コマンドライン入力の検証
活用シーン
- 01MPIまたはMPI+OpenMPシミュレーション用スクリプトの作成
- 02競合するメモリ指定の確認
- 03投入前のタスク・GPU配置の確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ heshamfs/ materials-simulation-skills --skill slurm-job-script-generatorインストール後、Claude Code で/slurm-job-script-generatorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
CHANGELOG.mdevals/evals.jsonreferences/slurm_directives.mdscripts/slurm_script_generator.py詳細
SLURM ジョブスクリプトジェネレーター
目標
シミュレーションを実行するための、正しくそのままコピーして使える SLURM ジョブスクリプト(.sbatch)を生成し、よくある設定ミス(不正なウォールタイムの形式、競合するメモリ指定、過剰割り当てのヒント)を提示します。
要件
- Python 3.10+
- 外部依存関係なし(Python 標準ライブラリのみ)
- Linux、macOS、Windows で動作します(スクリプトの生成のみ)
収集する入力
| 入力 | 説明 | 例 |
|---|---|---|
| ジョブ名 | ジョブの短い識別子 | phasefield-strong-scaling |
| ウォールタイム | SLURM の時間制限 | 00:30:00 |
| パーティション | クラスタのパーティション/キュー(必要な場合) | compute |
| アカウント | プロジェクト/アカウント(必要な場合) | matsim |
| ノード数 | 割り当てるノード数 | 2 |
| MPI タスク数 | 合計タスク数、またはノードあたりのタスク数 | 128 またはノードあたり 64 |
| スレッド数 | タスクあたりの CPU 数(OpenMP スレッド数) | 2 |
| メモリ | --mem または --mem-per-cpu(クラスタのポリシーによります) | 32G |
| GPU 数 | ノードあたりの GPU 数(任意) | 4 |
| 作業ディレクトリ | 実行するディレクトリ | $SLURM_SUBMIT_DIR |
| モジュール | 読み込む環境モジュール(任意) | gcc/12、openmpi/4.1 |
| 実行コマンド | SLURM で実行するコマンド | ./simulate --config cfg.json |
判断の指針
MPI と MPI+OpenMP のレイアウト
Does the code use OpenMP / threading?
├── NO → Use MPI-only: cpus-per-task=1
└── YES → Use hybrid: set cpus-per-task = threads per MPI rank
and export OMP_NUM_THREADS = cpus-per-task
経験則: MPI ランク数が多い場合に強スケーリング効率の低下が見られるなら、ランク数を減らしてランクあたりのスレッド数を増やし、計測してみてください。
メモリフラグの選択
--mem(ノードあたり)または--mem-per-cpu(CPU あたり)のどちらか一方を使い、両方は使わないでください。- クラスタのドキュメントに従ってください。サイトによっては、どちらか一方の形式しか許可されません。
- SLURM の
--memの単位は、既定では整数の MB です。または、接尾辞K/M/G/Tを付けた整数を指定します(--mem=0は一般に「ノード上のすべてのメモリ」を意味します)。
ランチャーの選択(二重ラップを回避)
- 既定では(
--launcher srun)、ジェネレーターは実行コマンドの前にsrun --ntasks=N --cpus-per-task=Tを付加し、SLURM のタスク配置を継承します。 - 実行コマンドがすでに
srun、mpirun、またはmpiexecで始まっている場合は、--launcher noneを渡してください。 ジェネレーターによる二重ラップを防げます。srunでmpirunをラップすると、独立したmpirunが N 個起動し、それぞれが独自の MPI ワールドを生成します。srunをsrunでラップするのは不正な形式です。 - 安全策として、ジェネレーターは先頭のランチャー(
srun、mpirun、mpiexec、mpiexec.hydra、orterun、aprun、jsrun)を自動検出してラップなしに切り替え、--launcher noneを推奨する警告を出します。
GPU レイアウト
- GPU あたりのランク数 =
total_ranks / (nodes * gpus_per_node)。--gpus-per-nodeが設定されている場合、ジェネレーターはresults.derived.total_gpusとresults.derived.ranks_per_gpuを報告します。 - ランクをデバイスに均等に割り当てることを目指してください。
ntasksが GPU の合計数で割り切れない場合、ジェネレーターは「タスクと GPU の比率が整数ではありません」という警告を出します。ntasks/GPU 数を調整するか、意図的な共有(NVIDIA MPS など)について説明を記載してください。 --gpu-bind=closestや--ntasks-per-gpuなどのバインドオプションを検討してください(実行コマンドまたは--srun-extraで渡します)。GPU と QoS のポリシーはサイトごとに異なるため、クラスタのドキュメントで確認してください。
スクリプトの出力(JSON フィールド)
| スクリプト | 主な出力 |
|---|---|
scripts/slurm_script_generator.py | results.script、results.directives、results.derived、results.warnings、results.run_line |
results.derived は ntasks、ntasks_per_node、cpus_total_requested と、該当する場合は cores_per_node、cpus_per_node_requested、total_gpus、ranks_per_gpu を報告します。results.warnings には、CPU の過剰割り当て、タスクと GPU の比率、二重ランチャーに関する警告が含まれる場合があります。
ワークフロー
- クラスターの制約(パーティション/アカウント、GPU のポリシー、メモリのポリシー)を確認します。
- プロセスの構成(MPI のみ、または MPI+OpenMP のハイブリッド)を選択します。
slurm_script_generator.pyを使用してスクリプトを生成します。- 警告(競合や疑わしい構成)を確認します。
- 生成されたスクリプトを
job.sbatchとして保存します。 sbatch job.sbatchで送信し、squeueで監視します。
CLI の例
# Preview a job script (prints to stdout)
python3 skills/hpc-deployment/slurm-job-script-generator/scripts/slurm_script_generator.py \
--job-name phasefield \
--time 00:10:00 \
--partition compute \
--nodes 1 \
--ntasks-per-node 8 \
--cpus-per-task 2 \
--mem 16G \
--module gcc/12 \
--module openmpi/4.1 \
-- \
./simulate --config config.json
# Write to a file and also emit structured JSON
python3 skills/hpc-deployment/slurm-job-script-generator/scripts/slurm_script_generator.py \
--job-name phasefield \
--time 00:10:00 \
--nodes 1 \
--ntasks 16 \
--cpus-per-task 1 \
--out job.sbatch \
--json \
-- \
/bin/echo hello
会話形式のワークフロー例
ユーザー:MPI シミュレーション用の sbatch スクリプトが必要です。2 ノード、ノードあたり 64 ランク、ランクあたり 2 個の OpenMP スレッド、実行時間は 2 時間にしたいです。
エージェントのワークフロー:
- パーティション/アカウントと、GPU が必要かどうかを確認します。
- ハイブリッドジョブのスクリプトを生成します。
python3 scripts/slurm_script_generator.py --job-name run --time 02:00:00 --nodes 2 --ntasks-per-node 64 --cpus-per-task 2 -- ./simulate - マッピングについて説明します。
- ランクの合計 = 128
- ランクあたりのスレッド数 = 2(
OMP_NUM_THREADS=2)
- ユーザーからノードのコア数が提示された場合は、
--cores-per-nodeを使用してオーバーサブスクリプションがないか確認します。
エラー処理
| エラー | 原因 | 解決方法 |
|---|---|---|
time must be HH:MM:SS or D-HH:MM:SS | ウォールタイムの形式が正しくありません | 00:30:00 または 1-00:00:00 を使用します |
nodes must be positive | ノード数が正の値ではありません | --nodes >= 1 を指定します |
Provide either --mem or --mem-per-cpu, not both | メモリ指定が競合しています | メモリ指定方式を 1 つ選択します |
Provide a run command after -- | 起動コマンドがありません | -- ./simulate ... を追加します |
--partition must match /^[A-Za-z0-9]... | パーティション/アカウント/qos/constraint/reservation に空白またはシェルのメタ文字が含まれています | 通常の識別子を使用します |
module must match /^[A-Za-z0-9]... | モジュール名にシェルのメタ文字が含まれています | 例:gcc/12、openmpi/4.1 を使用します |
nodes must be <= 100000 (got ...) | 整数の要求値が妥当性確認の上限を超えています | 要求値を再確認します |
検証チェックリスト
- 生成された
results.scriptで、すべての#SBATCHディレクティブがシバンの直後、かつset -euo pipefailより前に配置されていることを確認しました(スクリプトを開き、最初の実コマンド行を確認してください)。最初のコマンドの後にあるディレクティブは SLURM によって黙って無視されます。 -
results.warningsを確認し、空であることを確認するか、各警告(CPU のオーバーサブスクリプション、タスクと GPU の比率が整数でないこと、ランチャーの二重起動)について、無視する正当な理由を記録しました。 -
results.derived.cpus_total_requested(=ntasks * cpus-per-task)を記録し、--cores-per-nodeを指定した場合は、ノードがオーバーサブスクリプションにならないようcpus_per_node_requested <= cores_per_nodeを確認しました。 - ハイブリッド実行では、スクリプトの
export OMP_NUM_THREADSの値がresults.derivedのcpus_per_taskと一致することを確認しました(ジェネレーターは両者を同じ値に設定します。ランクあたりの意図したスレッド数と一致することを確認してください)。 - GPU ジョブでは、
results.derived.total_gpusとranks_per_gpuを記録し、ranks_per_gpuが意図した整数であること(または MPS など、共有が意図的であることを記録していること)を確認しました。 -
results.run_lineが二重にラップされていないことを確認しました。実行コマンドがすでにsrun/mpirun/mpiexec/orterun/aprun/jsrunで始まる場合は、SLURM が独立したコピーを N 個起動しないよう、--launcher noneが使用されたこと(または自動検出の警告が出たこと)を確認しました。 - パーティション、アカウント、QoS、メモリ指定方式(
--memと--mem-per-cpuのどちらか)、GPU ディレクティブを、実際のクラスターの文書化されたポリシーと照合しました。ジェネレーターが検証するのは内部整合性のみで、サイトのポリシーは検証しません。
よくある落とし穴と誤った自己正当化
| 誘惑されがちな近道 | それが誤りである理由/すべきこと |
|---|---|
| 「エラーなしでスクリプトが生成されたので、リソースは正しいはずです。」 | ジェネレーターがチェックするのは内部整合性だけで、クラスターへの問い合わせは行いません。ジョブを送信する前に、パーティション/アカウント/QoS/メモリの指定形式と GPU ディレクティブを、サイトの実際のドキュメントで確認してください。 |
「実行コマンドにすでに srun/mpirun があるので、そのままにしてジェネレーターでラップします。」 | mpirun を srun でラップすると、独立した N 個の mpirun プロセス(それぞれが独自の MPI ワールド)を起動します。srun を srun でラップするのは不正な形式です。--launcher none を渡し、自動検出の警告が results.warnings に出力されたことを確認してください。 |
| 「使いたいノードをリクエストしたので、ジョブはすべてのノードを使うはずです。」 | #SBATCH ディレクティブが最初のコマンドより下にあると、何も通知されずに無視され、ジョブはクラスターのデフォルト設定にフォールバックします。生成されたスクリプトを読み直し、すべてのディレクティブが set -euo pipefail より前にあることを確認してください。 |
「ntasks は GPU 数で割り切れませんでしたが、実行できたので問題ありません。」 | ranks_per_gpu が整数でない場合、ランクはデバイスに不均等に割り当てられます(GPU がアイドル状態または過剰割り当てになります)。ジェネレーターはタスクと GPU の割り当てに関する警告を出力します。ntasks/GPU 数を修正するか、MPS 共有について明示的に記載してください。 |
「ランク数が多いほど速くなるので、ntasks-per-node を大きく設定します。」 | --cores-per-node を指定しないと、ジェネレーターは過剰割り当てを検出できません。また、ntasks-per-node*cpus-per-task が物理コア数を超えると、パフォーマンスが低下します。--cores-per-node を渡し、cpus_per_node_requested を確認してください。 |
「念のため --mem と --mem-per-cpu の両方を設定します。」 | これらは相互排他的です。ジェネレーターは両方を指定すると拒否します。クラスターのポリシーで適用される方を選んでください。 |
| 「MPI 専用のコードでは OMP_NUM_THREADS は関係ありません。」 | ジェネレーターは常に OMP_NUM_THREADS=cpus-per-task をエクスポートします。MPI 専用の実行では、スレッド化されたライブラリがコアを気付かないうちに過剰使用しないよう、--cpus-per-task=1 にしてください。 |
セキュリティ
入力の検証
--timeは正規表現を使って厳密なHH:MM:SSまたはD-HH:MM:SS形式で検証されます(分/秒は[00,59])。--nodes、--ntasks、--ntasks-per-node、--cpus-per-task、--gpus-per-node、--cores-per-nodeは、十分に大きな上限(例:nodes ≤ 100000、ntasks ≤ 10000000、cpus-per-task ≤ 4096、gpus-per-node ≤ 64)を設けたうえで、正の整数として検証されます。導出される合計ntasks = nodes * ntasks-per-nodeも上限チェックされます。--memと--mem-per-cpuは SLURM が受け付ける形式(^[0-9]+([KMGT])?$)に照らして検証されます。同時に両方を指定すると拒否されます。--job-nameは^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$に照らして検証されます(スペースやシェルのメタ文字は使用できません)。--partition、--account、--qos、--constraint、--reservation、--gpu-typeは、#SBATCHディレクティブに出力される前に、安全な文字の許可リスト^[A-Za-z0-9][A-Za-z0-9._:,+-]{0,127}$に照らして検証されます。--moduleの値は、シェルインジェクションを防ぐため^[A-Za-z0-9][A-Za-z0-9._/+-]{0,127}$に照らして検証されます(;、|、&、バッククォート、$、空白は使用できません)。--envのキーは、有効なシェル識別子(^[A-Za-z_][A-Za-z0-9_]*$)でなければなりません。値は生成されるexport行でシェル用にクォートされます。--srun-extraはshlex.splitでトークン化され、各トークンはshlex.quoteで再クォートされるため、実行行にシェル構文(;、|、&、$など)を注入できません。- 入力が無効な場合、CLI はメッセージを stderr に出力してコード
2で終了します。
ファイルアクセス
- スクリプトは外部ファイルを読み込みません。すべての入力は CLI 引数で指定します。
--outは生成された sbatch スクリプトを、指定された単一のファイルパスに書き込みます。- 生成されるスクリプトは
#SBATCHディレクティブを含むプレーンテキストのシェルスクリプトで、動的に生成されたコードは含まれません。
ツールの制限事項
- Read:スクリプトのソース、参照資料、既存のジョブスクリプトの確認に使用します
- Bash:明示的な引数リストを指定して
slurm_script_generator.pyを実行するために使用します。生成されたスクリプト自体はエージェントによって実行されません - Write:生成された
.sbatchファイルの保存に使用します。書き込み先はユーザーの作業ディレクトリ内に限定されます - Grep/Glob:既存のスクリプト、設定ファイル、クラスターのドキュメントの検索に使用します
安全対策
eval()、exec()、動的なコード生成は使用しません- すべてのサブプロセス呼び出しでは明示的な引数リストを使用します(
shell=Trueは使用しません) - run コマンド(
--の後)はトークンごとにシェルクォートされて生成スクリプトに記述されますが、スキル自体が実行することはありません - モジュール名、
--srun-extraトークン、識別子形式のフィールドは、module load、srunの呼び出し、#SBATCHディレクティブへのインジェクションを防ぐためにサニタイズまたはクォートされます - 生成スクリプトでは、すべての
#SBATCHディレクティブをシバンの直後(実行可能なコマンドより前)に配置し、SLURM の解析が停止しないようにします。また、クラスター上で安全にシェルを実行するためにset -euo pipefailを使用します
制限事項
- クラスターのハードウェアやサイトのポリシーは照会しません。内部整合性の検証のみ可能です。
- SLURM のインストール環境によって、GPU ディレクティブ、QoS ルール、パーティションは異なります。サイトに合わせてディレクティブを調整してください。
参考資料
references/slurm_directives.md- 一般的な#SBATCHディレクティブとマッピングのヒント
バージョン履歴
- v1.2.2 (2026-06-24):ディレクティブの順序、オーバーサブスクリプション、タスクと GPU のマッピング、ランチャーの二重ラップ、およびジェネレーターが内部整合性の確認のみを行う点を取り上げた「検証チェックリスト」と「よくある落とし穴とその合理化」のセクションを追加しました。
- v1.2.0 (2026-06-23):重大なディレクティブ順序のバグを修正しました(すべての
#SBATCH行がset -euo pipefailより前に配置されるようになりました)。run コマンドがすでにsrun/mpirunで始まる場合にランチャーを二重にラップしないようにし、GPU タスクと GPU の比率に関する警告とレイアウトのガイダンスを追加しました。入力検証を強化し(整数の上限、パーティション/アカウント/qos/制約/予約/GPU タイプの許可リスト、モジュールのサニタイズ、--srun-extraのクォート)、--help内の%jをエスケープし、セキュリティと出力に関するドキュメントを修正しました。 - v1.1.0 (2026-03-26):発見されやすくなるよう説明を最適化し、評価スイート、セキュリティレビュー、標準化されたメタデータ、CHANGELOG を追加しました。
- v1.0.0 (2026-02-25):SLURM ジョブスクリプトジェネレーターの初版
コメント
Markdown 対応