Slurm を使ったジョブの投入

管理ノードへのログイン

$ ssh -l (ユーザ名) slurm.matsue-ct.ac.jp

キューの状態の確認

sugiyama@ncfs1:~$ sinfo

  PARTITION AVAIL  TIMELIMIT  NODES  STATE NODELIST
  debug*       up    1:00:00      1   idle ncsv3
  v100         up   infinite      1   idle ncsv3

slurm のコマンド

コマンド      説明・主な用途

srun          インタラクティブ実行・ステップ実行
              リソースを確保して即座にプログラムを実行する.
              MPI並列実行時にも使用.

sbatch        バッチジョブの投入
              ジョブスクリプト(シェルスクリプト)をキューに投げ,
              バックグラウンドで実行する.

squeue        ジョブ待ち行列の確認
              実行中(R)や待機中(PD)のジョブ一覧を表示する.-u <ユーザー名> で絞り込み

scancel       ジョブの取り消し
              scancel <ジョブID> で実行中または待機中のジョブを強制終了する

scantrol      詳細情報の表示・変更
              scontrol show job <ID> で,そのジョブのさらに詳細な設定やログを確認できる

sacct         過去のジョブ履歴の確認
              終了したジョブの実行時間や消費メモリ,終了ステータスなどを確認する

snfo          パーティション・ノード状態の確認
              ノードが使用可能(idle),使用中(alloc),ダウン(down)などの状態を表示する

scontrol show node     ノードの詳細確認特定のノードに積まれているCPU数,
                       メモリ,GPU(GRES) の空き状況などを詳しく見る。

ジョブの実行時に付けるオプション

オプション             意味

-p, --partition        実行するパーティション(キュー)を指定する

-n, --ntasks           合計タスク数(MPIプロセス数)を指定する

-c, --cpus-per-task    1タスクあたりのCPUコア数(OpenMPスレッド用)を指定する

--gres=gpu:N           使用するGPUの枚数(N枚)を指定する

--mem                  使用する合計メモリ量(例: --mem=10G)を指定する

-t, --time             最大実行時間を指定する(例: 01:00:00)

並列実行の時は --ntasks と --cpus-per-task を設定する.

例:
 --ntasks=12 + --cpus-per-task=1   : CPU 12 コアで MPI 並列
 --ntasks=1  + --cpus-per-task=12  : CPU 1 コアで,12 スレッドの OMP 並列
 --ntasks=4  + --cpus-per-task=3   : CPU 4 コアで,3 スレッドの OMP 並列 = 計 12 並列 

MPI 並列の時は以下のオプションも必要

--mpi=pmax           : MPI 並列するときに必ず付ける

OpenMP 並列の場合は環境変数の設定が必要

export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK

GPU 利用時は --gres オプションを指定.使わない場合は 0 にすること.

--gres=gpu:0         : GPU 利用しない (デフォルト)
--gres=gpu:1         : GPU 1 基利用

インタラクティブな実行

管理ノードから計算ノードにあたかも SSH でログインしたような操作感が得られる.

MPI 並列計算

mpirun のオプションとして --bind-to none を与える必要があることに注意.

sugiyama@ncfs1:~/CPU$ srun --ntasks=4 --pty bash
         ^^^^^
sugiyama@ncsv3:~/CPU$ mpirun --bind-to none c_mpi-hello
         ^^^^^
      Hello World 3
      Hello World 1
      Hello World 0
      Hello World 2

sugiyama@ncsv3:~/CPU$ mpirun --bind-to none -n 2 c_mpi-hello
         ^^^^^                              ^^^^
      Hello World 1
      Hello World 0

 sugiyama@ncsv3:~/CPU$ exit
 sugiyama@ncfs1:~/CPU$ 

OMP 並列計算

OpenMP で並列計算する場合は,--cpus-per-task=2 でスレッド数を指定する. MPI を使わない場合は,計算ノードにおいて環境変数 OMP_NUM_THREADS に $SLURM_CPUS_PER_TASK を与えることを割愛できる.

