FORTRAN 90 で多次元配列のチャンクを送受信 (MPI) する必要があります。
MPI_Send(x(2:5,6:8,1),12,MPI_Real,....)
Gropp、Lusk、および Skjellum による本「Using MPI...」に従って、使用することは想定されていません。これを行う最善の方法は何ですか?一時的な配列を作成して送信するか、使用するMPI_Type_Create_Subarray
か、そのようなものを使用する必要がありますか?
FORTRAN 90 で多次元配列のチャンクを送受信 (MPI) する必要があります。
MPI_Send(x(2:5,6:8,1),12,MPI_Real,....)
Gropp、Lusk、および Skjellum による本「Using MPI...」に従って、使用することは想定されていません。これを行う最善の方法は何ですか?一時的な配列を作成して送信するか、使用するMPI_Type_Create_Subarray
か、そのようなものを使用する必要がありますか?
配列セクションを使用しない理由は、コンパイラが一部のMPI 実装MPI_SEND
で一時コピーを作成する必要があるためです。これは、Fortran が配列セクションを明示的なインターフェイスを持つサブルーチンに正しく渡すことしかできず、それ以外の場合はすべて、通常は呼び出しサブルーチンのスタックで、一時的な「フラット化された」コピーを生成する必要があるためです。残念ながら、F2008 への TR 29113 拡張より前の Fortran では、変数型の引数を取るサブルーチンを宣言する方法がなく、MPI 実装は通常言語ハックに頼っています。たとえば、完全に C で実装されており、常にデータをポインターとして渡す Fortran に依存しています。MPI_Send
一部の MPI ライブラリは、次のように膨大な数のオーバーロードを生成することで、この問題を回避しますMPI_SEND
。
INTEGER
INTEGER
INTEGER
CHARACTER
、LOGICAL
、などに対して同じことが繰り返されDOUBLE PRECISION
ます。これは、ユーザー定義型を渡すケースをカバーしていないため、依然としてハックです。さらに、コンパイラ固有の Fortran 配列記述子を理解する必要があるため、C の実装が非常に複雑になります。
幸いなことに、時代は変わりつつあります。Fortran 2008 の TR 29113 拡張機能には、次の 2 つの新機能が含まれています。
TYPE(*)
DIMENSION(..)
両方の組み合わせ、つまりTYPE(*), DIMENSION(..), INTENT(IN) :: buf
は、さまざまな型と任意の次元の両方を持つことができる引数を記述します。mpi_f08
これは、MPI-3の新しいインターフェイスですでに利用されています。
ノンブロッキング呼び出しは、Fortran で Alexander Vogt が説明した以上の大きな問題を引き起こします。その理由は、Fortran にはコンパイラの最適化を抑制するという概念がないためです (つまりvolatile
、Fortran にはキーワードがありません)。次のコードは、期待どおりに実行されない可能性があります。
INTEGER :: data
data = 10
CALL MPI_IRECV(data, 1, MPI_INTEGER, 0, 0, MPI_COMM_WORLD, req, ierr)
! data is not used here
! ...
CALL MPI_WAIT(req, MPI_STATUS_IGNORE, ierr)
! data is used here
への呼び出しの後に、MPI_WAIT
data
ランク 0 から受け取った値が含まれると予想されるかもしれませんが、そうではない可能性があります。その理由は、コンパイラがリターンdata
後に が非同期に変更される可能性があることを認識できないMPI_IRECV
ため、代わりにその値をレジスタに保持するためです。これが、非ブロッキング MPI 呼び出しが一般に Fortran で危険であると見なされる理由です。
TR 29113 には、ASYNCHRONOUS
属性に関する 2 番目の問題に対する解決策もあります。mpi_f08
の定義を見るとMPI_IRECV
、そのbuf
引数は次のように宣言されています。
TYPE(*), DIMENSION(..), INTENT(OUT), ASYNCHRONOUS :: buf
がスカラー引数の場合、つまり一時コピーが作成されない場合でもbuf
、TR 29113 準拠のコンパイラは、バッファー引数の最適化を登録することに頼りません。
編集:Hristo Ilievが指摘したようMPI_Send
に、常にブロックされていますが、データを非同期に送信することを選択する場合があります。ここから:
MPI_Send は、送信バッファーを使用できるようになるまで戻りません。
非ブロック通信 ( などMPI_Send
) は、連続していない配列が関係している場合、Fortran で問題を引き起こす可能性があります。次に、コンパイラはダミー変数の一時配列を作成し、それをサブルーチンに渡します。サブルーチンが終了すると、コンパイラはそのコピーのメモリを自由に解放できます。
MPI_Send
サブルーチンが戻ったときにメッセージが送信されているため、ブロック通信 ( ) を使用している限り問題ありません。ただし、非ブロッキング通信 ( MPI_Isend
) の場合、一時配列は送信バッファーであり、サブルーチンは送信される前に戻ります。
そのため、MPI が有効なデータを保持していないメモリ位置からデータを送信する可能性があります。
そのため、自分でコピーを作成する (送信バッファーがメモリ内で連続するようにする) か、サブ配列を作成します (つまり、送信する要素のメモリ内のアドレスを MPI に伝えます)。など、他にも選択肢がありますがMPI_Pack
、私はそれらの経験がありません。
どちらの方法が速いですか?まあ、それは依存します:
詳細な説明とその他のオプションについては、こちらを参照してください。