KOBE HPC サマースクール 2018（初級）11. 熱伝導問題の並列計算（関数 MPI_Sendrecv）

2018/8/9

KOBE HPC サマースクール 20181

演習11-1 【準備】 関数 MPI_Sendrecv
プログラム sr.c は，２つのプロセスで互いにデータを送りあうプログラムである．
プログラムをコピー，実行し，動作を確かめる．

$ cp /tmp/Summer/M‐4/sr.c ./$ icc sr.c –lmpi$ qsub ...
← ２プロセスのMPIのバッチジョブ$ cat xxxxx.onnnnnn← バッチジョブの実行結果を確認
Before exchange... Rank: 0, a0= 1.0, a1= 0.0
Before exchange... Rank: 1, a0= 0.0, a1= 2.0
After exchange... Rank: 1, a0= 1.0, a1= 2.0
After exchange... Rank: 0, a0= 1.0, a1= 2.0

2018/8/9

KOBE HPC サマースクール 20182プログラム sr.c の説明#include <mpi.h>
int main( int argc, char **argv ){double a0, a1;
int nprocs, myrank;
MPI_Status status;【省略】
if( myrank == 0 ) {a0 = 1.0 ;a1 = 0.0 ;} else {a0 = 0.0 ;a1 = 2.0 ;};include行

rank 0では，a0=1.0, a1=0.0

rank 1では，a0=0.0, a1=2.0【省略】※ 交換部分：各プロセスでのsend，recvの実行順序に注意

if( myrank == 0 ) {MPI_Send( &a0, 1, MPI_DOUBLE, 1, 100, MPI_COMM_WORLD );MPI_Recv( &a1, 1, MPI_DOUBLE, 1, 200, MPI_COMM_WORLD, &status );} else {MPI_Recv( &a0, 1, MPI_DOUBLE, 0, 100, MPI_COMM_WORLD, &status );MPI_Send( &a1, 1, MPI_DOUBLE, 0, 200, MPI_COMM_WORLD );
};
【省略】
}

2018/8/9

a0の値を rank 0からrank 1へ送る．
rank 1 から a1の値を受け取る．
rank 0 から a0の値を受け取る．
a1の値を rank 1からrank 0へ送る．

※キーワード: ブロッキング関数

KOBE HPC サマースクール 20183

双⽅向通信：MPI_Sendrecv関数
MPI_Sendrecv( void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest,
int sendtag,
void *recvbuf, int recvcount, MPI_Datatype recvtype, int source,
int recvtag,
MPI_Comm comm, MPI_Status *status )sendbuf:
sendcount:sendtype:
dest:
sendtag:
recvbuf:
recvcount:recvtype:source:recvtag:
comm:status:2018/8/9

送信するデータのための変数名（先頭アドレス）
送信するデータの数
送信するデータの型
MPI_INTEGER, MPI_REAL8, MPI_CHARACTER など送信する相手のプロセス番号（destination）
メッセージ識別番号．送られて来たデータを区別するための番号
受信するデータのための変数名（先頭アドレス）
受信するデータの数（整数型）
受信するデータの型
送信してくる相手のプロセス番号
メッセージ識別番号．送られて来たデータを区別するための番号コミュニケータ（例えば，MPI_COMM_WORLD）
受信の状態を格納する変数
KOBE HPC サマースクール 20184

演習11-2 ：プログラムsr.c の書き換えプログラム sr.c のデータの交換部分を MPI_Sendrecv関数
で書き換えよ．
if( myrank == 0 ) {MPI_Send( &a0, 1, MPI_DOUBLE, 1, 100, MPI_COMM_WORLD );MPI_Recv( &a1, 1, MPI_DOUBLE, 1, 200, MPI_COMM_WORLD, &status );} else {MPI_Recv( &a0, 1, MPI_DOUBLE, 0, 100, MPI_COMM_WORLD, &status );MPI_Send( &a1, 1, MPI_DOUBLE, 0, 200, MPI_COMM_WORLD );};MPI_Sendrecv( ．．．);
MPI_Sendrecv( ．．．);

2018/8/9

rank 0 から rank 1
rank 1 から rank 0

KOBE HPC サマースクール 20185

【発展】MPI_Sendrecvの行列への適用
2次元配列（u[N+2][N+2] ）をブロック行分割する．
2次元配列（ブロック行分割）

外側の領域

PE0

PE1

このとき，自分の上下の１行の要素を，隣接するプロセスの持つ領域の外側に受信用の領域を確保し，その領域に各プロセスが転送するプログラムを作る．
2018/8/9

KOBE HPC サマースクール 2018

PE2

PE3

上下のプロセスから1行を受信（受信用の領域を確保しておく）
6

MPI_Sendrecvの発展（続き）

第1の sendrecv

第2の sendrecv

ダミープロセス

ダミープロセス

自分の担当範囲を計算
変数myrankを用いて，担当範囲 js ～ je 行を計算
受信領域を考慮し，js-1, je+1 行の領域を扱う．

