fortran+MPIコーディング入門(1) プロセス並列の基本


前回までで環境構築は済んだものとして、今回からコーディングに入っていきます。

目次(予定)

  1. 並列処理とは
  2. プロセス並列の基本 ←今ココ
  3. 集団通信
  4. 1対1通信
  5. オブジェクト指向コードの並列化

プロセスとランク

プロセスとは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_rankmpi_comm_sizeを使います。

fortranでは配列などの機能は1から始まるのに対し、ランクは0から始まるので注意が必要です。

mpiプログラムのコンパイルと実行

mpiコードをコンパイルする場合はmpif90を用います。

mpif90 -o smp01 smp01.f90

実行する場合も通常と異なり、openmpiを自前で実装した場合はmpiexecもしくはmpirunを用います。このとき-npオプションで並列数、つまりサイズを指定します。

mpiexec -np 4 smp01

サンプルコード

smp01.f90
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つのファイルにログを書き込んだりすると、どの内容がどのプロセスが書き込んだものかわからなくなります。そのためファイルに出す場合は別ファイルに出すようにしたほうがいいでしょう。

参考文献


  1. 基本的にinclude文はコードを内容結合にしてしまい可読性を著しく落とすため、用いるべきではありません。今回のように一般的な信頼できる外部ライブラリを用いる場合は例外ですが、自作のコードをincludeするようなことはやめましょう。