• 検索結果がありません。

ブロードキャスト

ドキュメント内 mpi-report-j.dvi (ページ 134-146)

MPI BCAST(buer,count, datatype,root,comm )

入出力 buer バッファの開始アドレス(choice)

入力 count バッファ内の要素の数(integer)

入力 datatyp e バッファのデータタイプ(handle)

入力 root ブロードキャスト・ルートのランク(integer)

入力 comm コミュニケータ(handle)

int MPI Bcast(void* buffer, int count, MPI Datatype datatype, int root, M

PI Comm comm )

MPI BCAST(BUFFER, COUNT, DATATYPE, ROOT, COMM, IERROR)

<type> BUFFER(*)

INTEGER COUNT, DATATYPE, ROOT, COMM, IERROR

MPI BCASTは、ランクがrootであるプロセスからそのプロセスを含むグループ内の全プ

ロセスへメッセージをブロードキャストする。commおよびrootとして同じ引数を使って全グ ループ・メンバにより呼び出される。戻った時点で、rootの通信バッファの内容が全プロセス へコピーされている。

一般にdatatypeとして、派生データタイプが許される。どのプロセスのcountdatatyp e の値もルートのcountdatatypeのそれと等しくなければならない。

このことは、各プロセスとルートの間で、送信データの量と受け取るデータの量が等しく なければならないということを意味している。MPI BCASTおよび他のすべてのデータ通信集 団ルーチンはこの制約を課している。ただし送信側と受信側とで型マップの異なりだけは許され る。

4.4.1 MPI BCASTの使用例

4.1 プロセス0からグループ内のすべてのプロセスへ100個の整数をブロードキャストする。

MPI\_Comm comm;

int array[100];

int root=0;

...

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

ここで取りあげる一部分のコードの多くは、変数(上記のcommなど)に適切な値が代入さ れているものと仮定している。

4.5 Gather

MPI GATHER(sendbuf, sendcount, sendtyp e,recvbuf, recvcount, recvtype, root,comm)

入力 sendbuf 送信バッファの開始アドレス(choice)

入力 sendcount 送信バッファの要素の数(integer)

入力 sendtyp e 送信バッファの要素のデータタイプ(handle)

出力 recvbuf 受信バッファのアドレス(choice, ルートでのみ意味をも

)

入力 recvcount numberofelementsforanysinglereceive(integer,ルー トでのみ意味をもつ)

入力 recvtyp e 受信バッファ要素のデータタイプ(ルートでのみ意味をも

)(handle)

入力 root 受信プロセスのランク(integer) 入力 comm コミュニケータ(handle)

int MPI Gather(void* sendbuf, int sendcount, MPI Datatype sendtype, void*

recvbuf, int recvcount, MPI Datatype recvtype, int root,

MPI Comm comm)

MPI GATHER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE ,

ROOT, COMM, IERROR)

<type> SENDBUF(*), RECVBUF(*)

INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR

各プロセス(ルートプロセスを含む)は、送信バッファの内容をルートプロセスへ送信す る。ルートプロセスはメッセージを受信し、ランクの順番に格納する。その結果は、グループの 中のn個のプロセス(ルートプロセスを含む)が次のルーチンの呼び出しを実行し

MPI Send(sendbuf;sendcount;sendtype;root;:::);

さらに次の呼び出しをn回実行した結果と同じである。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

ここで、extent(recvtype)はMPI Type extent()を呼び出して得られる型の大きさで ある。

言い換えると、グループ内のプロセスが送信したn個のメッセージをランク順に連結し、得 られたメッセージをMPI RECV(recvbuf, recvcount1n, recvtyp e, ...)を呼び出して受け取ったか のようにルートが受信する。

ルート以外の全てのプロセスについては受信バッファは無視される。

通常、sendtyp erecvtypeには派生データタイプが許される。プロセスisendcount

sendtypeは、ルートのrecvcountrecvtyp eと等しくなければならない。このことは、各プロセ スとルートの間で、送信データの量と受け取るデータの量が等しくなければならないということ を意味する。ただし送信側と受信側とで型マップの異なりは許される。

