6. 拡張ガイド¶
(註: 以下の内容は moller のバージョンによって変わる可能性があります。)
6.1. mollerによるバルク実行¶
バルク実行とは、大型のバッチキューに投入した一つのバッチジョブの中で、複数の小さいタスクを並行して実行するというものです。動作のイメージとしては、次のようにN個のタスクをバックグラウンドで実行し同時に処理させ、wait文によりすべてのタスクが終了するまで待ちます。
task param_1 &
task param_2 &
...
task param_N &
wait
このとき、バッチジョブに割り当てられたノード・コアを適宜分配し、param_1〜param_N のタスクがそれぞれ別のノード・コアで実行されるように配置する必要があります。また、多数のタスクがある時に、割当てリソースに応じて最大N個のタスクが実行されるよう実行を調整することも必要です。
moller で生成したジョブスクリプトを以下では moller scriptと呼ぶことにします。 moller script では、タスクの並行実行と制御には GNU parallel [1]を利用します。GNU parallel は param_1〜param_N のリストを受取り、これらを引数としてコマンドを並行して実行するツールです。 以下は GNU parllel を使った実行イメージで、list.dat の各行に param_1〜param_N を列挙しておきます。
cat list.dat | parallel -j N task
同時実行数については、バッチジョブに割当てられたノード数・コア数を実行時に環境変数等から取得し、各タスクの並列度(ノード数・プロセス数・スレッド数)の指定(nodeパラメータ)を元に計算します。
ノード・コアへのタスクの配置についてはジョブスケジューラによって方法が異なります。SLURM系のジョブスケジューラでは、リソースの排他利用のオプションを使うことで、バッチジョブ内部で発行された複数の srun をジョブスケジューラが適宜配置して実行します。具体的な指定方法はプラットフォームの設定に依存します。
一方、PBS系のジョブスケジューラはそのような仕組みがなく、リソースの配分をmoller script内部で処理する必要があります。moller scriptでは、バッチジョブに割り当てられた計算ノードとコアをスロットに分割し、GNU parallel で並行処理されるタスクに分配します。スロットへの分割は、実行時に取得される割当てノード・コアとタスクの並列度指定から計算し、テーブルの形で保持します。タスク内部では、mpirun (mpiexec) の引数や環境変数を通じて計算ノードの指定と割当コアのピン留めを行いプログラムを実行します。この処理は使用するMPI実装に依存します。
参考文献
6.2. mollerの動作について¶
mollerで生成されるスクリプトの構成¶
mollerは、入力されたYAMLファイルの内容をもとに、バルク実行のためのジョブスクリプトを生成します。生成されるジョブスクリプトは先頭から順に次のような構成になっています。
ヘッダ
ジョブスケジューラへの指示が記述されます。platform セクションに指定した内容が、ジョブスケジューラの種類に応じた形式に整形されて出力されます。この処理はプラットフォーム依存です。
プロローグ
prologue セクションに指定した内容です。code ブロックの中身がそのまま転記されます。
関数の定義
ジョブスクリプト内部で使う関数および変数の定義が出力されます。関数の概要については次節で説明します。この箇所はプラットフォーム依存です。
コマンドライン引数の処理
SLURM系のジョブスケジューラでは、リストファイルの指定やタスクの再実行などのオプション指定を sbatch コマンドの引数として与えることができます。
PBS系のジョブスケジューラでは引数の指定は無視されるため、オプション指定はジョブスクリプトを編集してパラメータをセットする必要があります。リストファイルのファイル名はデフォルトで
list.dat
です。また、タスクのリトライを行うにはretry
変数を1
にセットします。タスクの記述
jobs セクションに記述されるタスクの内容を出力します。タスクが複数ある場合はタスクごとに以下の処理を実行します。
parallel = false の場合は run ブロックの中身がそのまま転記されます。
parallel = true (デフォルト) の場合、task_タスク名 という関数が生成され、並列実行のための前処理と run ブロックの内容が出力されます。並列計算のためのキーワード(
srun
、mpiexec
またはmpirun
)はプラットフォームに応じたコマンドに置き換えられます。関数定義に続いて並列実行のコマンドが書き出されます。エピローグ
epilogue セクションに指定した内容です。code ブロックの中身がそのまま転記されます。
moller scriptの関数の概要¶
moller script の内部で使用する主な関数の概要を以下に説明します。
run_parallel
タスクの内容を記述した関数(タスク関数)を並行実行する関数です。並列度、タスク関数、ステータスファイル名を引数に取ります。内部では
_find_multiplicity
関数を呼んで多重度を計算し、GNU parallel を起動してタスクを並行実行します。GNU parallel の多段処理に対応するために、タスク関数は_run_parallel_task
関数でラップされます。プラットフォーム依存性は
_find_multiplicity
および_setup_run_parallel
関数としてくくり出しています。_find_multiplicity
並列実行の多重度を、割当てリソース(ノード数・コア数)とタスクの並列度指定から計算します。PBS系のジョブスケジューラでは、さらに計算ノード・コアをスロットに分割し、テーブルで保持します。 実行時に環境から取得する情報は次の通りです。
SLURM系
- 割当てノード数 _nnodes
SLURM_NNODES
- 割当てコア数 _ncores
SLURM_CPUS_ON_NODE
PBS系
- 割当てノード _nodes[]
PBS_NODEFILE
で指定されるファイルから計算ノードのリストを取得- ノード数 _nnodes
_nodes[] の項目数
- 割当てコア数 _ncores
- 以下の順に検索されます。
NCPUS
(PBS Professional)OMP_NUM_THREADS
platform セクションの core 指定(スクリプト中に moller_core変数として書き込まれる)
ヘッダの ncpus または ppn パラメータ
_setup_run_parallel
GNU parallel による並行実行を開始する前にいくつか処理を追加するために呼ばれます。PBS系ではスロットに分割されたノード・コアのテーブルをタスク関数から参照できるよう export します。SLURM系では実行する内容はありません。
各タスクに対応するタスク関数の構成については次の通りです。
タスク関数の引数は 1) 並列度指定(ノード数・プロセス数・スレッド数) 2) 実行ディレクトリ 3) GNU parallel のスロットID です。
_setup_taskenv
で実行環境の設定を行います。この関数はプラットフォーム依存です。PBS系ではスロットIDに基づいて計算ノード・コアをテーブルから取得します。SLURM系では実行する内容はありません。直前に実行するタスクが正常終了したかどうかを
_is_ready
関数を呼んでチェックします。正常終了している場合はタスクの処理を継続します。それ以外の場合は -1 のステータスでタスクの処理を中断します。code ブロックの内容を転記します。その際に、並列計算のためのキーワード(
srun
、mpiexec
またはmpirun
)はプラットフォームに応じたコマンドに置き換えられます。
6.3. mollerを他のシステムで使うには¶
mollerには現在、物性研スーパーコンピュータシステム ohtaka および kugui 向けの設定が用意されています。mollerを他のシステムで使うための拡張ガイドを以下で説明します。
クラス構成¶
mollerの構成のうちプラットフォーム依存の部分は platform/
ディレクトリにまとめています。
クラス構成は次のとおりです。
![digraph class_diagram {
size="5,5"
node[shape=record,style=filled,fillcolor=gray95]
edge[dir=back,arrowtail=empty]
Platform[label="{Platform (base.py)}"]
BaseSlurm[label="{BaseSlurm (base_slurm.py)}"]
BasePBS[label="{BasePBS (base_pbs.py)}"]
BaseDefault[label="{BaseDefault (base_default.py)}"]
Ohtaka[label="{Ohtaka (ohtaka.py)}"]
Kugui[label="{Kugui (kugui.py)}"]
Pbs[label="{Pbs (pbs.py)}"]
Default[label="{DefaultPlatform (default.py)}"]
Platform->BaseSlurm
Platform->BasePBS
Platform->BaseDefault
BaseSlurm->Ohtaka
BasePBS->Kugui
BasePBS->Pbs
BaseDefault->Default
}](../../_images/graphviz-06368183531b8fc81c8d91cef6b17e1dc3c86493.png)
プラットフォームの選択についてはファクトリが用意されています。register_platform(登録名, クラス名)
でクラスをファクトリに登録し、 platform/__init__.py
にクラスを import しておくと、入力パラメータファイル中で platform セクションの system パラメータに指定できるようになります。
SLURM系ジョブスケジューラ¶
SLURM系のジョブスケジューラを利用している場合、BaseSlurm クラスを元にシステム固有の設定を行います。
並列計算を実行するキーワードを置き換える文字列は parallel_command()
メソッドの戻り値で与えます。リソースの排他利用を行うための srun のパラメータをここに指定します。
具体例は ohtaka.py を参照してください。
PBS系ジョブスケジューラ¶
PBS系のジョブスケジューラ (PBS Professional, OpenPBS, Torque など)を利用している場合、BasePBS クラスを元にシステム固有の設定を行います。
PBS系ではバッチジョブのノード数の指定の仕方に2通りあり、PBS Professional は select=N:ncpus=n という書式で指定しますが、Torque などは node=N:ppn=n と記述します。後者の指定を用いる場合は self.pbs_use_old_format = True
をセットします。
計算ノードのコア数は node パラメータで指定できますが、対象システムを限定してコア数のデフォルト値を設定しておくこともできます。kugui.py ではノードあたり128コアを設定しています。
細かいカスタマイズが必要な場合¶
基底クラスを参照して必要なメソッドを再定義します。メソッド構成は次のようになっています。
setup
platform セクションのパラメータの取り出しなどを行います。
parallel_command
並列計算のキーワード (
srun
,mpiexec
,mpirun
) を置き換える文字列を返します。generate_header
ジョブスケジューラオプションの指定を記述したヘッダを生成します。
generate_function
moller script 内部で使用する関数の定義を生成します。変数および関数の実体はそれぞれ以下のメソッドで作られます。
generate_variable
generate_function_body
それぞれの関数は埋め込み文字列としてクラス内で定義されています。
新しいタイプのジョブスケジューラに対応させるには¶
moller scriptの動作のうちプラットフォーム依存な箇所は、並行実行の多重度の計算、リソース配置に関する部分、並列計算のコマンドです。
割当てノード・ノード数・ノードあたりのコア数を実行時に環境変数等から取得する方法
並列計算を実行するコマンド (mpiexec等) と、実行ホストやコア割当の指定のしかた
これらをもとにmoller script内で使う関数を作成します。
printenv
コマンドでジョブスクリプト内で有効な環境変数の一覧を取得できます。
トラブルシューティング¶
moller script内の _debug
変数を 1 にセットすると、バッチジョブ実行時にデバッグ出力が書き出されます。もしジョブがうまく実行されないときは、デバッグ出力を有効にして、内部パラメータが正しくセットされているかを確認してみてください。