演習 II ( 連続系アルゴリズム ) 第 1 回 : MPI 須田研究室 M2 本谷徹 motoya@is.s.u-tokyo.ac.jp 2012/10/05 2012/10/18 補足 訂正
演習 II 2 つの講義の演習 奇数回 : 連続系アルゴリズム 部分 偶数回 : 計算量理論 部分 連続系アルゴリズム部分は全 8 回を予定 前半 2 回 高性能計算 後半 6 回 数値計算 4 回以上の課題提出 ( プログラム + 考察レポート ) で単位 http://olab.is.s.u-tokyo.ac.jp/~reiji/enshu2_12.html
高性能計算 高い計算性能を達成することを目的 ソフトウェアの目標 ハードの性能を最大限活用
MPI を用いた並列プログラミング ネットワークで繋がれた並列環境が対象 分散メモリ型 : 京, Blue Gene, TSUBAME 大規模 高性能な計算を目的としている そのプロセス間通信に使われるライブラリ群 Message Passing Interface C, Fortran から呼び出せる
MPI を用いた並列プログラミング SPMD (Single Program Multiple Data) 各プロセスは全て同じプログラムを実行 プロセスはシステムリソースを共有しない 異なるプロセッサ, 異なるデータ C からは mpi.h を include して使用 $ mpicc foo.c でコンパイル $ mpirun -np <np> a.out で実行 -np <np> は起動するプロセスの数
MPI 定義定数 MPI_Comm MPI_COMM_WORLD コミュニケータ 通信グループとなるプロセスの情報が入っている MPI 通信ライブラリを呼ぶときにはこれを必ず渡す 長くて不便? #define MCW MPI_COMM_WORLD int MPI_SUCCESS MPI 関数が成功したときに返る値 MPI_Datatype MPI_CHAR, MPI_INT, MPI_DOUBLE, MPI_FLOAT 対応する型を表す MPI_Op MPI_MAX, MPI_MIN, MPI_SUM, MPI_PROD 演算の種類を表す それぞれ最大値, 最小値, 総和, 積
MPI 基本 API int MPI_Init(int *argc, char ***argv) 全ての MPI 関数を呼ぶ前に必ず 1 度だけ呼ぶ関数 int MPI_Finalize(void) 最後の MPI 関数を呼んだ後に必ず 1 度だけ呼ぶ関数 int MPI_Comm_size(MPI_Comm comm, int *size) size にプロセスの数が入って返ってくる関数 int MPI_Comm_rank(MPI_Comm comm, int *rank) rank に自分のプロセス番号が入って返ってくる関数
サンプルコード 実行例 $ mpicc hoge.c $ mpirun -np 5 a.out I am 2nd process I am 1st process I am 0th process I am 3rd process I am 4th h process $ csc では Torque の script に実行コマンドを書いてください {stderr, stdout} は ( スクリプト名 ).{e, o}( ジョブ id) に出力されます hoge.c #include <stdio.h> #include "mpi.h" int main(int argc, char *argv[]){ int myid; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&myid); if(myid%10==1&&myid!=11) printf ("I am %dst process\n", myid); else if(myid%10==2&&myid!=12) printf ("I am %dnd process\n", myid); else if(myid%10==3&&myid!=13) printf ("I am %drd process n", myid); else printf ("I am %dth process n", myid); MPI_Finalize(); return 0; }
MPI での時間計測 以下のように時間を計測し MPI_Barrier(MPI_COMM_WORLD); t0 = MPI_Wtime(); /* ここで計算 通信をします */ MPI_Barrier(MPI_COMM_WORLD); t1 = MPI_Wtime(); double MPI_Wtime(void) 経過時間を秒で返す関数 int MPI_Barrier(MPI_Comm comm) コミュニケータ内のプロセスの同期を取る elapsed_time = t1 - t0; 全てのプロセスの最大経過時間を所要時間とする MPI_Reduce(&elapsed_time, &max_time, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); If (myrank==0){ printf( elapsed time = %10.7e\n, max_time); }
MPI 通信ライブラリ プロセス間通信関数には 2 種類存在 1 対 1 通信 集団通信 コミュニケータに属する全てのプロセスが参加 通信しながら計算もしてくれるものも 大抵はブロッキング通信 通信が終わるまで処理が中断される デッドロックに注意
MPI1 対 1 通信 (1) int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status) buf: 送受信バッファ, count: 要素数, datatype: 型, dest/source: 送信先 / 受信先, tag: 識別子, status: 受信結果 以下の例ではデッドロックします If(myrank==0){ MPI_Send(sbuf, n, MPI_INT, 1, 0, MPI_COMM_WORLD); MPI_Recv(rbuf, n, MPI_INT, 1, 0, MPI_COMM_WORLD, &status); } Else if(myrank==1){ MPI_Send(buf, n, MPI_INT, 0, 0, MPI_COMM_WORLD); MPI_Recv(rbuf, n, MPI_INT, 0, 0, MPI_COMM_WORLD, &status); }
MPI1 対 1 通信 (2) int MPI_Isend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request) int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status, MPI_Request *request) ノンブロッキング通信 すぐに戻ってくる request に状態が入る int MPI_Wait(MPI_Request *request, MPI_Status *status) request の通信が完了するまでブロックする Isend, Irecv の buf は MPI_Wait するまで触ってはいけない
MPI 集団通信 状況に応じて使いこなす int MPI_Bcast (void *buf, int count, MPI_Datatype datatype, int root, MPI_Comm comm) int MPI_Reduce(void *sendbuf, void *recvbuf, int count,mpi_datatype datatype, MPI_Op op, int root, MPI_Comm comm) int MPI_Scatter(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) int MPI_Gather (void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm) int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_ Datatype recvtype, MPI_Comm comm) int MPI_Reduce_scatter(void *sendbuf, void *recvbuf, int recvcnts, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) int MPI_Allreduce(void *sendbuf, void * recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) int MPI_Alltoall(void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm) http://olab.is.s.u-tokyo.ac.jp/~reiji/mpicollective.pdf がわかりやすい
第 1 回課題 並列ソートを実装してください 0.2 秒以下でソートできた最大の個数 N を報告 学科計算機 csc 上にて P プロセスで実行するとする rand() 関数で各プロセスに N/P 個の整数を発生させる 0 ~ RAND_MAX の一様乱数 各マシンで異なる seed を与える ソート終了時にも各マシンは N/P 個の整数を持つ ソート終了時 ランク id のプロセスの整数でランク (id+1) の整数を超えるものは無い 使用するノード数の上限は 8 とする srand(pid) 工夫や考察をレポートにまとめてください
csc 情報科学科の GPU クラスタ 東工大 GPU スパコン : TSUBAME 2.0 の 1 ラック 16 ノード CPU: Xeon X5670 x 2 ( 6core 2.93GHz ) MEMORY: 48 GB PC3-10600 GPU: Tesla M2050 以下の内部マニュアルを参照 http://www.is.s.u-tokyo.ac.jp/naibu/misc/csc_manual.pdf スパコンはみんなで仲良く使いましょう TSUBAME2.0 ガイダンス配布資料 http://tsubame.gsic.titech.ac.jp/sites/default/files/tsubame2-guidance_0.pdf
Torque csc にはバッチジョブ管理システム Torque が導入 システムはジョブ単位でプログラムを実行 今回の課題では Torque 用の script を用いて下さい 以下の内部マニュアルを参照 http://www.is.s.u-tokyo.ac.jp/naibu/misc/csc_manual.pdf
課題について renzoku-enshu@is.s.u-tokyo.ac.jp に提出 氏名 学籍番号 出題日を明記 演習 II であることも明記 レポートを pdf にした上でメールで提出 Subject は 演習 2 第? 回レポート提出者氏名 プログラム + レポート 課題の半分以上の提出が単位の取得条件 全 8 回を予定 締切は各課題出題日から2 週間後 http://olab.is.s.u-tokyo.ac.jp/~reiji/enshu2_12.html を参照
csc で MPI が動かない問題 ( 補足 )! 必ず確認 対処して下さい!! 今後の csc での実験全てに差し障ります! 原因 : ライブラリのパスが通ってない 去年の情報科学基礎実験で csp の設定を変更 csc と csp は /home 以下を共有 シェルの設定ファイル (.cshrc や.bashrc ) に setenv LD_LIBRARY_PATH /home/yoshizoe/local/lib export LD_LIBRARY_PATH=/home/yoshizoe/local/lib などとパスを書き換えるコマンドがあることが原因 対策 : シェル設定ファイルの上記該当箇所を削除 Thanks: 美添さん