rootのプロセスでは関数への全ての引数は意味を持つが、他のプロセスでは引数sendbuf

sendcount、sendtyperootcommのみが意味を持つ。引数rootおよびcommは全てのプロ セスで同じ値でなければならない。

個数と型の指定は、ルートプロセス上の同じ位置に複数回書き込まれることがあってはなら ない。そのような呼び出しはエラーである。

ルートプロセスの引数recvcountは各プロセスから受信する要素数を示しているのであって、

受信する要素の総数を示しているのではないことに注意すること。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

MPI GATHERV( sendbuf, sendcount, sendtype, recvbuf, recvcounts, displs, recvtype, root,

comm)

入力 sendbuf 送信バッファの開始アドレス(choice)

入力 sendcount 送信バッファの要素の数(integer)

入力 sendtyp e 送信バッファの要素のデータタイプ(handle)

出力 recvbuf 受信バッファのアドレス(choice, ルートでのみ意味をも

)

入力 recvcounts (グループサイズの長さの)整数配列各プロセスから受け

取る要素の数を含んでいる(ルートでのみ意味をもつ)

入力 displs (グループサイズの長さの)整数配列。プロセスiから送

れて来るデータを置く場所をrecvbufからの相対位置とし てi番目の要素に指定(ルートでのみ意味をもつ)

入力 recvtyp e 受信バッファ要素のデータタイプ(ルートでのみ意味をも

)(handle)

入力 root データを受信するプロセスのランク(integer)

入力 comm コミュニケータ(handle)

int MPI Gatherv(void* sendbuf, int sendcount, MPI Datatype sendtype, void

* recvbuf, int *recvcounts, int *displs,

MPI Datatype recvtype, int root, MPI Comm comm)

MPI GATHERV(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNTS, DISPLS ,

RECVTYPE, ROOT, COMM, IERROR)

<type> SENDBUF(*), RECVBUF(*)

INTEGER SENDCOUNT, SENDTYPE, RECVCOUNTS(*), DISPLS(*), RECVTYPE, ROOT,

COMM, IERROR

MPI GATHERVはMPI GATHERの機能を拡張したもので、recvcountsが配列になってお り、各プロセスから可変個のデータを受け取れるようになっている。さらに、新しい引数として

displsを提供することにより、ルート上のデータの配置に関して自由度が増している。

結果としては、ルートプロセスを含む各プロセスがメッセージをルートへ送り、

MPI Send(sendbuf;sendcount;sendtype;root;:::);

ルートプロセスが受信をn繰り返した場合と同じである。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

メッセージはルートプロセスの受信バッファの中にランク順に配置される。つまり、プロ セスjから送られたデータはルートプロセスの受信バッファrecvbufj番目の部分に配置され る。recvbufj番目の部分はrecvbufをベースにしたオフセットdispls[j]要素(recvtyp eの表現 で)から始まる。

ルート以外の全てのプロセスでは、受信バッファは無視される。

プロセスisendcountsendtyp eは、ルートのrecvcounts[i]、recvtyp eと等しくなければ ならない。このことは、各プロセスとルートとの間で、送信データの量が受け取るデータの量と 等しくなければならないということを意味する。ただし、例4.6に示されているように、送信側 と受信側とで型マップの違いは許される。

rootプロセスでは、全ての引数が意味を持つが、それ以外のプロセスでは引数sendbuf

send-count、sendtyperootcommのみが意味をもつ。引数rootおよびcommは全てのプロセス で値が同一でなければならない。

個数と型の指定により、ルートプロセス上の同じ位置に複数回書き込まれることがあっては ならない。そのような呼び出しはエラーである。

4.5.1 MPI GATHER、MPI GATHERVの使用例

4.2 グループ内のすべてのプロセスからルートへ100個の整数を収集する。図4.2を参照の こと。

MPI_Comm comm;

int gsize,sendarray[100];

int root, *rbuf;

...

MPI_Comm_size( comm, &gsize)

rbuf = (int *)malloc(gsize*100*sizeof(int));

