MPI_Scattervは「あるプロセスが持つデータを,任意に分割して,各々のプロセスに配分する関数」。
※MPI_Scatterは「あるプロセスが持つデータを,等分して,各々のプロセスに配分する関数」であったことに注意。
【目的】
あるプロセスに存在する一次元配列 send から適当な数(eachsz)の要素だけ取り出して、各々のプロセスにある一次元配列 recv に代入することでMPI_Scatterv の機能を知る。
【使用するもの】
open-mpi
【環境】
$ mpicc —version
Apple clang version 11.0.3 (clang-1103.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
【方法】
#include<stdio.h>
#include<mpi.h>
int main(int argc, char **argv){
int i;
int my_rank, num_proc;
int send[20];
int recv[10];
int eachsz[2] = {3,8};
int place[2];
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_proc);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
for(i=0;i<10;i++) recv[i] = -1;
if(my_rank == 1){
for(i=0;i<20;i++) send[i] = i;
for(i=0;i<2;i++) place[i] = 10*i;
}
MPI_Scatterv(send, eachsz, place, MPI_INT, recv, eachsz[my_rank], MPI_INT, 1,MPI_COMM_WORLD);
printf("myrank %d:", my_rank);
for(i=0;i<10;i++) printf(" %2d",recv[i]);
printf("\n");
MPI_Finalize();
return 0;
}
【結果】
mpicc コマンドでコンパイル、mpirun コマンドでプロセス数を2にして実行。
$ mpicc Scatterv.c
$ mpirun -np 2 ./a.out
myrank 0: 0 1 2 -1 -1 -1 -1 -1 -1 -1
myrank 1: 10 11 12 13 14 15 16 17 -1 -1
【考察(何が起きたのか)】
まずプロセス0と1でそれぞれ send[0]、send[1]、…、send[19] が生成される。
プロセス0と1でそれぞれ recv[0]、recv[1]、…、recv[9] が生成される。
プロセス0と1でそれぞれ eachsz[0](=3)、eachsz[1](=8) が生成される。
プロセス0と1でそれぞれ place[0]、place[1] が生成される。
それぞれのプロセスでのfor文で値が格納される。
at プロセス0 recv[0]=-1、 recv[1]=-1、…、recv[9]=-1
at プロセス1 recv[0]=-1、 recv[1]=-1、…、recv[9]=-1
at プロセス1 send[0]=0、send[1]=1、…、send[19] =19
at プロセス1 place[0]=0、place[1]=10
MPI_Scattervによって「send」から各プロセスに個数「eachsz」のデータが送られる。各プロセスに送られるデータの場所(配列のインデックス)は「place」。つまり、place[0]=0なのでsend[0]から数えてeachsz[0]個のデータ、place[1]=10なのでsend[10]から数えてeachsz[1]個のデータが送信される。
送るデータの型は整数(int)「MPI_INT」。各プロセスの「recv」は、それぞれ「eachsz[my_rank] 」個の要素を受け取る。つまり、プロセス0は3個(eachsz[0]=3)、プロセス1は8個(eachsz[1]=8)の要素を受け取る。受け取るデータの型は整数(int)「MPI_INT」。データはプロセス「1」から送信される。
よって
at プロセス0
recv[0](= プロセス1の send[0])=0、
recv[1](= プロセス1の send[1])=1、
recv[2](= プロセス1の send[2])=2
となる。さらに
at プロセス1
recv[0](= プロセス1の send[10])=10、
recv[1](= プロセス1の send[11])=11、
…、
recv[7](= プロセス1の send[17])=17
となる。
それぞれのプロセスで recv が表示されて終了。
【参考】
「mpi 並列プログラミング」と検索すると、より正確でより情報量の多い資料が見つかります。