OpenMPI で配列をまとめる
やりたいこと
プロセス数 allrank を 4 として、 各 myrank の配列 my_array[3]
myrank == 0 ... my_array[3] = {0,1,2}; myrank == 1 ... my_array[3] = {3,4,5}; myrank == 2 ... my_array[3] = {6,7,8}; myrank == 3 ... my_array[3] = {9,10,11};
をまとめて、各 myrank の配列 all_array[12]
myrank == 0 ... all_array[12] = {0,1,2,3,4,5,6,7,8,9,10,11} myrank == 1 ... all_array[12] = {0,1,2,3,4,5,6,7,8,9,10,11} myrank == 2 ... all_array[12] = {0,1,2,3,4,5,6,7,8,9,10,11} myrank == 3 ... all_array[12] = {0,1,2,3,4,5,6,7,8,9,10,11}
を作りたい。
戦略
MPI_Gather と MPI_Bcast を組み合わせれば、達成できそう。
MPI_Gather
MPI_Bcast
ソースコード
// distribute_array.c // myrank == 0 : my_array[3] = {0,1,2}; // myrank == 1 : my_array[3] = {3,4,5}; // myrank == 2 : my_array[3] = {6,7,8}; // myrank == 3 : my_array[3] = {9,10,11}; // をまとめて // all_array[12] = {0,1,2,3,4,5,6,7,8,9,10,11} // をつくる #include <stdio.h> #include <mpi.h> int main(int argc, char **argv){ // MPIの初期設定 MPI_Init(&argc, &argv); int myrank, allrank; MPI_Comm_rank(MPI_COMM_WORLD, &myrank); MPI_Comm_size(MPI_COMM_WORLD, &allrank); // 各myrankで配列my_arrayを宣言 int my_array[3]; // 配列初期化 my_array[0] = 0 + 3*myrank; my_array[1] = 1 + 3*myrank; my_array[2] = 2 + 3*myrank; printf("rank=%d/%d %d %d %d\n", myrank, allrank, my_array[0], my_array[1], my_array[2]); // 各myrankで配列all_arrayを宣言 int all_array[12] = {0}; // 3*allrank個の配列 // 各myrankのmy_arrayを、myrank==0のall_arrayに集めて代入 MPI_Gather( my_array , // 送信する配列の最初のアドレス // 送信データが配列ではなく、普通の値の場合でも、アドレスを渡す 3 , // 各ランク毎に何個のデータを送信するのか // 送信データが配列ではなく、普通の値の場合は 1 とする MPI_INT , // 送信するデータの型。'int' ではないので注意 all_array , // 受信する配列の最初のアドレス 3 , // 各ランク毎に何個のデータを受信するのか // 3つ上の引数と一致するはず MPI_INT , // 受信するデータの型。'int' ではないので注意 0 , // どのrankのall_arrayに入れるか MPI_COMM_WORLD // コミュニケータ。MPI_COMM_WORLD としておく ); // ここで if(myrank == 0){...} として、作成したall_array[12]を処理すると便利 // この時点では、myrank==0のall_arrayにしかデータが入っていない。 printf("Before Bcast rank=%d/%d :", myrank, allrank); int n; for (n = 0; n < 12; n++) { printf("%d ", all_array[n]); } printf("\n"); // myrank==0のall_arrayを各myrankのall_arrayにコピー MPI_Bcast( all_array , // 送受信する配列の最初のアドレス 12 , // 送受信するデータの数 MPI_INT , // 送受信するデータの型 0 , // どのmyrankのデータを送信するか MPI_COMM_WORLD // コミュニケータ。MPI_COMM_WORLD としておく ); // MPI_Bcastしたので、全てのmyrankのall_arrayが同等になった printf("After Bcast rank=%d/%d :", myrank, allrank); for (n = 0; n < 12; n++) { printf("%d ", all_array[n]); } printf("\n"); MPI_Finalize(); }
コンパイルと実行
$ mpicc ./distribute_array.c $ mpirun -np 4 a.out rank=3/4 9 10 11 Before Bcast rank=3/4 :0 0 0 0 0 0 0 0 0 0 0 0 rank=2/4 6 7 8 rank=0/4 0 1 2 Before Bcast rank=2/4 :0 0 0 0 0 0 0 0 0 0 0 0 rank=1/4 3 4 5 Before Bcast rank=1/4 :0 0 0 0 0 0 0 0 0 0 0 0 Before Bcast rank=0/4 :0 1 2 3 4 5 6 7 8 9 10 11 After Bcast rank=2/4 :0 1 2 3 4 5 6 7 8 9 10 11 After Bcast rank=0/4 :0 1 2 3 4 5 6 7 8 9 10 11 After Bcast rank=1/4 :0 1 2 3 4 5 6 7 8 9 10 11 After Bcast rank=3/4 :0 1 2 3 4 5 6 7 8 9 10 11
参考:
- MPIリファレンス
- 統計物理屋のための簡単 MPI 講座 ← OpenMPIの初心者向け解説(C言語)。オススメ