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

パックとアンパック

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

/* All entries of u have identical type; variable

utype keeps track of their current type */

MPI_Datatype type[2];

int blocklen[2] = {1,1};

MPI_Aint disp[2];

MPI_Datatype mpi_utype[2];

MPI_Aint i,j;

/* compute an MPI datatype for each possible union type;

assume values are left-aligned in union storage. */

MPI_Address( u, &i);

MPI_Address( u+1, &j);

disp[0] = 0; disp[1] = j-i;

type[1] = MPI_UB;

type[0] = MPI_INT;

MPI_Type_struct(2, blocklen, disp, type, &mpi_utype[0]);

type[0] = MPI_FLOAT;

MPI_Type_struct(2, blocklen, disp, type, &mpi_utype[1]);

for(i=0; i<2; i++) MPI_Type_commit(&mpi_utype[i]);

/* actual communication */

MPI_Send(u, 1000, mpi_utype[utype], dest, tag, comm);

3.13

パックとアンパック

既存の幾つかの通信ライブラリは不連続なデータを送信するためにパック/アンパック関数を提 供している。この場合、利用者は送信前に連続したバッファに明示的にパックし、受信後に連続 したバッファからアンパックする。利用者は3.12節で説明したような、派生データ型を、ほとん どの場合、明示的にパック、アンパックしなくてよい。利用者は送信する、または受信するデー

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 では実現できない様 ないくつかの機能を提供する。例えば、受信内容が既に受信された部分に依存するような、複数 に分かれたメッセージを受信することが出来る。他には、送出するメッセージを利用者が明示的 に指定した場所にバッファリングすることで、システムのバッファリング規則を置き換えること が出来る。つまり、パック、アンパックを利用することでMPI 上に別の通信ライブラリを容易 に開発できる。

MPI PACK(inbuf,incount, datatyp e,outbuf, outcount,position, comm)

入力 inbuf 入力バッファ始点(選択型)

入力 incount 入力項目数(整数型)

入力 datatype 個々の入力項目のデータ型(ハンドル)

出力 outbuf 出力バッファ始点(選択型)

入力 outcount 出力バッファ・バイト長(整数型)

入出力 position バッファ中での現在のバイト位置(整数型)

入力 comm コミュニケータ(ハンドル)

int MPI Pack(void* inbuf, int incount, MPI Datatype datatype, void *outbuf,

int outcount, int *position, MPI Comm comm)

MPI PACK(INBUF, INCOUNT, DATATYPE, OUTBUF, OUTCOUNT, POSITION, COMM,

IERROR)

<type> INBUF(*), OUTBUF(*)

INTEGER INCOUNT, DATATYPE, OUTCOUNT, POSITION, COMM, IERROR

inbuf, incount, datatypeで指定される送信バッファ内のメッセージをoutbuf, outcountで 指定されるバッファへパックする。入力バッファにはMPI SENDで使うことが出来るバッファ を指定できる。出力バッファは、outbufから始まるoutcountバイトの領域を含む、連続領域で

ある。(長さは、MPI PACKED型メッセージの通信バッファであるかのごとく、要素数ではな

く、バイトで表される。)

入力値positionは出力バッファ中のパッキングの開始位置である。positionはパックされた メッセージの大きさ分増加し、出力値positionはパックされたメッセージに続く領域の先頭であ る。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

3.13. パックとアンパック 109

MPI UNPACK(inbuf,insize, position, outbuf,outcount, datatype,comm)

入力 inbuf 入力バッファ始点(選択型)

入力 insize 入力バッファ・バイト長(整数型)

入出力 position バッファ中での現在のバイト位置(整数型)

出力 outbuf 出力バッファ始点(選択型)

入力 outcount 出力項目数(整数型)

入力 datatype 個々の入力項目のデータ型(ハンドル)

入力 comm コミュニケータ(ハンドル)

int MPI Unpack(void* inbuf, int insize, int *position, void *outbuf,

int outcount, MPI Datatype datatype, MPI Comm comm)

MPI UNPACK(INBUF, INSIZE, POSITION, OUTBUF, OUTCOUNT, DATATYPE, COMM,

IERROR)

<type> INBUF(*), OUTBUF(*)

INTEGER INSIZE, POSITION, OUTCOUNT, DATATYPE, COMM, IERROR

