MPIによる並列プログラミング演習

MPI による並列プログラミング演習
大塚 智宏
北村 聡
天野 英晴
天野研究室 PDARCH グループ
1
ターゲットマシン (SGI Altix3700) の構成
詳細は,http://www.sgi.co.jp/servers/altix/ を参照のこと.
•
•
•
•
2
プロセッサ : Itanium2 1.3GHz × 8 (全体では 64PU)
メモリ : 48GB (全体では 384GB)
OS : SGI Advanced Linux Environment 3.0 (kernel 2.4.21 ベース)
MPI : SGI Message Passing Toolkit (MPT)
MPI による並列プログラミング
MPI (Message Passing Interface) は,主に分散メモリ型並列計算機上でメッセージパッシングモデルに基づく並列プログラミ
ングを行うための標準的な API 仕様である.現在では,メッセージパッシングの事実上の標準として広く用いられている.
2.1
メッセージパッシング
分散メモリ型並列計算機 (クラスタも含む) では,各プロセスは独立なアドレス空間を持つため,共有変数による並列プログ
ラミングは直接には実現できない.各プロセスは,メッセージを交換し合うことにより,協調して処理を進める.
メッセージ通信には,Point-to-Point 通信と Collective 通信の 2 種類がある.Point-to-Point 通信では,一対のプロセス間で,
片方が送信者 (Sender),もう片方が受信者 (Receiver) として,それぞれ送信・受信のための関数を実行して通信を行う.一
方,Collective 通信では,2 つ以上のプロセスが同じ関数を実行して協調的な通信を行う.一般に Collective 通信は,複数の
Point-to-Point 通信で代用可能である.
また,MPI では,SPMD (Single Program Multiple Data) 型と呼ばれるスタイルに基づいてプログラムを記述する.これは,複
数のプロセスが全て同一のプログラムを実行し,プロセス番号によって分岐して処理を進めるもので,並列プログラミングで
は最も一般的なプログラム記述法である.MPI 環境下でプログラムが実行されると,指定した数のプロセスが生成され,並列
計算機やクラスタ内の各プロセッサに分配される.
2.2
サンプルプログラム
MPI では,最低限 6 つの関数を使えばたいていのプログラムを記述することができる.以下に,C 版のサンプルプログラム
を示す.
1
¶
³
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:
µ
•
•
•
•
•
•
•
•
•
2.3
#include <stdio.h>
#include <mpi.h>
#define MSIZE 64
int main(int argc, char **argv)
{
char msg[MSIZE];
int pid, nprocs, i;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &pid);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
if (pid == 0) {
for (i = 1; i < nprocs; i++) {
MPI_Recv(msg, MSIZE, MPI_CHAR, i, 0, MPI_COMM_WORLD, &status);
fputs(msg, stdout);
}
}
else {
sprintf(msg, "Hello, world! (from process #%d)\n", pid);
MPI_Send(msg, MSIZE, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
}
MPI_Finalize();
return 0;
}
´
2: ヘッダファイル mpi.h をインクルードする.
12: MPI の初期化.
13: 自プロセスのプロセス番号を求める.
14: 全プロセス数を求める.
16∼21: プロセス 0 の場合の処理.
17∼20: 自分以外の全プロセス (プロセス 1 ∼ nprocs−1) から順にメッセージを受信し,表示する.
22∼25: プロセス 0 以外の場合の処理.
24: プロセス 0 にメッセージを送信する.
27: MPI の終了.
基本的な 6 つの関数
MPI Init
MPI の初期化を行う.argc, argv には,コマンドライン引数として受け取ったものをそのまま渡さなければならない.
¶
int MPI_Init(
int
char
mpi_init(ierr)
integer
µ
*argc,
***argv
ierr
³
/* argc へのポインタ */
/* argv へのポインタ */ );
! 返却コード
´
2
MPI Finalize
MPI の終了処理を行う.
¶
³
int MPI_Finalize();
mpi_finalize(ierr)
integer
µ
ierr
! 返却コード
´
MPI Comm rank
コミュニケータ comm 中の自プロセスのランク (プロセス番号) を求める.
¶
int MPI_Comm_rank(
MPI_Comm
int
comm,
*rank
mpi_comm_rank(comm, rank, ierr)
integer
comm, rank
integer
ierr
µ
³
/* コミュニケータ */
/* プロセス ID (出力) */ );
! 返却コード
´
MPI Comm size
コミュニケータ comm 中のプロセス数を求める.
¶
int MPI_Comm_size(
MPI_Comm
int
comm,
*size
mpi_comm_size(comm, size, ierr)
integer
comm, size
integer
ierr
µ
³
/* コミュニケータ */
/* プロセス数 (出力) */ );
! 返却コード
´
MPI Send
プロセス dest にデータを送信する.
¶
int MPI_Send(
void
int
MPI_Datatype
int
int
MPI_Comm
*buf,
count,
datatype,
dest,
tag,
comm
³
/*
/*
/*
/*
/*
/*
送信バッファ */
送信データの要素数 */
各要素のデータ型 */
送信先プロセス ID */
タグ */
コミュニケータ */ );
mpi_send(buf, count, datatype, dest, tag, comm, ierr)
<type>
buf(*)
integer
count, datatype, dest, tag, comm
integer
ierr
! 返却コード
µ
MPI Recv
プロセス source からデータを受信する.
3
´
¶
³
int MPI_Recv(
void
int
MPI_Datatype
int
int
MPI_Comm
MPI_Status
*buf,
count,
datatype,
source,
tag,
comm,
*status
/*
/*
/*
/*
/*
/*
/*
受信バッファ */
受信データの要素数 */
各要素のデータ型 */
受信元プロセス ID */
タグ */
コミュニケータ */
ステータス (出力) */ );
mpi_recv(buf, count, datatype, source, tag, comm, status, ierr)
<type>
buf(*)
integer
count, datatype, source, tag, comm, status(mpi_status_size)
integer
ierr
! 返却コード
µ
´
• コミュニケータ (C では MPI_Comm 型) は,プロセスのサブセットを「通信空間」として扱うためのもので,全プロセスで
構成される MPI_COMM_WORLD があらかじめ定義されている.とりあえず,引数 comm には MPI_COMM_WORLD を指定すれば
よい.
• タグは,メッセージを区別するためのもので,送信側と同じタグを指定しないとメッセージは受信できない.
• MPI_Recv の引数 status には,MPI_Status 型変数へのポインタを渡す (C の場合).MPI_Status 型は,MPI_SOURCE,
MPI_TAG, MPI_ERROR の 3 つのメンバを持つ構造体で,それぞれ送信プロセス ID,タグ,エラーコードが格納される.
• MPI_Send および MPI_Recv では,パラメータ count と datatype でメッセージの大きさを指定する.すなわち,メッセー
ジは count 個の値の列を含み,それぞれの MPI データ型が datatype である.MPI データ型には以下のものがある.
MPI データ型
MPI_CHAR
MPI_SHORT
MPI_INT
MPI_LONG
MPI_UNSIGNED_CHAR
MPI_UNSIGNED_SHORT
MPI_UNSIGNED
MPI_UNSIGNED_LONG
MPI_FLOAT
MPI_DOUBLE
MPI_LONG_DOUBLE
2.4
対応する C の型
char
short
int
long
unsigned char
unsigned short
unsigned int
unsigned long
float
double
long double
Collective 通信
Collective 通信では,2 つ以上のプロセスが同一の関数を実行して協調的な通信を行う.Collvective 通信関数の機能は基本的
にはすべて MPI_Send や MPI_Recv 等の Point-to-Point 通信関数の組み合わせで代用できる.しかし,効率的に実装されたもの
を用いれば,Point-to-Point 通信を用いて手でチューニングするよりも楽にパフォーマンス向上が得られる場合があるし,プロ
グラムが読みやすくなるというメリットがある.
ここでは各関数の詳細には触れないが,興味のある方は後述の資料を参照して頂きたい.
2.5
その他の関数
MPI Barrier
バリア同期を行う.すなわち,全プロセスがこの関数を呼ぶまでプロセスをブロックする.
4
¶
³
int MPI_Barrier(
MPI_Comm
comm
mpi_barrier(comm, ierr)
integer
comm
integer
ierr
µ
/* コミュニケータ */ );
! 返却コード
´
MPI Wtime
ある時点からの経過時間 (掛け時計時間) を返す.単位は秒.
¶
³
double MPI_Wtime();
double precision mpi_wtime()
µ
´
以下に,実行時間の測定例を示す.
¶
³
double start, finish;
...
MPI_Barrier(MPI_COMM_WORLD);
start = MPI_Wtime();
/* 全プロセスがここにたどり着くまで待つ */
/* 測定開始 */
...
/* 何らかの処理 */
MPI_Barrier(MPI_COMM_WORLD);
finish = MPI_Wtime();
if (pid == 0)
printf("Elapsed time = %f[sec]\n", finish - start);
µ
/* 測定終了 */
´
MPI にはこの他にも非常に多くの関数がある.中でも重要なのはノンブロッキング通信関数である.ノンブロッキング通信
において,送信や受信は,要求を発行する関数と,終了を待つ関数とに分かれている.要求の発行と終了待ちとの間に他の演
算を行うことで,通信と計算のオーバラップを行い,パフォーマンスを向上させることができる.詳しい説明は省略するが,興
味のある方は後で紹介する資料を参照されたい.
3
Altix3700 上での MPI プログラミング
まず Altix3700 システムにログインする必要がある.altix.educ.cc.keio.ac.jp (131.113.108.84) というホストに ssh
でログインする1 .
¶
³
localhost% ssh -l ログイン名 altix.educ.cc.keio.ac.jp
µ
´
さきほどのサンプルプログラムをコンパイルし,実行してみよう.コンパイルコマンドは icc で,MPI 関数をリンクするた
めに -lmpi オプションが必要である2 .
¶
³
altix% icc -o hello hello.c -lmpi
µ
´
うまくコンパイルできたら,実行してみよう.実行するためには,mpirun というコマンドを用い,-np オプションによって
起動するプロセス数を指定する.
1 最初にログインする前に,ログイン名をシステムに登録しておく必要がある.4.4
2 Fortran77
の場合は ifort コマンドを使用する.
5
節を参照のこと.
¶
³
altix%
Hello,
Hello,
Hello,
Hello,
Hello,
Hello,
Hello,
µ
4
mpirun
world!
world!
world!
world!
world!
world!
world!
-np 8
(from
(from
(from
(from
(from
(from
(from
./hello
process
process
process
process
process
process
process
#1)
#2)
#3)
#4)
#5)
#6)
#7)
´
課題
4.1
問題
MPI を用いて,重力多体問題のシミュレーションを並列に行うプログラムを作成せよ.
多体問題とは,相互作用を及ぼし合う 3 体以上からなる系を扱う問題のことである.重力多体問題は,その中で相互作用が
重力 (万有引力) によるものである場合を扱い,星団や銀河のシミュレーションを行う場合の基本的なモデルとして用いられる.
N 個の質点が与えられたとき,重力多体問題における運動方程式は以下の式で表される.
X
x j − xi
d2 xi
=−
Gm j
2
dt
|x j − xi |3
1≤ j≤N, j,i
ここで, xi , mi はそれぞれ質点 i の位置,質量であり,G は万有引力定数である.しかし,この問題は,N ≥ 3 の場合一般に
は解析的に解けないことが分かっているため,上式を数値積分することによりシミュレーションを行うのが普通である.
シミュレーションは,一般に以下の手順で行われる.
1. N 個の質点の質量 mi ,初期位置 xi ,初期速度 vi (1 ≤ i ≤ N) が与えられる.
2. 質点 i が各質点から受ける重力の総和を計算することにより,加速度 ai を求める.
3. ai について時間積分を行い,質点 i の速度 vi および位置 xi を更新する.
4. 手順 2, 3 を全質点について行う.
5. 手順 2∼4 を時間ステップ数 T だけ繰り返す.
今回の問題では,以上の手順を行った後の各質点の位置 xi および速度 vi を求めてもらう.実際には,main ルーチンその他
のひな型についてはこちらの提供するものを使い,上記手順に従ってシミュレーションを行うルーチン solve_gmbp の中身を
並列化によって高速化するのが目標である.
4.1.1 問題の詳細
はじめ,各プロセスは初期データ取得ルーチンを呼ぶことによって N 個の質点の質量 mi ,初期位置 xi ,初期速度 vi の全体
を取得する (つまり,全プロセスが同じデータを取得する).m は倍精度浮動小数点型の配列であり, x および v は以下の構造
体 (C/C++の場合) を要素とする配列である.初期データは数種類用意されており,毎回ランダムにどれかが取得される.
¶
³
typedef struct
double
double
double
} vector_t;
µ
{
x;
y;
z;
/* x 成分 */
/* y 成分 */
/* z 成分 */
´
solve_gmbp ルーチンは,各プロセスにおいて,m, x,v を引数として呼び出され,シミュレーション結果である T ステッ
プ後の位置,速度を再び x,v に格納して返す.この際,最終的な結果としてはプロセス 0 のもののみが採用されるため,他の
プロセスでは特に結果を格納しなくてもよい.
6
solve_gmbp 内には,並列化されていないシミュレーションコードがすでに記述されているので,これを並列化することに
よって高速化を行えばよい.ただし,このコードでは,数値積分法として 1 次 Symplectic 法 (詳細は略) を採用している.この
手の問題では,数値積分法やその他の部分の計算方法を変えた場合,結果が大きく変わってしまうことがあるので十分注意し
て欲しい.
この他,solve_gmbp 内では,外部変数 pid および nprocs にそれぞれ自身のプロセス ID と全プロセス数があらかじめ格納
されている.
最後に,結果検証ルーチンが呼び出され,あらかじめ保存されている結果と照合することにより判定を行う.その際,2 乗
ノルムによる誤差ノルム率 (Quality Index) を計算し,一定値以上となった場合には不正解と判定する.
実行時間は,solve_gmbp ルーチンを呼び出す直前からリターンした直後までの時間を計測する.
4.1.2 プログラム作成上のルール
•
•
•
•
実装言語は C, C++, Fortran77 のいずれかとする.これらを組み合わせて使用しても構わない.
プロセス数は 8 までとする.用いるプロセス数は固定でも構わない.
並列化に用いるアルゴリズムは自由だが,並列化ツールとして用いるのは MPI のみとする.
提出されたプログラムをこちらで実行し,その実行時間と,得られた結果の精度を元に評価を行う (主要な基準は実行時
間の方である).
• こちらで用意したファイルのうち,main.c,util.c,data.c の 3 つについては改変せずに用いること.サンプルプロ
グラムと共に Web 上で配布する.
• ここで紹介した以外の MPI 関数を用いても構わない.
4.1.3 ヘッダファイルについて
ヘッダファイル gmbp.h 内には以下の定数等が定義されている.
•
•
•
•
•
•
N : 質点の数.
T : タイムステップ数.
DT : 時間刻み幅 (タイムステップ間隔).
G : 万有引力定数.
USE_MPI : #define されていると,MPI を使用する.
USE_FIXED_DATA : #define されていると,毎回同じ初期データが取得されるようになる.(デバッグ用)
USE_MPI をコメントアウトすると,solve_gmbp ルーチン以外の場所にある MPI 関数が無効になる.自宅の PC 等,MPI が
ない環境で試してみたい場合に利用するとよい.
4.2
提出について
すべてのソースファイルをホームディレクトリ以下のどこかのディレクトリにまとめ,
•
•
•
•
ディレクトリのパス,ソースファイルのリスト
コンパイル・実行方法 (プロセス数等)
プログラムの解説 (アルゴリズム,並列化方法等)
考察・感想
を書いたメールを 7 月 26 日 24:00 (7 月 27 日 0:00) までに [email protected] 宛に提出する.Subject は [MPI] ログ
イン名 とすること.正しく提出されれば,自動的に返信メールが来るはずである.レポートを Word や PDF ファイルにして添
付しても構わない.
なお,コピーしたと見なせるレポートがあった場合,それらのレポートは採点しない.誰かにコピーされたりしないように
パミッションを設定するなど,自分のファイルは自分で保護すること.
質問があれば,[email protected] まで.
4.3
評価について
プログラム自体の評価は,実行時間が主な基準となる.公平を期すため,提出されたソースファイルをこちらでコンパイル・
実行した結果を公式の実行結果とする.その際,コンパイルオプションはすべて同じものを指定し,こちらで用意した数種類
のデータで実行してその平均値を採用する予定である.
7
4.4
アカウントについて
理工学 ITC の UNIX アカウント (ログイン名 y*****) を取得する必要がある.以前に取得したことがあっても,今年度の利用
申請を行っていない場合はあらためて申請が必要である.詳細は http://www.educ.cc.keio.ac.jp/guide/account2.html
を参照のこと.
また,Altix3700 システムにログインするには,ログイン名をシステムに登録してもらう必要があるため,最初にログインす
る前にログイン名を [email protected] まで知らせること.
また,Altix3700 の利用に際しては以下の点に注意して欲しい.
• 簡単なソースファイル編集,コンパイル,課題に関連した計算処理以外の目的で利用しないこと.
• プログラムを実行する前に top コマンド等を実行して,他のユーザのプロセスが実行されていないか確認すること.他
のユーザのジョブ実行と重なってしまうと,時間計測が正確に行えないだけでなく,場合によってはメモリとスワップ領
域を使い果たしてシステムが落ちる可能性があるので要注意.
• プロセッサ,メモリ等のリソースを浪費しないこと.システム側の制限により,CPU 時間を 5 分以上使っているプロセ
スは問答無用で kill されることになっている.この他,メモリを確保したまま長時間放置されているプロセス等を発見し
たら,理工学 ITC に頼んで処理してもらうので知らせて欲しい.
例年,提出期限が近くなるとシステムが混雑し,思うように実行時間が計測できなくなったり,システムにトラブルが発生
することが多いため,早めに取り掛かることを強くお勧めする.
なお,課題提出期限を過ぎた後しばらくすると登録が解除されて Altix3700 システムにはログインできなくなる.
4.5
連絡事項について
課題実施期間中の連絡事項は基本的にすべてメールで行うので,定期的にメールを確認すること.連絡用のメールアドレス
を変更したい場合などは [email protected] まで.
5
Web 上の情報源
この授業のページ
MPI の本家
MPI-J メーリングリスト
SGI Altix 3000 シリーズ
NEMO
天野研 PDARCH グループ (参考)
6
http://www.am.ics.keio.ac.jp/comparc/
http://www.mpi-forum.org/
http://phase.hpcc.jp/phase/mpi-j/ml/
http://www.sgi.com/products/remarketed/altix3000/
http://www.sgi.co.jp/servers/altix/
http://bima.astro.umd.edu/nemo/
http://www.am.ics.keio.ac.jp/proj/pdarch/
改訂履歴
• 2007/6/29: バージョン 1.0.
• 2007/6/29: mpirun の使い方を修正.
• 2007/7/7: ソースファイル名変更に伴う修正.また,締切を 7/26 に延長.
8