MPI_Gather( sendarray, 100, MPI_INT, rbuf, 100, MPI_INT, root, comm);

4.3 前の例の手直し−ルートだけが受信バッファ用のメモリを割り当てる。

MPI_Comm_rank( comm, myrank);

if ( myrank == root) {

MPI_Comm_size( comm, &gsize);

rbuf = (int *)malloc(gsize*100*sizeof(int));

}

MPI_Gather( sendarray, 100, MPI_INT, rbuf, 100, MPI_INT, root, comm);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

100 100 100

100 100

all processes

100

rbuf

at root

4.2: ルートプロセスがグループ内の各プロセスから100個の整数を収集する。

4.4 前の例と同じことをしているが、派生データタイプを使用している。gatherではルート プロセスと各プロセスとの間で型対応が行われているので、その型はgsize*100個の整数の集ま りと一致しない。

MPI_Comm comm;

int gsize,sendarray[100];

int root, *rbuf;

MPI_Daratype rtype;

...

MPI_Comm_size( comm, &gsize);

MPI_Type_contiguous( 100, MPI_INT, &rtype );

MPI_Type_commit( &rtype );

rbuf = (int *)malloc(gsize*100*sizeof(int));

MPI_Gather( sendarray, 100, MPI_INT, rbuf, 1k rtype, root, comm);

4.5 各プロセスはルートへ100個の整数を送信するが、それぞれを、整数stride個分だけの 間隔をおいて配置する。MPIGATHERV関数およびdispls引数を使用してこの効果を得るこ とが出来る。stride100と仮定する。図4.3を参照のこと。

MPI_Comm comm;

int gsize,sendarray[100];

int root, *rbuf, stride;

int *displs,i,*rcounts;

...

MPI_Comm_size( comm, &gsize);

rbuf = (int *)malloc(gsize*stride*sizeof(int));

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

100 100 100

100 100 100

stride rbuf

at root all processes

4.3: ルートプロセスは、グループ内の各プロセスから100個の整数を集め(gather)、各々

を整数stride個分だけ間隔をおいて配置する。

rcounts = (int *)malloc(gsize*sizeof(int));

for (i=0; i<gsize; ++i) {

displs[i] = i*stride;

rcounts[i] = 100;

}

MPI_Gatherv( sendarray, 100, MPI_INT, rbuf, rcounts, displs, MPI_INT,

root, comm);

stride<100だと、プログラムは誤りであることに注意。

4.6 受信側についての例4.5と同じ。ただし、C言語における1002150の整数配列の第0列 から100個の整数を送信する。図4.4を参照のこと。

MPI_Comm comm;

int gsize,sendarray[100][150];

int root, *rbuf, stride;

MPI_Datatype stype;

int *displs,i,*rcounts;

...

MPI_Comm_size( comm, &gsize);

rbuf = (int *)malloc(gsize*stride*sizeof(int));

displs = (int *)malloc(gsize*sizeof(int));

rcounts = (int *)malloc(gsize*sizeof(int));

for (i=0; i<gsize; ++i) {

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

100 100 100

150

rbuf

at root stride

all processes 100

150

100

150

100

4.4: ルート・プロセスはC言語における1002150配列の第0列を集め,各々を整数stride 個分だけ間隔をおいて配置する。

rcounts[i] = 100;

}

/* Create datatype for 1 column of array

*/

MPI_Type_vector( 100, 1, 150, MPI_INT, &stype);

MPI_Type_commit( &stype );

MPI_Gatherv( sendarray, 1, stype, rbuf, rcounts, displs, MPI_INT,

root, comm);

4.7 プロセスiC言語における100 2 150の整数配列の第i列から(100-i)個の整数を送 信する。上記2つの例と同様にして、stride間隔でバッファの中へ読み込む。図4.5を参照のこ と。

MPI_Comm comm;

int gsize,sendarray[100][150],*sptr;

int root, *rbuf, stride, myrank;

MPI_Datatype stype;

int *displs,i,*rcounts;

...

MPI_Comm_size( comm, &gsize);

MPI_Comm_rank( comm, &myrank );