outbuf,outcount,datatyp eで指定される受信バッファへinbuf,insizeで指定されるバッファ 空間からデータをアンパックする。出力バッファにはMPI RECVで利用できる、どの通信バッ ファでも指定できる。入力バッファは、inbufで始まるinsizeバイトの領域を含む連続した記憶 領域である。入力値positionは入力バッファ中のパックされたメッセージの先頭位置である。

po-sitionはパックされたメッセージの大きさの分増加するので、出力値positionは入力バッファ中

でアンパックされたメッセージの占めていた位置に続く領域の先頭である。commはパックさ れたメッセージを受信するのに使ったコミュニケータである。

ユーザへのアドバイス MPI RECVMPI UNPACKの違いに注意。MPI RECVではcount 引数は受信できる最大項目数を指定する。実際に受信された項目数は受信されたメッセー ジ長で決まる。MPI UNPACKではcount引数は実際にアンパックされた項目数である。

メッセージの\サイズ"positionの増分に一致する。この\受信メッセージサイズ"の違 いは、利用者がどれだけアンパックするかを決定するため、事前に決まらないためである。

アンパックされる項目数から\メッセージサイズ"を決定するのは容易ではない。実際、

異機種混在のシステムではこの数は経験的に決められない。(ユーザへのアドバイスの終 わり)

パックとアンパックの動作は、そのメッセージで送られる値を連結して得られた並びと考え ることが。パック操作は、バッファに送信するかのように、この並びを格納する。アンパック操

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

作は、バッファから受信されるかのように、この並びを取り出す。(この方法はFORTRAN言 語の内部ファイルや、C言語のsscanf等の同様の関数を理解する助けにもなる。)

いくつかの連続した関連するMPI PACKの呼出によって、いくつかのメッセージを続けて ひとつのパッキング単位にパックすることが出来る。最初の呼出はposition = 0で行なわれ、

続くそれぞれの呼出は直前のpositionの出力を入力値として与え、同じoutbuf, outcount及び

commを使う。このパッキング単位は、個々の送信バッファを\連結"したバッファをひとつの 送信操作によって送られたメッセージと等価な情報を含んでいる。

パッキング単位はMPI PACKED型として送信できる。あらゆる一対一通信で、パッキング 単位の形状をしたバイトの並びを、あるプロセッサから他へ移動することが出来る。この時点 で、このパッキング単位はどのようなデータ型を用いてどのような受信操作ででも受信できる。

型一致規則はMPI PACKED型の場合は緩められる。

どんなデータ型(MPI PACKEDを含む)で送られたメッセージでも、MPI PACKED型で受 信することが出来る。この様なメッセージはMPI UNPACKによってアンパックできる。

連続したMPI UNPACKの呼出によって、パッキング単位(或は通常の\型つき"送信で生 成されたメッセージ)を幾つかの連続したメッセージにアンパック出来る。最初はposition = 0 で呼び出され、続く呼び出しは、それぞれの直前の呼び出しによって得られるpositionを引数と し、同じinbuf,insize及び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

3.13. パックとアンパック 111

MPI PACKSIZE(incount, datatype,comm, size)

入力 incount パック操作に渡すincount引数(整数型)

入力 datatype パック操作に渡すdatatype引数(ハンドル)

入力 comm パック操作に渡すcomm引数 (ハンドル)

出力 size パックされたメッセージの上限値(バイト単位)(整数型)

int MPI Pack size(int incount, MPIDatatype datatype, MPI Comm comm,

int *size)

MPI PACK SIZE(INCOUNT, DATATYPE, COMM, SIZE, IERROR)

INTEGER INCOUNT, DATATYPE, COMM, SIZE, IERROR

MPI PACKSIZE(incount, datatype, comm, size)はMPI PACK(inbuf, incount, datatype, outbuf,outcount, position, comm)の結果position引数の増加分の上限をsizeに返す。

根拠 厳密な範囲ではなく、上限を返すのは、メッセージをパックするのに要する領域の大 きさは状況に依存する可能性があるからである。(例えば、パッキング単位に最初にパッ クされたメッセージはより多くの領域を占めるかも知れない。) (根拠の終わり)

3.37 MPI PACKを使用する例

int position, i, j, a[2];

char buff[1000];

....

MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

if (myrank == 0)

{

/ * 送信側コード */

position = 0;

MPI_Pack(&i, 1, MPI_INT, buff, 1000, &position, MPI_COMM_WORLD);

MPI_Pack(&j, 1, MPI_INT, buff, 1000, &position, MPI_COMM_WORLD);

MPI_Send( buff, position, MPI_PACKED, 1, 0, MPI_COMM_WORLD);

}

else /* 受信側コード */

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

MPI_Recv( a, 2, MPI_INT, 0, 0, MPI_COMM_WORLD)

}

