•
rank0 側で
MPI_Send(a, 16, MPI_INT, 1, 100, MPI_COMM_WORLD);
• rank1側で
MPI_Recv(b, 16, MPI_INT, 0,
100, MPI_COMM_WORLD, &stat);
rank 0 rank 1 MPI_Send
MPI_Recv
MPI_Send
MPI_Send(a, 16, MPI_INT, 1, 100, MPI_COMM_WORLD);
•
a: メッセージとして送りたいメモリ領域の先頭アドレス
•
16: 送りたいデータ個数
•
MPI_INT: 送りたいデータ型
– 他にはMPI_CHAR, MPI_LONG. MPI_DOUBLE, MPI_BYTE・・・
•
1: メッセージの宛先プロセスの rank
•
100: メッセージにつけるタグ ( 整数 )
•
MPI_COMM_WORLD: コミュニケータ
MPI_Recv
MPI_Status stat;
MPI_Recv(b, 16, MPI_INT, 0, 100, MPI_COMM_WORLD, &stat);
• b: メッセージを受け取るメモリ領域の先頭アドレス – 十分な領域を確保しておくこと
• 16: 受け取るデータ個数
• MPI_INT: 受け取るデータ型
• 0: 受け取りたいメッセージの送信元プロセスのrank
• 100: 受け取りたいメッセージのタグ.ユーザが決める整数
– MPI_Sendで指定したものと同じなら受け取れる
• MPI_COMM_WORLD: コミュニケータ
• &stat: メッセージに関する補足情報が受け取れる
MPI_Recvを呼ぶと,メッセージが到着するまで待たされる (ブロッキング)
MPI_Recv のマッチング処理
受信側には複数メッセージがやってくるかも 受け取りたい条件を指定 する
• 受け取りたい送信元を指定するか,MPI_ANY_SOURCE (誰からでもよ い)
• 受け取りたいタグを指定するか,MPI_ANY_TAG(どのタグでもよい)
1 0
source:0 tag:100
…data…
source:2 tag:200
…data…
63
分散メモリと共有メモリの違い 行列積 (C=AxB) の例
•
共有メモリ:計算をどうス レッドに分割するか
A
B
C A
B0
A
分散メモリ:計算とデータを どうプロセスに分割するか
行列Aは全スレッドによって アクセスされる
行列Aは全プロセスに置かれる C0
B1 C1
分散メモリプログラミングとデータ配置
(mm‐mpiを題材に)
A
B0 C0 A
B1
C1 A
B2
C2 A
B3 C3 A
B C
配置方法を 決める:
行列B, Cは列方向で ブロック分割しよう.
Aは全プロセスに 複製を置こう.
実際の配置をプログラミング:
65
データ分散とプログラミング
•
m × n 行列を p プロセスで分割する とはどういうことか?
– データ並びはcolumn‐majorとする – ここでは割り切れる場合を仮定
•
各プロセスが持つのは, m × (n/p) の部分行列
– m*(n/p)*sizeof(データ型)のサイズの 領域をmallocすることに
– 部分行列と全体行列の対応を意識 する必要
• プロセスrの部分行列の(i,j)要素⇔
全体行列の(i, n/p*r + j)要素に対 応
全体のイメージ
m
n
プロセスが持つ領域
m
n/p
(0,0)
MPI 版行列積
• LB ・ LC 配列が、 B ・ C の部分行列だとする
MPI_Init(&argc, &argv);
:
ln = n/nprocs;
for (int j = 0; j < ln; j++) { for (int l = 0; l < k; l++) {
double blj = B[l+j*ldb];
for (int i = 0; i < m; i++) { double ail = A[i+l*lda];
C[i+j*ldc] += ail*blj;
} } }
Diffusion の MPI 化に向けて
隣の点の情報を用いて値更新
並列化は、基本的に空間分割
プロセス間の境界が問題になる
NX
NY 時間t-1 時間t
Diffusion の並列化方針
•
各プロセスが write する領域よりも read する領域が大き い
プロセス間に依存関係