rbuf = (int *)malloc(gsize*stride*sizeof(int));

displs = (int *)malloc(gsize*sizeof(int));

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

100 99

rbuf

at root stride

all processes 100

150

100

150

100

150

98

4.5: ルートプロセスは 100-i個の整数をC言語における 1002100 配列の第i列から集め、

各々をstride個の整数だけ離して配置する。

for (i=0; i<gsize; ++i) {

displs[i] = i*stride;

rcounts[i] = 100-i; /* note change from previous example */

}

/* Create datatype for the column we are sending

*/

MPI_Type_vector( 100-myrank, 1, 150, MPI_INT, &stype);

MPI_Type_commit( &stype );

/* sptr is the address of start of "myrank" column

*/

sptr = &sendarray[0][myrank];

MPI_Gatherv( sptr, 1, stype, rbuf, rcounts, displs, MPI_INT,

root, comm);

4.84.7と同じ。ただし、送信側では別の方法で行われている。送信側で正しいストライド となるようなデータタイプを生成し、C言語における配列から1列読み込む。??節、例3.33で 行ったのと同じである。

MPI_Comm comm;

int gsize,sendarray[100][150],*sptr;

int root, *rbuf, stride, myrank, disp[2], blocklen[2];

MPI_Datatype stype,type[2];

int *displs,i,*rcounts;

...

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

MPI_Comm_size( comm, &gsize);

MPI_Comm_rank( comm, &myrank );

rbuf = (int *)malloc(gsize*stride*sizeof(int));

displs = (int *)malloc(gsize*sizeof(int));

rcounts = (int *)malloc(gsize*sizeof(int));

for (i=0; i<gsize; ++i) {

displs[i] = i*stride;

rcounts[i] = 100-i;

}

/* Create datatype for one int, with extent of entire row

*/

disp[0] = 0; disp[1] = 150*sizeof(int);

type[0] = MPI_INT; type[1] = MPI_UB;

blocklen[0] = 1; blocklen[1] = 1;

MPI_Type_struct( 2, blocklen, disp, type, &stype );

MPI_Type_commit( &stype );

sptr = &sendarray[0][myrank];

MPI_Gatherv( sptr, 100-myrank, stype, rbuf, rcounts, displs, MPI_INT,

root, comm);

4.9 送信側は例4.7と同じ。ただし、受信側では受信したブロックの間のストライドはブロッ クごとに異なる。図4.6を参照のこと。

MPI_Comm comm;

int gsize,sendarray[100][150],*sptr;

int root, *rbuf, *stride, myrank, bufsize;

MPI_Datatype stype;

int *displs,i,*rcounts,offset;

...

MPI_Comm_size( comm, &gsize);

MPI_Comm_rank( comm, &myrank );

stride = (int *)malloc(gsize*sizeof(int));

...

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

100

stride[1]

rbuf

at root

all processes 100

150

100

150

100

150

99 98

4.6: ルート・プロセスは、C言語における1002150配列の第i列から100-i個の整数を集 め、各々整数個stride[i]分だけ離して配置する(可変ストライド)。

/* stride[i] for i = 0 to gsize-1 is set somehow

*/

/* set up displs and rcounts vectors first

*/

displs = (int *)malloc(gsize*sizeof(int));

rcounts = (int *)malloc(gsize*sizeof(int));

offset = 0;

for (i=0; i<gsize; ++i) {

displs[i] = offset;

offset += stride[i];

rcounts[i] = 100-i;

}

/* the required buffer size for rbuf is now easily obtained

*/

bufsize = displs[gsize-1]+rcounts[gsize-1];

rbuf = (int *)malloc(bufsize*sizeof(int));

/* Create datatype for the column we are sending

*/

MPI_Type_vector( 100-myrank, 1, 150, MPI_INT, &stype);

MPI_Type_commit( &stype );

sptr = &sendarray[0][myrank];

MPI_Gatherv( sptr, 1, stype, rbuf, rcounts, displs, MPI_INT,

root, comm);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

ドキュメント内 mpi-report-j.dvi (ページ 134-146)