前回までで環境構築は済んだものとして、今回からコーディングに入っていきます。
目次(予定)
- 並列処理とは
- プロセス並列の基本 ←今ココ
- 集団通信
- 1対1通信
- オブジェクト指向コードの並列化
プロセスとランク
プロセスとはMPIで並列化する処理の単位です。MPIプログラムではプロセスが複数並行して動作します。プロセスは共通の処理を行いますがそれぞれのメモリを持ち、それぞれの変数で同じ処理を行います。
プロセスには通し番号が振られており、その番号をランクと言います。またプロセスの個数をサイズと言います。
たとえば以下の画像のようなコードを書くと、各プロセスが各プロセスの変数xx、yyを持ちます。(ここでmyrankはランクを格納しているとします。)これらの変数は通信しないと同期されたりはしません。
基本的なコマンド
mpif.hのインクルード
mpiを用いるために、まずmpif.h
(fortranの場合)をincludeします 1 。場所はimplicit none
の後です。
起動処理と終了処理
mpiを用いるためには、コードの最初にmpi_init(ierr)
を呼び出します。ierr
はエラー番号を受けるためのinteger型変数で、事前に宣言する必要があります。
またコードの最後には終了処理としてmpi_finalize(ierr)
を呼び出します。
ランク、サイズの取得
ランク、サイズを取得するためには、それぞれサブルーチンmpi_comm_rank
、mpi_comm_size
を使います。
fortranでは配列などの機能は1から始まるのに対し、ランクは0から始まるので注意が必要です。
mpiプログラムのコンパイルと実行
mpiコードをコンパイルする場合はmpif90
を用います。
mpif90 -o smp01 smp01.f90
実行する場合も通常と異なり、openmpiを自前で実装した場合はmpiexec
もしくはmpirun
を用います。このとき-npオプションで並列数、つまりサイズを指定します。
mpiexec -np 4 smp01
サンプルコード
program main
implicit none
include 'mpif.h'
integer :: nnn
integer :: me
integer :: ierr
call mpi_init(ierr)
call mpi_comm_size(mpi_comm_world,nnn,ierr)
call mpi_comm_rank(mpi_comm_world,me,ierr)
write(6,*) "I am ",me,"/",nnn
call mpi_finalize(ierr)
end program main
このコードでは、それぞれのプロセスが自分のランクが何プロセス中の何番目なのかを取得して出力します。
各プロセスはnnnにサイズを、meにランクを書き込みます。そのため当然のように、各プロセスは各プロセスの変数nnn、meを持ちます。ですがnnn、meを出力するという処理はまったく同じです。
ここでmpi_comm_world
はmpiコミュニケータと呼ばれるもので、プロセスの集合の名前のようなものです。基本的にはこの名前で使う場合が多いです。
結果
4並列で実行した場合の結果例は、以下のようになります。
I am 1 / 4
I am 3 / 4
I am 0 / 4
I am 2 / 4
おのおののプロセスは自分が準備できたタイミングでwriteするため、必ずしもランクが小さい順に並んだりはしません。
そのため1つのファイルにログを書き込んだりすると、どの内容がどのプロセスが書き込んだものかわからなくなります。そのためファイルに出す場合は別ファイルに出すようにしたほうがいいでしょう。
参考文献
-
基本的にinclude文はコードを内容結合にしてしまい可読性を著しく落とすため、用いるべきではありません。今回のように一般的な信頼できる外部ライブラリを用いる場合は例外ですが、自作のコードをincludeするようなことはやめましょう。 ↩