rank 0

メモリ節約の観点では，自分の領域分のメモリがあれば良いが，c言語のポインタ，malloc関数を使ってやるひつようがあるので，本スクー
ルではやらない．
rank 1

MPI_Sendrecv による送受信
まず，上側に js 行を送り，下側から送られてくるデータを (je+1) 行で受信
rank 2

次に，下側に je 行を送り，上側から送られてくるデータを (js-1) 行に受信
最上下端のプロセスは，ダミープロセス（MPI_PROC_NULL） と送受信するようにする．
MPI_Sendrecv の source, dest に使うことが出来る．ダミープロセ
スを指定すると，実際にはどこからにもデータを送らないし，どこからもデータを受け取らない．

rank 3

ダミープロセス2018/8/9

KOBE HPC サマースクール 2018

ダミープロセス7

プログラム sr_matrix.c（続く）#include <stdio.h>#include <mpi.h>
N = 20 とする#define N 20
int main( int argc, char **argv ){double u[N+2][N+2];
int i, j, is, ie;(N+2)次の行列として宣言する．後で分かる．

int nprocs, myrank, upper, lower, srtag;
MPI_Status status;

Recvで必要な配列変数の宣言

MPI_Init( &argc, &argv );MPI_Comm_size( MPI_COMM_WORLD, &nprocs );MPI_Comm_rank( MPI_COMM_WORLD, &myrank );is = (N/nprocs)* myrank + 1;
ie = (N/nprocs)*(myrank+1);

各プロセスの担当する行の範囲を計算

upper = myrank‐1;
if( myrank == 0

上側プロセスのプロセス番号を設定) upper = MPI_PROC_NULL;lower = myrank+1 ;if( myrank == nprocs‐1 ) lower = MPI_PROC_NULL;

2018/8/9（存在しない場合は MPI_PROC_NULL とする）
下側プロセスのプロセス番号を設定

KOBE HPC サマースクール 20188

プログラム sr_matrix.c（続き）
for( i=is; i<=ie; i++ ) {for( j=0; j<N+2; j++ ) {u[i][j] = (myrank+1)*10.0 ;};};/* from the lower process to the upper one */MPI_Sendrecv();/* 下側のプロセスから上側へ */MPI_Sendrecv による送受信/* from the upper process to the lower one */MPI_Sendrecv();/* 上側のプロセスから下側へ */MPI_Sendrecv による送受信

printf("Rank = %d %d %d¥n", myrank, is, ie ) ;for( i=is‐1; i<=ie+1; i++ ) {printf("%6.2f", u[i][N/2] ) ;};printf("¥n") ;N/2 の列のみプリントして確認している．

MPI_Finalize();
return 0;}

2018/8/9

KOBE HPC サマースクール 20189

演習11-3 ：プログラムの完成と実行
sr_matrix.c は未完成である．
MPI_Sendrecvの部分を完成させ，コンパイルして，2，4 プロセスで実行し，データの送受信が正しくできていることを確かめよ.
$cp/tmp/Summer/M‐4/sr_matrix.c./

実行結果（出力順は，以下とは異なる）．
Rank= 0, is:ie=1:50.00 10.00 10.00 10.00 10.00 10.00 20.00
Rank= 1, is:ie=6:10