sugiyama@ncfs1:~/CPU$ srun --cpus-per-task=2 --pty bash
         ^^^^^
sugiyama@ncsv3:~/CPU$ ./c_omp-hello
         ^^^^^
    Hello World from 0 of 2
    Hello World from 1 of 2

sugiyama@ncsv3:~/CPU$ nvidia-smi  -L
         ^^^^^
    GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-0ef0bd70-fd0b-7c80-7cdb-cc4ea2302287)

sugiyama@ncsv3:~/CPU$ exit
sugiyama@ncfs1:~/CPU$

MPI + OMP 並列計算

MPI と OMP の両方を使う場合は, 計算ノードにおいて環境変数 OMP_NUM_THREADS に $SLURM_CPUS_PER_TASK を与える必要がある.

sugiyama@ncfs1:~/CPU$ srun --ntasks=2 --cpus-per-task=2 --pty bash

sugiyama@ncsv3:~/CPU$ export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK

sugiyama@ncsv3:~/CPU$ mpirun --bind-to none -n 2 c_mpi-omp-hello

  Hello from thread 0 out of 2 from process 1 out of 2 on ncsv3
  Hello from thread 1 out of 2 from process 1 out of 2 on ncsv3
  Hello from thread 0 out of 2 from process 0 out of 2 on ncsv3
  Hello from thread 1 out of 2 from process 0 out of 2 on ncsv3

Python venv 環境

sugiyama@ncfs1:~/check/python$ srun --gres=gpu:1 --pty bash

sugiyama@ncsv3:~/check/python$ source ../venv/bin/activate

(venv) sugiyama@ncsv3:~/check/python$ python test_tf.py

docker イメージ

sugiyama@ncfs1:~/check/python$ srun  --gres=gpu:1 --ntasks=1 --pty bash

sugiyama@ncsv3:~/check/python$ podman run --rm --device "nvidia.com/gpu=$CUDA_VISIBLE_DEVICES" docker.io/nvidia/cuda:12.0.1-base-ubuntu22.04 nvidia-smi -L

   GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-0ef0bd70-fd0b-7c80-7cdb-cc4ea2302287)

ジョブ投入方法

GPU

何もつけないとデフォルトの debug キューとして実行される

$ srun --gres=gpu:1 nvidia-smi -L
GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-0ef0bd70-fd0b-7c80-7cdb-cc4ea2302287)

GPU を 2 基要求するとエラーになる (期待通り)

$ srun --gres=gpu:2 nvidia-smi
srun: error: Unable to allocate resources: Invalid generic resource (gres) specification

--gres オプションをつけないと GPU は割り当てられない.

$ srun  nvidia-smi -L
No devices found.

CPU (MPI 並列)

デフォルトの debug キューで 4 並列で実行する.srun に --mpi=pmix オプションが必要

$ srun --mpi=pmix --ntasks=4 ./c_mpi-hello

  Hello World 3
  Hello World 0
  Hello World 1
  Hello World 2

v100 キューを使うと,最大 32 並列まで OK.

$ srun --partition=v100 --mpi=pmix --ntasks=32 ./c_mpi-hello

  Hello World 0
  Hello World 1
  Hello World 2
  Hello World 3
  ...略...

--ntasks を指定しないと 1 並列で実行

$  srun --mpi=pmix ./c_mpi-hello

  Hello World 0

debug キューは 4 コアが上限なので,それを超えるとエラーになる (期待通り)

$ srun --mpi=pmix --ntasks=5 ./c_mpi-hello

  srun: error: Unable to allocate resources: Requested node configuration is not available

CPU (OMP 並列)

OMP だけしか使わない場合は環境変数 OMP_NUM_THREADS の設定を割愛することが可能.

$ srun --cpus-per-task=2 ./c_omp-hello

  Hello World from 0 of 2
  Hello World from 1 of 2

$ srun --partition=v100 --cpus-per-task=10 ./c_omp-hello

  Hello World from 5 of 10
  Hello World from 9 of 10
  Hello World from 4 of 10
  ...略...

