整数配列の配列 (基本的には 2 次元配列) をルートからすべてのプロセッサに渡す必要があります。C プログラムで MPI を使用しています。2 次元配列の MPI データ型を宣言する方法とメッセージの送信方法 (ブロードキャストまたはスキャッターを使用する必要があります)
4 に答える
同じメッセージのコピーをすべてのプロセスに送信するため、Broadcastを使用する必要があります。Scatterはメッセージを分割し、チャンクをプロセス間で分散します。
データの送信方法については、HIndexedデータ型が適しています。
2 次元配列が次のように定義されているとします。
int N; // number of arrays (first dimension)
int sizes[N]; // number of elements in each array (second dimensions)
int* arrays[N]; // pointers to the start of each array
最初に、データ型の開始アドレスに対する各配列の開始アドレスの変位を計算する必要があります。これは、便利にするために最初の配列の開始アドレスにすることができます。
MPI_Aint base;
MPI_Address(arrays[0], &base);
MPI_Aint* displacements = new int[N];
for (int i=0; i<N; ++i)
{
MPI_Address(arrays[i], &displacements[i]);
displacements[i] -= base;
}
次に、タイプの定義は次のようになります。
MPI_Datatype newType;
MPI_Type_hindexed(N, sizes, displacements, MPI_INTEGER, &newType);
MPI_Type_commit(&newType);
この定義は、次々にパックされたすべての配列を含むデータ型を作成します。これが完了したら、次のタイプの単一のオブジェクトとしてデータを送信します。
MPI_Bcast(arrays, 1, newType, root, comm); // 'root' and 'comm' is whatever you need
ただし、まだ完了していません。受信プロセスは、送信する配列のサイズを知る必要があります。コンパイル時にその知識が利用できない場合は、最初にそのデータを含む別のメッセージを送信する必要があります (int の単純な配列)。N
、sizes
およびが受信プロセスで上記と同様に定義され、配列を満たすのに十分なスペースが割り当てられている場合arrays
、受信プロセスで行う必要があるのは、同じデータ型 (送信者とまったく同じコード) を定義し、送信者のメッセージを受信することだけです。そのタイプの単一のインスタンスとして:
MPI_Bcast(arrays, 1, newType, root, comm); // 'root' and 'comm' must have the same value as in the sender's code
そして出来上がり!すべてのプロセスに配列のコピーが含まれるようになりました。
もちろん、2d 配列の 2 番目の次元が何らかの値に固定されている場合、物事はずっと簡単になりますM
。その場合、最も簡単な解決策は、単純に 1 つのint[N*M]
配列に格納することです。C++ は、すべてが連続したメモリであることを保証するため、次のように、カスタム データ型を定義せずにブロードキャストできます。
MPI_Bcast(arrays, N*M, MPI_INTEGER, root, comm);
注: HIndexed の代わりにIndexed型を使用しても問題が解決しない場合があります。違いは、Indexed では配列が要素数で与えられるのに対し、HIndexed ではバイト数であるということです (H は Heterogenous を表します)。インデックス付きを使用する場合は、 で指定された値を で割る必要があります。ただし、ヒープ上の任意の位置で定義された整数配列が C++ の整数制限に「整列」することが保証されているかどうかはわかりません。いずれにせよ、HIndexed バージョンは (わずかに) コードが少なく、同じ結果を生成します。displacements
displacements
sizeof(int)
連続したデータ ブロックを送信する場合 (C 配列は連続していると思いますが、私は Fortran プログラマーなのでよくわかりません)、新しい MPI データ型を宣言する必要はありません。をしたい。分散は、たとえば配列を多数のプロセスに分散させるためのものです。scatter を使用して、配列の各行を異なるプロセスに送信できます。したがって、整数の連続した配列の例では、最も簡単なオプションは次のようにブロードキャストすることです(私の貧弱なCスキルを念頭に置いて):
MPI_Bcast(&buf, numRows*numCols, MPI_INT, root, MPI_COMM_WORLD)
どこ
&buf
配列の最初の要素のアドレスです
numRows*numCols
もちろん、2D配列の要素数です
MPI_INT
(おそらく)使用する組み込みデータ型です
root
配列をブロードキャストしているプロセスのランクです
MPI_COMM_WORLD
通常のデフォルトのコミュニケータです。必要に応じて変更してください
また、ブロードキャストは集合的な操作であることを忘れないでください。すべてのプロセスが同じ呼び出しを行います。
配列が連続していない場合は、いくつかのサンプル配列サイズで再度投稿してください。MPI データ型を定義する方法を見つけます。
MPI_Send(tempmat,16,MPI_INT,0,0,MPI_COMM_WORLD);
MPI_Recv(resultmaster,16,MPI_INT,MPI_ANY_SOURCE , 0, MPI_COMM_WORLD, &stat);
上記の API を使用すると、マトリックスの最初の行しか取得できません。
仮想アドレスが異なる可能性があるため、配列の配列を別のプロセスに直接渡すことはできません。つまり、他の配列へのポインタを持つ最初の次元配列は、他のプロセスでは意味がありません。したがって、各配列を個別に渡し、受信側で「2D配列」を手動で再アセンブルする必要があります。
2)ブロードキャストvs.スキャッター。Broadcastは、コミュニケータ内の他のすべてのMPIランクに完全なアレイを送信します。Scatter(OTOH)は、ソース配列を他のすべてのMPIランクに分散します。つまり、ブロードキャストを使用すると、各ランクはソースアレイのコピーを受信し、スキャッターを使用すると、各ランクはアレイの異なる部分を受信します。