0

MPI2を使用すると、派生データ型を作成し、次のように記述して送信できます。

call mpi_type_create_indexed_block(size,1,dspl_send,rtype,DerType,ierr)
call mpi_send(data,1,DerType,jRank,20,comm,ierr)

これを行うことにより、data(N)の位置dspl_sendがMPIライブラリによって送信されます。

これで、行列データ(M、N)の場合、次のコードを介してその位置を送信できます。

call mpi_type_create_indexed_block(size,M,dspl_send,rtype,DerTypeM,ierr)
call mpi_send(data,1,DerTypeM,jRank,20,comm,ierr)

つまり、data(i、dspl_send(j))のエントリが送信されます。

私の質問は、後続のmpi_sendでの1の役割に関するものです。常に1である必要がありますか?別のサイズは可能ですか?MPIから派生したデータ型は、インターネット上の多くのドキュメントでうまく説明されていますが、send / recvのサイズは、別のサイズが許可されているかどうか、およびその使用方法は言うまでもなく、常に1です。

サイズMが呼び出しごとに異なる行列data(M、N)を処理する場合、呼び出すたびに常に派生データ型を作成する必要がありますか?行列データ(M、N)またはデータ(N、M)を送信するためにDerTypeを使用することは不可能ですか?

4

2 に答える 2

3

各 MPI データ型には、サイズと範囲という 2 つのプロパティがあります。サイズはデータ型が表す実際のバイト数であり、エクステントはデータ型がメモリ内でカバーするバイト数です。一部のデータ型は連続していません。つまり、サイズがその範囲よりも小さい場合があります。たとえば、(ここでは疑似コードで示されています)

MPI_TYPE_VECTOR(count = 1,
                blocklength = 10,
                stride = 20,
                oldtype = MPI_INTEGER,
                newtype = newtype)

blocklength合計 20 ( ) の要素から最初の 10 ( ) 要素を取るデータ型を作成しますstride。このデータ型のサイズは、ほとんどのシステムでバイトとしてカウントされるサイズの10倍です。その範囲は、ほとんどのシステムで 2 倍またはバイトです。が 2 の場合、10 個の要素を取り、次の 10 個をスキップし、さらに 10 個の要素を取り、次の 10 個をもう一度スキップします。したがって、そのサイズと拡張は 2 倍になります。MPI_INTEGER4080count

MPI ルーチンで特定の要素数を指定すると、たとえばMPI_SEND、MPI は次のように処理します。

  1. ソース バッファ引数のアドレスで内部データ バッファを初期化します。
  2. データ型の型マップを調べて、何バイト、どこから取得するかを決定し、それらを構築中のメッセージに追加します。追加されるバイト数は、データ型のサイズと同じです。
  3. 内部データ ポインタをデータ型の範囲だけインクリメントします。
  4. 内部カウントをデクリメントし、まだゼロでない場合は、前の 2 つの手順を繰り返します。

MPI の優れた機能の 1 つは、データ型のエクステントがそのサイズと一致する必要がないことです (ベクトルの例に示されているように) MPI_TYPE_CREATE_RESIZED。これにより、非常に複雑なデータ アクセス パターンを作成できます。たとえば、MPI_SCATTERV行全体 (C) または列全体 (Fortran) にまたがらないブロックごとに行列を分散させるために使用するには、そのようなサイズ変更された型を使用する必要があります。

ベクトルの例に戻ります。でベクトル型を作成してでcount = 1呼び出すか、 でベクトル型を作成してで呼び出すかに関係なく、最終結果は同じです。多くの場合、送信したいオブジェクトを完全に記述するデータ型を構築します。この場合、 への呼び出しで与えます。ただし、オブジェクトの一部 (たとえば単一のパーツ) のみを記述するデータ型を作成し、送信するパーツの数を設定して呼び出す方が有益な場合があります。個人的な好みの問題である場合もあれば、アルゴリズムの要件の問題である場合もあります。MPI_SENDcount = 2count = 2MPI_SENDcount = 1count = 1MPI_SENDMPI_SENDcount

最後の質問については、Fortran は行列を列優先順で格納しdata(i,j)ます。したがって、各要素の連続した列ベクトルで構成されます。となどの 2 つの要素間の距離は、 に依存します。そのため、型コンストラクターで指定します。行数が異なる (例: が異なる) 行列は、作成された型の型マップに「適合」せず、メッセージの作成に間違った要素が使用されます。data(i±1,j)data(i,j±1)data(M,N)NMdata(1,1)data(1,2)MMM

于 2012-12-10T13:47:53.680 に答える
0

https://stackoverflow.com/a/13802243/7784768のエクステントに関する説明は、エクステントがデータ型の最後のパディングを考慮していないため、完全には正しくありません。MPI データ型は typemap によって定義されます。

typemap = ((type_0, disp_0 ), ..., (type_n−1, disp_n−1 ))

エクステントは、次のように定義されます。

lb = min(disp_j)
ub = max(disp_j + sizeof(type_j)) + e)
extent = ub - lb,

ここで、e は、アラインメント要件によりゼロ以外にすることができます。

つまり、この例では

MPI_TYPE_VECTOR(count = 1,
                blocklength = 10,
                stride = 20,
                oldtype = MPI_INTEGER,
                newtype = newtype)

count=1 の場合、typemap は

((int, 0), (int, 4), ... (int, 36))

また、エクステントはほとんどのシステムで 40 であり、80 ではありません (つまり、この場合、ストライドは typemap に影響しません)。count=2 の場合、typemap は次のようになります。

((int, 0), (int, 4), ... (int, 36), (int, 80), (int, 84), ... (int, 116))

エクステント 120 (10 個の整数の最初のブロックに 40 バイト、ストライドに 40 バイト、10 個の整数の 2 番目のブロックに 40 バイト。ただし、エクステントでは残りのストライドは無視されます)。MPI_Type_get_extent 関数を使用すると、エクステントを簡単に見つけることができます。

範囲は非常にトリッキーな概念であり、派生データ型の複数の要素を通信しようとすると、間違いを犯しやすくなります。

于 2017-03-29T09:46:36.897 に答える