CPU (MPI + OMP 並列)

環境変数を指定しないと,並列数がおかしくなることに注意.

$  srun --partition=v100 --mpi=pmix --ntasks=2 --cpus-per-task=4 \
   bash -c "export OMP_NUM_THREADS=\$SLURM_CPUS_PER_TASK; ./c_mpi-omp-hello"      

   Hello from thread 0 out of 4 from process 0 out of 2 on ncsv3
   Hello from thread 2 out of 4 from process 0 out of 2 on ncsv3
   Hello from thread 3 out of 4 from process 0 out of 2 on ncsv3
   Hello from thread 1 out of 4 from process 0 out of 2 on ncsv3
   Hello from thread 2 out of 4 from process 1 out of 2 on ncsv3
   Hello from thread 0 out of 4 from process 1 out of 2 on ncsv3
   Hello from thread 1 out of 4 from process 1 out of 2 on ncsv3
   Hello from thread 3 out of 4 from process 1 out of 2 on ncsv3

上記の例で,export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK を指定しないと 16 並列となる. その原因は,「Slurmが確保したCPUコア数」と「OpenMPが自動認識したスレッド数」が食い違っているためである. OpenMP(libgomp等)は、環境変数 OMP_NUM_THREADS が指定されていない場合,「システムに見える全コア数」をスレッド数にしようとするためである.今回の例ではジョブに割り当てられた合計コア数(今回は 2タスク × 4コア = 8)が「システム全体」として見えてしまう.

Python venv 環境

bash -c で囲む形で,実行の手順をカンマ区切りで並べているだけ.

$ srun  --gres=gpu:1 --ntasks=1 bash -c "source ../venv/bin/activate; python test_tf.py"

docker イメージ

podman を使って docker イメージを利用する場合は,bash -c でコマンドを囲む必要がある.

$ srun --gres=gpu:1 bash -c 'podman run --rm --device "nvidia.com/gpu=$CUDA_VISIBLE_DEVICES" docker.io/nvidia/cuda:12.0.1-base-ubuntu22.04 nvidia-smi -L'

  GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-0ef0bd70-fd0b-7c80-7cdb-cc4ea2302287)

覚書(1)

bash -c でコマンドを囲まないと環境変数 $CUDA_VISIBLE_DEVICES が取れない.

$ srun --gres=gpu:1 podman run --rm --device "nvidia.com/gpu=$CUDA_VISIBLE_DEVICES" docker.io/nvidia/cuda:12.0.1-base-ubuntu22.04 nvidia-smi -L

  Error: stat nvidia.com/gpu=: no such file or directory
  srun: error: ncsv3: task 0: Exited with exit code 125

覚書(2)

bash -c で囲まず,gpu=all にすると,全部の GPU が見えてしまう.このあたりに slurm と podman の連携がまだ完全ではないことが垣間見える.

$ srun --gres=gpu:1 podman run --rm --device "nvidia.com/gpu=all" docker.io/nvidia/cuda:12.0.1-base-ubuntu22.04 nvidia-smi -L

  GPU 0: Tesla V100S-PCIE-32GB (UUID: GPU-0ef0bd70-fd0b-7c80-7cdb-cc4ea2302287)
  GPU 1: Tesla V100S-PCIE-32GB (UUID: GPU-d19054e2-f863-3da6-c30b-f299bb053a27)
  GPU 2: Tesla V100S-PCIE-32GB (UUID: GPU-cf4c7b4a-6a73-1407-4d80-c5a8000eca26)
  GPU 3: Tesla V100S-PCIE-32GB (UUID: GPU-a478fcef-90a8-f595-6260-85b310526d6d)

ジョブスクリプトの例

CPU (MPI 並列)

c_mpi-hello.sh を以下のように作成する

#!/bin/sh
#SBATCH --job-name=MyTest          # ジョブ名
#SBATCH --output=%j_out.txt        # 標準出力 (%j はジョブIDに置換)
#SBATCH --error=%j_err.txt         # 標準エラー出力
#SBATCH --partition=debug          # パーティション名 (sinfoで確認したもの)
#SBATCH --ntasks=2                 # MPI 並列数
#SBATCH --cpus-per-task=1          # OMP 並列数

