研究室の計算機クラスタでは、1つのノード内で24コア程度のCPUが使える。 単一ノード内の並列計算ならば、Open MPを使って比較的簡単にコード開発・実行が出来るが、並列数に制限がある。 これを越える並列数で計算するため、MPIの使い方のメモを残しておく。 MPI的に正しい書き方・術語である自信はないので、鵜呑みにせず各自で勉強してほしい。
ノード間並列をしたい場合MPIを使う。 なお、MPIは単一ノード内の並列化でも使用できる。
C++でMPIを使う場合、生のMPIを使う方法とBoost.MPIを使う方法がある。
C++的に自然な書き方ができるのは後者だと思われるが、Boost.MPIの導入はやや面倒である。
それ以外のboostライブラリと異なり、ビルドが必要だからである。
少なくとも piano
に元々入っているコンパイラとMPIで私はビルドに成功しておらず、他のコンパイラでのトライなどはしていない。
ここでは、生のMPIを使う方法を簡単にまとめる。
先ずはヘッダー
#include <mpi.h>
を書く。
プログラム中では、最初に
int main(int argc, char** argv) {
int rank;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
}
を書く。
MPI_Init
で初期化をしている。
この際、コマンドライン引数で受け取った並列数を argv
で渡している(引数の与え方については後述)。
MPI_Comm_rank
では、自身が存在するプロセス・インデックスを int
型の変数 rank
に格納している。
あとは自由にプログラム内部を記述していく。 プログラムの最後には
MPI_Finalize();
と書いてMPIを終了させる。
よく使用するのは
MPI_Barrier(MPI_COMM_WORLD);
MPI_Allgather(&vec[rank], 1, MPI_DOUBLE, vec.data(), 1, MPI_DOUBLE, MPI_COMM_WORLD);
あたりだろうか( vec
は std::vector<double>
型)。
MPI_Barrier
は、全プロセスが通過するまで計算を待機する命令である。
もちろん、律速のプロセスを待つ間、他のプロセスはアイドル状態なので、全体の実行速度は低下するので注意。
また、 MPI_Barrier
同士は識別されず、全プロセスがプログラム中の「どこかの」 MPI_Barrier
を通過すれば計算が再開するので、留意する必要がある。
MPI_Gather
は、計算結果をどこかのプロセスに集約する命令。
MPI_Allgather
は、計算結果を全プロセスで共有する命令で、 MPI_Gather
を繰り返すより高速に動作する。
その他はネットで検索すればたくさん出てくる。
コンパイルではコマンド mpic++
を使う。
piano
には複数のOpen MPIが入っているが、ここでは /usr/local/openmpi-2.1.6-intel64-v15.0.2/bin/mpic++
を使うべきである。
これより古いバージョンには、ノード間並列化が実行できないバグがあるからである。
この mpic++
が実際に何をやっているのか知りたい場合、
mpic++ -show
とすればverboseな表示となる。
このときは、実行時の並列数などは考えずにコンパイルしよう。
CMakeを使う際は、 find_package(MPI REQUIRED)
などを書く必要がある(ネットに解説多数)。
例えば生成された a.out
を20並列で実行するには、
mpirun -np 20 ./a.out
とする。
投入するジョブスクリプトファイルでもPATHを通して、使用する mpirun
とコンパイル時に使った mpic++
のバージョンを同じにしよう。
さて、ここまではMPIの話であったが、以下ではジョブ管理システム torque
の使い方の話である。
希望する並列数が単一ノード上で用意できる場合、ジョブスクリプトに
#PBS -l nodes=1:ppn=20:X
#PBS -q beethoven01
と書けばノード指定して計算できる。
ノード指定しないで行う場合は、2行目末尾の :X
と 3行目を削除する。
ノード指定しない場合は、
#PBS -l nodes=2:ppn=10
と書く。 torque
が10コアの空きを2ノードで探して計算が開始される(合計20並列)。
ノード指定する場合は、
#PBS -l nodes=ika01:ppn=5+ika02:ppn=15
として、ノード名とコア数を指定する(これも合計20並列)。
この場合、ノードを表すアルファベットを書かなくてもノード指定できるが、 qstat
では default
と表示される。
なお、単一・複数どちらの場合も、PBSで指定した並列数の合計と mpirun -np
後に指定した並列数が合致することを確認しよう。