上のプロセスのie行が，下のプロセスの(is‐1）行にコピー

10.00 20.00 20.00 20.00 20.00 20.00 30.00

下のプロセスのis行が，上のプロセスの(ie+1)行にコピー

Rank= 2, is:ie=されていることを確認する．

11:

15

20.00 30.00 30.00 30.00 30.00 30.00 40.00
Rank= 3, is:ie=

16:2030.00 40.00 40.00 40.00 40.00 40.00

2018/8/9

0.00

KOBE HPC サマースクール 201810KOBE HPC サマースクール 2018（初級）

2次元定常熱伝導問題のMPIによる並列計算

2018/8/9

KOBE HPC サマースクール 201811

2次元定常熱伝導問題
2次元正方形領域 [0,1]×[0,1] に一定の熱を加え続けた時の領域の温度がどうなるか？
境界で0.0境界条件

2018/8/90,0.0011,0.001,00.001,10.001

KOBE HPC サマースクール 201812

離散化格子と変数方向， 方向どちらも1 等分する．
,

1/1

≜

,,0, 1, 2, … ,1,,

境界条件として既知の値内部の格子点（未知数）内部の格子点に関する関係式を作る．

,,,,,
2018/8/9,,,,,
KOBE HPC サマースクール 201813

熱伝導問題へのヤコビ法の適用
反復ベクトル生成のアルゴリズム
for( i=1; i<=N; i++ ) {for( j=1; j<=N; j++ ) {ui,j(m+1) = (ui‐1,j(m)+ui+1,j(m)+ui,j‐1(m)+ui,j+1(m))*0.25 + 10.0*dx*dx;};};

2018/8/9

KOBE HPC サマースクール 201814

演習11-4 ：プログラム heat2d.c の実行
2次元定常熱伝導問題の逐次プログラム heat2d.c をコンパイルして実行せよ．
$$$

cp /tmp/Summer/M‐4/heat2d.c ./icc –O3 heat2d.c./a.out

プログラムでは N 80 の時に，反復ベクトルの差のノルムがある閾値
1.0 10 より,,小さくなったら反復を停止している．

2018/8/9

KOBE HPC サマースクール 201815

heat2d.c のMPIによる並列化
並列化のヒント
2次元配列 u，u0 をブロック行分割
u の計算をする前に，u[is:ie][]をu0にコピーし，- 上のプロセスのu0の je行を下のプロセスの(js-1)行へ，- 下のプロセスのu0の js 行を上のプロセスの(je+1)行へ，送る．
並列化sr_matrix.c と同様に，mpi_sendrecv を用いて送受信
u の js ～ je 行の計算を行う.

上下のプロセスから1行を受信（受信用の領域を確保しておく）

反復ベクトルの差のノルムの部分和を計算し，MPI_Allgatherで総和を取り，収束の判定を行うようにする．
ローカルで残差の部分和を計算し，各プロセスでノルムを計算する．
2018/8/9

KOBE HPC サマースクール 201816

演習11-5 heat2d.cの並列化
heat2d.cをMPIを用いて並列化せよ．
N=128とし，プロセス数1, 2, 4, 8 として，反復開始から終了までの計算時間を計測し，速度向上率を求めよ．また，それをグラフにせよ．
計算結果を gnuplotで図示せよ．
計算結果の出力は，プロセス0にデータを集め，ファイルに出力する．

2018/8/9

KOBE HPC サマースクール 201817上級者になるために．．．
大規模問題を解く場合には，1プロセスのメモリ使用容量を少なくする必要が出てくる．
今回のプログラムでは，どのプロセスも u[N+2,N+2], u0[N+2,N+2] として，計算全領域の変数を宣言したが，外側の領域

PE0

u[N/nprocs][N+2]u0[N/nprocs+2][N+2]

各プロセスは，これだけの大きさをもてば良いはず．

実行前から並列数（nprocs）が固定されていれば，上記のように，プログラムの先頭で小さい領域を宣言することも出来るが，汎用のプログラ
ムとしては，nprocsを実行開始時に決めたい．
配列を動的に確保する必要がある（malloc関数） ．
サンプルプログラム /tmp/Summer/M-4/alloc_mpi_heat2d.c
2018/8/9

KOBE HPC サマースクール 201818

補足：2次元定常熱伝導問題の離散化

2018/8/9

KOBE HPC サマースクール 201819

, を辞書式順序で並べたベクトルを,,⋮⋮,,10,

1, 2, … ,,,,,,⋮,,,,,,,,

⋮,,,0

⋯

1⋯

1N離れている4 1 ⋯⋯0⋮⋮
⋮,,,

⋮,⋮⋮

1 0N離れている⋮,⋮⋮,,,,,,⋮⋮,

2018/8/9,,⋮⋮⋮4とすると，点 , に関する離散式は,KOBE HPC サマースクール 201820

行列を用いた表現

2018/8/9

KOBE HPC サマースクール 201821

連立一次方程式の反復解法

2018/8/9

KOBE HPC サマースクール 2018

22

行列分離

００００
行列分離：

＝
: 対角行列: 狭義下三角行列: 狭義上三角行列

2018/8/9

KOBE HPC サマースクール 201823

ヤコビ法（その1）ヤコビ行列で，反復ベクトル系列を生成する．

/,

1

2018/8/9,0KOBE HPC サマースクール 201824

参考：Fortran版

2018/8/9

KOBE HPC サマースクール 201825

双方向通信：mpi_sendrecv関数
mpi_sendrecv( sendbuff, sendcount, sendtype, dest, sendtag,recvbuff, recvcount, recvtype, source, recvtag,
comm, status, ierr )sendbuff:
sendcount:sendtype:
dest:
sendtag :recvbuff:
recvcount:recvtype:source:recvtag:
comm:status:ierr:
2018/8/9

送信するデータのための変数名（先頭アドレス）
送信するデータの数（整数型）
送信するデータの型（MPI_REAL，MPI_INTEGERなど）
送信する相手プロセスのランク番号
メッセージ識別番号．送くるデータを区別するための番号
受信するデータのための変数名（先頭アドレス）
受信するデータの数（整数型）
受信するデータの型（MPI_REAL，MPI_INTEGERなど）
送信してくる相手プロセスのランク番号
メッセージ識別番号．送られて来たデータを区別するための番号
コミュニケータ（例えば，MPI_COMM_WORLD）
受信の状態を格納するサイズMPI_STATUS_SIZEの配列（整数型）
戻りコード（整数型）
KOBE HPC サマースクール 201826