# 作業フォルダに移動
cd /work/$USER/CPU

# コンパイル
mpicc -o c_mpi-hello c_mpi-hello.c

# 実行. --mpi=pmix オプション必須.
srun --mpi=pmix ./c_mpi-hello

ジョブの投入

$ sbatch c_mpi-hello.sh

確認

$ cat 282_out.txt

  Hello World 0
  Hello World 1

$ cat 282_err.txt

CPU (OMP 並列)

#!/bin/sh
#SBATCH --job-name=MyTest          # ジョブ名
#SBATCH --output=%j_out.txt        # 標準出力 (%j はジョブIDに置換)
#SBATCH --error=%j_err.txt         # 標準エラー出力
#SBATCH --partition=debug          # パーティション名 (sinfoで確認したもの)
#SBATCH --ntasks=1                 # MPI 並列数
#SBATCH --cpus-per-task=2          # OMP 並列数

# OpenMP の時は環境変数を設定する必要あり
export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK

# 作業フォルダに移動
cd /work/$USER/CPU

# コンパイル
gcc -fopenmp -o c_omp-hello c_omp-hello.c

# 実行
./c_omp-hello

CPU (MPI + OMP 並列)

#!/bin/sh
#SBATCH --job-name=MyTest          # ジョブ名
#SBATCH --output=%j_out.txt        # 標準出力 (%j はジョブIDに置換)
#SBATCH --error=%j_err.txt         # 標準エラー出力
#SBATCH --partition=debug          # パーティション名 (sinfoで確認したもの)
#SBATCH --ntasks=2                 # MPI 並列数
#SBATCH --cpus-per-task=2          # OMP 並列数

# OpenMP の時は環境変数を設定する必要あり
export OMP_NUM_THREADS=$SLURM_CPUS_PER_TASK

# 作業フォルダに移動
cd /work/$USER/CPU

# コンパイル
mpicc -fopenmp -o c_mpi-omp-hello c_mpi-omp-hello.c

# 実行.  --mpi=pmix オプション必須.
srun --mpi=pmix ./c_mpi-omp-hello

Python venv

#!/bin/sh
#SBATCH --job-name=MyTest          # ジョブ名
#SBATCH --output=%j_out.txt        # 標準出力 (%j はジョブIDに置換)
#SBATCH --error=%j_err.txt         # 標準エラー出力
#SBATCH --partition=debug          # パーティション名 (sinfoで確認したもの)
#SBATCH --gres=gpu:1               # GPUを1枚要求
# --- メール通知設定 ---
#SBATCH --mail-type=END,FAIL       # 通知するタイミング
#SBATCH --mail-user=hoge@...       # 送信先のアドレス

# 作業フォルダに移動
cd /work/$USER/check/python

# venv 環境
. ../venv/bin/activate

# 実行
python test_tf.py

docker イメージ

#!/bin/bash
#SBATCH --job-name=cuda_direct
#SBATCH --output=%j_out.txt        # 標準出力 (%j はジョブIDに置換)
#SBATCH --error=%j_err.txt         # 標準エラー出力
#SBATCH --partition=debug          # パーティション名 (sinfoで確認したもの)
#SBATCH --gres=gpu:1

# 作業フォルダに移動
cd /work/$USER/check/python

# 1. 計算ノード側でSlurmが割り当てたGPUを決定
GPU_SPEC="nvidia.com/gpu=$CUDA_VISIBLE_DEVICES"

# 2. Podman実行
# --rm: 終了後にコンテナを削除
# -v: ホストのディレクトリをコンテナへマウント
# -w: 作業ディレクトリ
podman run --rm \
 --device "$GPU_SPEC" \
 -v "$HOME:$HOME" \
 -w "$PWD" \
 docker.io/nvidia/cuda:12.0.1-base-ubuntu22.04 \
 nvidia-smi