0. はじめに
前回の記事では,ParallelClusterの立ち上げとログインまでを扱いました.そちらをご覧になっていない方は,下記「シリーズの流れ」にリンクを記載していますので,参考にしてください.今回は,ParallelCluster上でのFrontISTR実行について,ジョブスケジューラであるSlurmの使い方・ジョブスクリプトの書き方を中心に見ていきます.
1. シリーズの流れ
- ParallelCluster バージョン3用のカスタムAMIの作成
- ParallelCluster バージョン3用の設定ファイルの作成〜起動
- Slurmを利用したFrontISTR並列実行 (この記事)
2. ログイン〜領域分割
前回の記事に沿って,クラスタの作成とログインを行います.
設定ファイル「v3.1.2-FrontISTR.yaml」を利用して,「FrontISTR-cluster」という名称のクラスタを作成するコマンドは次の通りです.
pcluster create-cluster -n FrontISTR-cluster -c v3.1.2-FrontISTR.yaml
作成が完了したのを確認したら,ヘッドノードにログインします(ここではpcluster ssh
コマンドを利用します).
pcluster ssh -n FrontISTR-cluster -i PRIVATE_KEY
子ノード(計算資源)との共有ディレクトリとして「/shared」を指定したので,そちらに移動し,例題となるモデル(サポートリポジトリ)をGitLabから持ってきます(書籍p. 235と同じ内容です).
cd /shared
git clone https://gitlab.com/FrontISTR-Commons/nonlinearparallelfem.git
cd nonlinearparallelfem/SampleModels/OpenTool
並列計算をするに当たり,モデルの領域分割を行います.今回は比較的小さいものですので,ジョブを投げる(=子ノードを立ち上げる)ことなく,その場で実行します.
hecmw_part1
ここでは,領域分割したメッシュを別のディレクトリに格納するよう設定しています1ので,「MESH」というディレクトリが作成されます.
$ ls
frontistr.job hecmw_part_ctrl.dat MESH mesh.inp
hecmw_ctrl.dat hecmw_part.log mesh.cnt ucd.inp
$ ls MESH
mesh.dist.0 mesh.dist.2 mesh.dist.30 mesh.dist.41 mesh.dist.52 mesh.dist.63
mesh.dist.1 mesh.dist.20 mesh.dist.31 mesh.dist.42 mesh.dist.53 mesh.dist.64
mesh.dist.10 mesh.dist.21 mesh.dist.32 mesh.dist.43 mesh.dist.54 mesh.dist.65
mesh.dist.11 mesh.dist.22 mesh.dist.33 mesh.dist.44 mesh.dist.55 mesh.dist.66
mesh.dist.12 mesh.dist.23 mesh.dist.34 mesh.dist.45 mesh.dist.56 mesh.dist.67
mesh.dist.13 mesh.dist.24 mesh.dist.35 mesh.dist.46 mesh.dist.57 mesh.dist.68
mesh.dist.14 mesh.dist.25 mesh.dist.36 mesh.dist.47 mesh.dist.58 mesh.dist.69
mesh.dist.15 mesh.dist.26 mesh.dist.37 mesh.dist.48 mesh.dist.59 mesh.dist.7
mesh.dist.16 mesh.dist.27 mesh.dist.38 mesh.dist.49 mesh.dist.6 mesh.dist.70
mesh.dist.17 mesh.dist.28 mesh.dist.39 mesh.dist.5 mesh.dist.60 mesh.dist.71
mesh.dist.18 mesh.dist.29 mesh.dist.4 mesh.dist.50 mesh.dist.61 mesh.dist.8
mesh.dist.19 mesh.dist.3 mesh.dist.40 mesh.dist.51 mesh.dist.62 mesh.dist.9
3. Slurmコマンド
領域分割が完了したら,いよいよソルバの実行になります.ここではまず,ジョブスケジューラであるSlurmの主要コマンドについて,実行例と共に見ていきます.Slurm公式ドキュメントの他,以下のサイトが参考になります.
3.1. ジョブの投入
ジョブの投入はsbatch
コマンドです.ジョブスクリプトを指定します.ジョブIDが返ってきます.
$ sbatch v3.1.2-frontistr.job
Submitted batch job 3
3.2. ジョブの削除
ジョブの削除はscancel
コマンドです.ジョブIDを指定します.リターンはありません.
$ scancel 3
3.3. ジョブ情報の表示
ジョブの情報はsqueue
コマンドで表示します.SGEと異なり,経過時間2も表示されます.
$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
3 queue OpenTool ec2-user CF 0:03 2 queue-dy-compute-resource-[1-2]
$ squeue
JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
3 queue OpenTool ec2-user R 0:06 2 queue-dy-compute-resource-[1-2]
ST
欄に表示される状態については,上に載せたFOCUSのページに詳しく書かれています.ノード確保中のCF
,実行中のR
の他には,確保に失敗した際のPD
や削除後のCG
を比較的目にすると思われます.一番右のNODELIST
については次の3.4.を参照してください.
3.4. ノード情報の表示
利用しているノードの情報はsinfo
コマンドで表示します.オプション-N
を付けると,各ノードが個別の行で,-s
を付けると,全ノードをまとめた形で状態ごとのノード数が表示されます.
$ sinfo
PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
queue* up infinite 2 alloc~ queue-dy-compute-resource-[1-2]
queue* up infinite 8 idle~ queue-dy-compute-resource-[3-10]
$ sinfo -N
NODELIST NODES PARTITION STATE
queue-dy-compute-resource-1 1 queue* alloc~
queue-dy-compute-resource-2 1 queue* alloc~
queue-dy-compute-resource-3 1 queue* idle~
queue-dy-compute-resource-4 1 queue* idle~
queue-dy-compute-resource-5 1 queue* idle~
queue-dy-compute-resource-6 1 queue* idle~
queue-dy-compute-resource-7 1 queue* idle~
queue-dy-compute-resource-8 1 queue* idle~
queue-dy-compute-resource-9 1 queue* idle~
queue-dy-compute-resource-10 1 queue* idle~
$ sinfo -s
PARTITION AVAIL TIMELIMIT NODES(A/I/O/T) NODELIST
queue* up infinite 2/8/0/10 queue-dy-compute-resource-[1-10]
上の例の場合は,1・2番の2ノードを利用しているということになります.全体が10ノードなのは,ParallelCluster バージョン3での最大ノード数のデフォルト値が10であるためです.なお.ここで表示されるalloc
はあくまでも「10の内使用する2を設定しました」のような意味合いであり,実機を確保できているとは限りません.実機の確保に失敗した場合は,alloc
が再びidle
となり,別の番号のノードで確保を試みます.
4. Slurm用ジョブスクリプトの書き方
サポートリポジトリでは,SGE用のジョブスクリプト frontistr.job が提供されています.こちらをSlurm用に書き換えていきます.
SGEとSlurmとの対応については,先にも挙げたモナシュ大,スタンフォード大,ペンシルベニア大のページが参考になります.特にモナシュ大のページでは,様々な並列計算の場合について紹介されています.また,FOCUSのページ(他節)も,比較はありませんが良い日本語資料となっています(以下,断りなくこれらを参照します).
4.1. SGE用のものを書き換える
こちらが,サポートリポジトリに掲載されている元のジョブスクリプトです.上から順に書き換えていきましょう.
#!/bin/sh
#$ -cwd
#$ -N OpenTool
#$ -pe mpi 72
#$ -j y
source ~/.bashrc
export OMP_NUM_THREADS=1
mpirun -np 72 fistr1 > out.log
- L. 2
#$ -cwd
- 現在のワーキングディレクトリへの移動を示します.Slurmではデフォルトの挙動ですので,対応するコマンドは存在しません.
- L. 3
#$ -N OpenTool
- ジョブの名称設定です.Slurmでは
#SBATCH -J JOB_NAME
と書きます.
- ジョブの名称設定です.Slurmでは
- L. 4
#$ -pe mpi 72
- MPI並列数の設定です.Slurmでは
#SBATCH --ntasks <num_procs>
もしくは#SBATCH -n <num_procs>
と書きます.
- MPI並列数の設定です.Slurmでは
- L. 5
#$ -j y
- 標準出力と標準エラー出力を1つのファイルにまとめる設定です.Slurmでは標準出力のみを指定することで同様の結果を得ます.
- L. 11
mpirun -np 72 fistr1 > out.log
- FrontISTRの並列実行を示します.並列数は決め打ちでも良いですが,Slurmでは環境変数
$SLURM_NTASKS
を利用して取得することができます.
- FrontISTRの並列実行を示します.並列数は決め打ちでも良いですが,Slurmでは環境変数
これらを踏まえて書き直すと,以下のジョブスクリプトが完成します.名称は元のファイルにならい「v3.1.2-frontistr.job」としています.
#!/bin/sh
#SBATCH -J OpenTool
#SBATCH -n 72
source ~/.bashrc
export OMP_NUM_THREADS=1
mpirun -np $SLURM_NTASKS fistr1 > out.log
前項で扱ったコマンドを用い,実行させます.
sbatch v3.1.2-frontistr.job
すると,計算開始後すぐに終了してしまいました.明らかに失敗しているのでout.logを確認すると,下に示す内容が36行(1ノード分)続いていました.
MPI startup(): PMI server not found. Please set I_MPI_PMI_LIBRARY variable if it is not a singleton case.
MPI startup(): PMI server not found. Please set I_MPI_PMI_LIBRARY variable if it is not a singleton case.
...
どうやら"PMI"というものでエラーになってしまったようです.
4.2. 並列実行部分を修正する
どうもSlurmでのmpirun
コマンドの利用に問題がありそうなので,Intel MPIの利用について,Slurmのドキュメントを参照します.すると,mpirun
コマンド自体は利用できるようですが,別にプロセスマネージャの利用・指定が必要なことが分かります.また,推奨されているのはsrun
コマンドを利用した方法ですので,こちらに切り替えます.
srun
コマンドを利用するにはまず
export I_MPI_PMI_LIBRARY=/path/to/slurm/pmi/library/libpmi.so
としてPMI (Process Management Interface)のライブラリを指定する必要があります.このlibpmi.soという共有オブジェクトですが,「slurm libpmi.so」と検索すると,場所に関するGitHubのIssue3が出てきました.これを基に/opt/slurm/lib内を探したところ,確かに存在しましたので,値として設定します.
srun
コマンドの例は
srun -n <num_procs> a.out
と示されています.
これらを踏まえてv3.1.2-frontsitr.jobを書き直します.下3行が更新箇所です.
#!/bin/sh
#SBATCH -J OpenTool
#SBATCH -n 72
source ~/.bashrc
export OMP_NUM_THREADS=1
export I_MPI_PMI_LIBRARY=/opt/slurm/lib/libpmi.so
srun -n $SLURM_NTASKS fistr1 > out.log
再びジョブスクリプトを投入します.
sbatch v3.1.2-frontistr.job
投入後にsqueue
,sinfo
コマンドを利用すると,前項のような出力を得られます.その他にも,ノードの情報を表示するコマンドとしてscontrol
,ジョブの情報を表示するコマンドとしてsstat
などがあります.
$ scontrol show nodes
NodeName=queue-dy-compute-resource-1 Arch=x86_64 CoresPerSocket=1
CPUAlloc=36 CPUTot=36 CPULoad=1.04
AvailableFeatures=dynamic,c5n.18xlarge,compute-resource,efa
ActiveFeatures=dynamic,c5n.18xlarge,compute-resource,efa
Gres=(null)
NodeAddr=10.0.1.76 NodeHostName=queue-dy-compute-resource-1 Version=21.08.6
OS=Linux 4.14.268-205.500.amzn2.x86_64 #1 SMP Wed Mar 2 18:38:38 UTC 2022
RealMemory=1 AllocMem=0 FreeMem=179437 Sockets=36 Boards=1
State=ALLOCATED+CLOUD ThreadsPerCore=1 TmpDisk=0 Weight=1 Owner=N/A MCS_label=N/A
Partitions=queue
...
NodeName=queue-dy-compute-resource-2 Arch=x86_64 CoresPerSocket=1
CPUAlloc=36 CPUTot=36 CPULoad=1.00
AvailableFeatures=dynamic,c5n.18xlarge,compute-resource,efa
...
$ sstat 3
JobID MaxVMSize MaxVMSizeNode MaxVMSizeTask AveVMSize MaxRSS MaxRSSNode MaxRSSTask AveRSS MaxPages MaxPagesNode MaxPagesTask AvePages MinCPU MinCPUNode MinCPUTask AveCPU NTasks AveCPUFreq ReqCPUFreqMin ReqCPUFreqMax ReqCPUFreqGov ConsumedEnergy MaxDiskRead MaxDiskReadNode MaxDiskReadTask AveDiskRead MaxDiskWrite MaxDiskWriteNode MaxDiskWriteTask AveDiskWrite TRESUsageInAve TRESUsageInMax TRESUsageInMaxNode TRESUsageInMaxTask TRESUsageInMin TRESUsageInMinNode TRESUsageInMinTask TRESUsageInTot TRESUsageOutAve TRESUsageOutMax TRESUsageOutMaxNode TRESUsageOutMaxTask TRESUsageOutMin TRESUsageOutMinNode TRESUsageOutMinTask TRESUsageOutTot
------------ ---------- -------------- -------------- ---------- ---------- ---------- ---------- ---------- -------- ------------ -------------- ---------- ---------- ---------- ---------- ---------- -------- ---------- ------------- ------------- ------------- -------------- ------------ --------------- --------------- ------------ ------------ ---------------- ---------------- ------------ -------------- -------------- ------------------ ------------------ -------------- ------------------ ------------------ -------------- --------------- --------------- ------------------- ------------------- --------------- ------------------- ------------------- ---------------
3.0 213503982+ 0 0 Unknown Unknown Unknown 0
今度は何十分か経ってから終了しました.可視化ファイルも問題なく出力されています.
$ ls vis_out
mesh_vis_psf.0000.inp mesh_vis_psf.0002.inp mesh_vis_psf.0005.inp mesh_vis_psf.0009.inp
mesh_vis_psf.0001.inp mesh_vis_psf.0003.inp mesh_vis_psf.0008.inp mesh_vis_psf.0010.inp
out.logより,正常に実行・終了したことを確認します.
##################################################################
# FrontISTR #
##################################################################
---
version: 5.3
git_hash: 5db1d80452b951905658da828285c2fd0537603c
build:
date: 2022-03-09T10:01:41+0000
MPI: "3.1, Intel MPI 2021.4.0"
OpenMP: 201511
option: "-p --with-tools --with-metis --with-mumps --with-lapack --with-ml --with-parmetis --with-mkl "
HECMW_METIS_VER: 5
execute:
date: 2022-03-16T04:44:36+0000
processes: 72
threads: 1
cores: 72
MPI: "3.1, Intel(R) MPI Library 2021.4 for Linux* OS"
host:
0: queue-dy-compute-resource-1
1: queue-dy-compute-resource-1
2: queue-dy-compute-resource-1
...
70: queue-dy-compute-resource-2
71: queue-dy-compute-resource-2
---
fstr_setup: OK
loading step= 1
sub_step= 1, current_time= 0.0000E+00, time_inc= 0.1800E+03
loading_factor= 0.0000000 1.0000000
...
iter: 5, residual: 9.5416E-01, disp.corr.: 6.2839E-04
### FSTR_SOLVE_NLGEOM FINISHED!
====================================
TOTAL TIME (sec) : 4845.84
pre (sec) : 1.29
solve (sec) : 4844.55
====================================
FrontISTR Completed !!
5. ちょっとした補足
- メッシュのサイズが大きい場合には領域分割もジョブとして投入する必要があります.ヘッドノードではメモリ不足になります.
- 子ノードがいつまでも確保できないなど,Slurmでエラーが発生した場合は,
/var/log/parallelcluster/slurm_resume.log
を参照します.中を見てはじめて,アベイラビリティーゾーン内に資源がないため失敗したことが分かった,という経験があります.
エラーについての参考↓
-
この辺りの詳細はFrontISTRのマニュアルをご覧ください. ↩
-
それぞれの状態(
ST
)ごとに0からカウントされます.実行時間はジョブ投入からの経過時間ではありません. ↩