MPI は、このような種類の問題に対してストライド ベクトル型を提供します。このような型は、列の高さの合計に等しいストライドと、サブブロック内の行数に等しいブロック サイズを使用して作成します。また、この型には、行の列数と等しい数を指定します。具体的な例を次に示します。行と列REAL
を含む行列があり、各プロセスが行を含むサブブロックを保持しているとします。次に、次のようにします。nr
nc
nr1
integer :: rowtype
call MPI_TYPE_VECTOR(nc, nr1, nr, MPI_REAL, rowtype, ierr)
call MPI_TYPE_COMMIT(rowtype, ierr)
row で始まるサブブロックにデータを受け取りたいとしましょうmyrow
。この新しいタイプを使用すると、次のことが簡単にできます。
call MPI_RECV(array(myrow,1), 1, rowtype, src, tag, &
MPI_COMM_WORLD, status, ierr)
それはそのように動作します-サブブロックのトップレフ要素の提供されたアドレス(つまり、array(myrow,1)
)から開始nr1
して、受信したメッセージから要素を配置し、次にnr - nr1
の要素をスキップし、さらに要素を配置し、再び要素をスキップするなど、時間を繰り返します.array
nr1
nr - nr1
nc
しかし、ここで問題があります。rowtype
型の範囲はnc*nr
要素になります。MPI_(ALL)GATHERV()
タイプ エクステントの倍数、つまりnc*nr
、この制限を克服するために、MPI では を使用して型の範囲を人為的に変更できますMPI_TYPE_CREATE_RESIZED
。型を取り、同じ型マップを持つ新しい型を構築します (たとえば、古い型と同じ「レシピ」を使用してメモリ内の要素をレイアウトします) が、型の範囲に依存するオフセットやその他のものを計算する場合、MPI は実際の値の代わりにユーザーが提供した値を使用します。あなたがする必要があるのは、型の要素のmyrow
範囲と等しくなるように範囲を変更することですnr1
MPI_REAL
. これは次のように行われます。
integer(kind = MPI_ADDRESS_KIND) :: lb, extent
integer :: rowtype_resized
call MPI_TYPE_GET_EXTENT(MPI_REAL, lb, extent, ierr)
extent = extent * nr1
call MPI_TYPE_CREATE_RESIZED(rowtype, 0, extent, rowtype_resized, ierr)
call MPI_TYPE_COMMIT(rowtype_resized, ierr)
行と列rowtype_resized
のサブブロックを受け取るために を使用できるようになりましたが、 の合計サイズの倍数だけでなく、複数の大きな任意の行から開始するようにそれらを配置できます。その後、次のように続行できます。nr1
nc
array
nr1
array
call MPI_ALLGATHER(smallarray, nr1*nc, MPI_REAL, &
array, 1, rowtype_resized, MPI_COMM_WORLD, ierr)
smallarray
これにより、小さな配列(nr1
行とnc
列のそれぞれ) の内容が大きな配列array
(nr1 * #processes
行と列のそれぞれ)に集められnc
ます。
さらに柔軟に、 の代わりに 1 のブロック長で vector 型を登録することもできますnr1
。これにより、単一の行を送信できます。次に、1 つのMPI_REAL
要素の範囲でサイズ変更された型を作成し、MPI_(ALL)GATHERV
異なるサイズのサブブロックを収集するために使用できます。
少しトリッキーであることはわかっていますが、いずれ MPI の型システムを習得する方法を学ぶことができます。