3.38 A elaborate example.

int position, i;

float a[1000];

char buff[1000]

....

MPI_Comm_rank(MPI_Comm_world, &myrank);

if (myrank == 0)

{

/ * SENDER CODE */

int len[2];

MPI_Aint disp[2];

MPI_Datatype type[2], newtype;

/* build datatype for i followed by a[0]...a[i-1] */

len[0] = 1;

len[1] = i;

MPI_Address( &i, disp);

MPI_Address( a, disp+1);

type[0] = MPI_INT;

type[1] = MPI_FLOAT;

MPI_Type_struct( 2, len, disp, type, &newtype);

MPI_Type_commit( &newtype);

/* Pack i followed by a[0]...a[i-1]*/

position = 0;

MPI_Pack( MPI_BOTTOM, 1, newtype, buff, 1000, &position, MPI_COMM_WORLD);

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

3.13. パックとアンパック 113

/* Send */

MPI_Send( buff, position, MPI_PACKED, 1, 0,

MPI_COMM_WORLD)

/* *****

One can replace the last three lines with

MPI_Send( MPI_BOTTOM, 1, newtype, 1, 0, MPI_COMM_WORLD);

***** */

}

else /* myrank == 1 */

{

/* RECEIVER CODE */

MPI_Status status;

/* Receive */

MPI_Recv( buff, 1000, MPI_PACKED, 0, 0, &status);

/* Unpack i */

position = 0;

MPI_Unpack(buff, 1000, &position, &i, 1, MPI_INT, MPI_COMM_WORLD);

/* Unpack a[0]...a[i-1] */

MPI_Unpack(buff, 1000, &position, a, i, MPI_FLOAT, MPI_COMM_WORLD);

}

3.39 Each process sends a count, followed by count characters to the root; the root

concatenateall charactersintoonestring.

int count, gsize, counts[64], totalcount, k1, k2, k,

displs[64], position, concat_pos;

char chr[100], *lbuf, *rbuf, *cbuf;

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);

/* allocate local pack buffer */

MPI_Pack_size(1, MPI_INT, comm, &k1);

MPI_Pack_size(count, MPI_CHAR, &k2);

k = k1+k2;

lbuf = (char *)malloc(k);

/* pack count, followed by count characters */

position = 0;

MPI_Pack(&count, 1, MPI_INT, &lbuf, k, &position, comm);

MPI_Pack(chr, count, MPI_CHAR, &lbuf, k, &position, comm);

if (myrank != root)

/* gather at root sizes of all packed messages */

MPI_Gather( &position, 1, MPI_INT, NULL, NULL,

NULL, root, comm);

/* gather at root packed messages */

MPI_Gatherv( &buf, position, MPI_PACKED, NULL,

NULL, NULL, NULL, root, comm);

else { /* root code */

/* gather sizes of all packed messages */

MPI_Gather( &position, 1, MPI_INT, counts, 1,

MPI_INT, root, comm);

/* gather all packed messages */

displs[0] = 0;

for (i=1; i < gsize; i++)

displs[i] = displs[i-1] + counts[i-1];

totalcount = dipls[gsize-1] + counts[gsize-1];

rbuf = (char *)malloc(totalcount);

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

3.13. パックとアンパック 115

cbuf = (char *)malloc(totalcount);

MPI_Gatherv( lbuf, position, MPI_PACKED, rbuf,

counts, displs, MPI_PACKED, root, comm);

/* unpack all messages and concatenate strings */

concat_pos = 0;

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

position = 0;

MPI_Unpack( rbuf+displs[i], totalcount-displs[i],

&position, &count, 1, MPI_INT, comm);

MPI_Unpack( rbuf+displs[i], totalcount-displs[i],

&position, cbuf+concat_pos, count, MPI_CHAR, comm);

concat_pos += count;

}

cbuf[concat_pos] = `\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

Chapter4

集団通信

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