Reedbushスーパーコンピュータシステム
の利用とMPIプログラムの実行
松本 正晴
大学院情報理工学系研究科コンピュータ科学専攻
本日の講義資料
ITC-LMSの授業スライドにある「計算科学概論0409.pdf」
(前回分の資料)と「計算科学概論0416.pdf」(今回の資料)
を各自ダウンロードしてください。
前提とする知識,条件
C言語またはFortranによるプログラミングの経験は無くてもいいが、今日 は上記の経験がある程度あることを前提に話を進めます。 UNIX環境についての基本的な知識と利用経験 UNIXの基本コマンド,及び,プログラムの基本がわかってないと厳しい 個別に,集中的に教えるよう配慮しますので,遠慮なく聞いてください 知ってる人は近くの人にどんどん教えてあげるとよい。知らない人同士で相 談しながらやるのもよし。 情報基盤センター教育用計算機システム(ECCS)のアカウントを予め取得 しておくこと http://www.ecc.u-tokyo.ac.jp/doc/announce/newuser.html 今日はReedbushスーパーコンピュータシステムの使い方、ならびにMPIの 基礎についての実習です。OpenMPやGPUを使った計算は扱いません。Reedbushアカウントの発行
1. 本人証明ができるものを用意。
• 学生証、運転免許証、など • 無い場合は、ECCSにログインできることで証明。2. 名前を呼びます。
3. 本人確認の上、アカウントが記載された紙を
配布します。
4. 授業で指示があるまで、ログイン作業を行わ
ないでください。
(先週までに名簿登録した者のみです。)ECCSにログイン
1. ECCSのマシンにログインする
•
ユーザ名、パスワードを間違えずに!
•
今配った<スパコンのアカウント>ではない。
2. デスクトップ画面下の「ターミナル」をクリックする。
3. コンソール画面が表示される。
(以降、macでの説明です。)ユーザ名の確認
ユーザ名(利用者番号):
t03xxx
(xxxは3桁番号)
グループ名(課金プロジェクト名):
gt03
紙に書いてある情報が間違えている場合は教えてく
ださい。
秘密鍵/公開鍵の作成
1. ターミナルを起動して、以下を入力する $ ssh-keygen -t rsa 2. 鍵の収納先を聞かれるので、リターンを押す(以前に別の鍵を 作成してそれを使っている場合は、ファイル名を変更しないと上 書きしてしまうので注意) 3. 鍵を使うためのパスワードを聞かれるので、自分の好きなパス ワードを入れる(パスフレーズと呼ぶ) 4. もう一度、上記のパスフレーズを入れる 5. 鍵が生成される。鍵の利用(1/2)
1. 生成した鍵は以下に入っている .ssh/ 2. 以下を入力する $ cd .ssh/ 3. 以下を入力すると、ファイルが見える(以下は例) $ lsid_rsa id_rsa.pub known_hosts • 以下が生成した鍵ファイル
id_rsa :秘密鍵
鍵の利用(2/2)
4. 以下を入力して、公開鍵を表示する $ cat id_rsa.pub <公開鍵が表示される> 5. “ssh-rsa…”で始まる部分を、マウスでカットアンド ペーストし、公開鍵の登録に使う (“.u-tokyo.ac.jp”まで)公開鍵の登録(1/2)
1. Webブラウザ(Safari)を起動 2. 以下のポータルサイトのアドレスを入力する https://reedbush-www.cc.u-tokyo.ac.jp/ 3. 「ユーザ名」にセンターから配布された“利用者番号”を入力する 4. 「パスワード」に、センターから配布された“初期パスワード”を入力 する 記載されている文字列はパスワードではないので注意 【次ページを参照】 5. “Login”ボタンを押すと、“初期パスワード”を変更するよう指示され るので、新しいパスワードを入力して変更する 鍵を作成した際のパスフレーズとは別の文字列を使うこと正しいパスワードの確認とログイン
表示されている文字列の奇数番号(1, 3, 5, 7, 9,
11, 13, 15)の8文字列をつなぎ合わせたもの
例:
P9aesWsbw6oZrrd5
→ Password
ポータル画面(ログイン前)
公開鍵の登録(2/2)
5. パスワードの変更が完了したら、利用者番号と新
しいパスワードを入力して、
“Login”ボタンを押す
6. ログインメッセージが出る
7. (“Change Language”メニューで言語を変更)
8. 左側メニューの「公開鍵アップロード」をクリック
9. 画面に、公開鍵をカットアンドペーストする
10.「作成」ボタンを押す
言語の変更
“Change Language”で日本語に変更できます • “Japanese (JA_JP.UTF-8”)を選んで“Change”を押す • 終わったら、ブラウザを再読み込み 1.ここをクリック 2.ここを選択 3.ここをクリックポータル画面(日本語選択後)
ポータル画面(公開鍵登録)
1.ここに公開鍵をペースト
ポータル画面(公開鍵登録成功)
ペーストした鍵が表示 されていればOK
Reedbushへログイン
ターミナルから、以下を入力 $ ssh reedbush-u.cc.u-tokyo.ac.jp -l t03xxx 「-l」はハイフンと小文字のL 「t03xxx」は利用者番号(t+数字) 接続するかと聞かれるので、yesを入力する 鍵作成時に自分で決めたパスフレーズを入力する 成功するとログインできる 鍵の名前がid_rsaじゃない場合や、.ssh/に無い場合はオプショ ン「-i」で鍵を指定できる ログイン時は必ず/home/gt03/t03XXX/に入る。ReedbushのデータをローカルPCに取り込む
ローカルPC(ECCS)のターミナルでscpコマンドを使う。 $ scp t03xxx@reedbush-u.cc.u-tokyo.ac.jp:~/a.f90 ./ • 「t03xxx」は利用者番号 • 上の例はReedbush上のホームディレクトリにあるa.f90を ローカルPCのカレントディレクトリに取ってくる • ディレクトリごとダウンロードする場合は-rを指定 $ scp –r t03xxx@reedbush-u.cc.u-tokyo.ac.jp:~/SAMPLE ./ • SAMPLEディレクトリをディレクトリごとダウンロードローカルPCのファイルをReedbushに置く
同様にローカルPC(ECCS)のターミナルでscpコマンドを使う。 $ scp ./a.f90 t03xxx@reedbush-u.cc.u-tokyo.ac.jp: • 「t03xxx」は利用者番号 • 上の例はローカルPCのカレントディレクトリにあるa.f90を Reedbush上のホームディレクトリに置く • ディレクトリごとアップロードする場合は-rを指定 $ scp –r ./SAMPLE t03xxx@reedbush-u.cc.u-tokyo.ac.jp: • SAMPLEディレクトリをディレクトリごとアップロードGUIによるファイル操作(主にWindowsユーザ向け)
FileZillaやWinSCPを使えば手元のパソコンとReedbush間のファイル転 送をGUI操作で行うことができる
FileZilla
• https://filezilla-project.org
• “Download Filezilla Client”からダウンロード
• サイトマネージャにてプロトコルをSFTPに設定、ログオンの種類を鍵ファイルにす る(Putty形式の公開鍵ファイルが必要、puttygenによって変換すると良い) WinSCP • https://winscp.net/eng/download.php • プロトコルをSFTPまたはSCPに設定する • ホスト設定画面の設定からSSH-認証を選び、秘密鍵を指定する(OpenSSH形 式・Putty形式の両方に対応)
異なるパソコンの公開鍵登録
1. 同様の手順により、異なるパソコンで公開鍵を作成 2. 「公開鍵のアップロード」メニューの中で、複数登録する ことが可能 3. 鍵認証なので、家のパソコンや自分のノートパソコンか らでも接続可能です。Reedbushにおける注意点
• ログイン時に始めに入る/homeファイルシステムは容量が小 さく(最大2GB)、ログインに必要な設定ファイルだけを置くた めの場所です。 • /homeに置いたファイルは計算ノードから参照できません。 ジョブの実行もできません。 ⇒ ログイン後は/lustreファイルシステムを利用してください。 • ホームディレクトリ:/home/gt03/t03xxx • cdコマンドで移動できます。 • Lustreディレクトリ:/lustre/gt03/t03XXX • cdwコマンドで移動できます。Reedbushにおける計算の仕方
Reedbush-U( CPU only )
Reedbush-H( w/ GPU )
Reedbush-U 1ノードの構成
メモリ 128GB
Intel Xeon E5-2695 v4 (Broadwell-EP) 18コア DDR4 DDR4 DDR4 DDR4 QPI QPI メモリ 128GB
Intel Xeon E5-2695 v4 (Broadwell-EP) 18コア DDR4 DDR4 DDR4 DDR4 76.8GB/s 76.8GB/s 76.8GB/s 1ノード当たり36コア、256GB × 420ノード G3 x16 Infin ib an d EDR HCA 一般的なスーパーコンピュータで は、ノード単位で計算資源を数え ることが多い。 Reedbush-Uの場合、1ノード当た り36コア、256GB(18コア、 128GBが2つ)。これが全部で420 ノードある。 ノード内は共有メモリ型計算機な ので、OpenMPによる並列化が 可能。 ノード間で並列化する際はMPIに よるデータ通信が必要(分散メモ リ型計算機)。
(ちなみに)Reedbush-Hノードのブロック図
26 NVIDIA Pascal NVIDIA Pascal NVLinK 20 GB/s Intel Xeon E5-2695 v4 (Broadwell-EP) NVLinK 20 GB/s QPI 76.8GB/s 76.8GB/s IB FDR HCA G 3x 1 6 15.7 GB/s 15.7 GB/s DDR4 128GB EDR switch E D R 76.8GB/s 76.8GB/s Intel Xeon E5-2695 v4 (Broadwell-EP) QPI DDR4 DDR4 DDR4 DDR4 DDR4 DDR4 DDR4 128GB PCIe sw G 3 x1 6 PCIe sw G 3 x1 6 x16 G3 IB FDR HCA ×120Reedbush-Uで利用できるコンパイラ
Intelコンパイラ
• Fortranコンパイラ :ifort (逐次実行)
:mpiifort (MPI実行,Intel MPI)
• Cコンパイラ :icc (逐次実行)
:mpiicc (MPI実行,Intel MPI)
• C++コンパイラ :icpc (逐次実行)
:mpiicpc (MPI実行,Intel MPI)
ソースファイルをコンパイルして実行ファイルを作成した後にそ れを実行するには“ジョブ”を投げる必要がある。
Reedbush-Hで利用できるGPU用コンパイラ(PGI)
• moduleコマンドを利用して、コンパイラ環境、パスを設定。
$ module load cuda/(バージョン番号) $ module load pgi/(バージョン番号)
• CUDA C
$ nvcc –gencode arch=compute_60,code=sm_60 [options] hoge.cu
• CUDA Fortran
$ pgfortran –Mcuda=cc60 [options] hoge.cuf
• OpenACC
• Fortran: $ pgfortran –acc –ta=tesla,cc60 [options] hoge.f90 • C: $ pgcc –acc –ta=tesla,cc60 [options] hoge.c
Reedbush-Uスーパーコンピュータシステムでのジョブ実行形態
インタラクティブジョブ実行(本実習では利用不可) • PCでの実行のように、コマンドを入力して実行 • スパコン環境では、あまり一般的でない • あくまでもデバッグ用。大規模実行はできない • Reedbush-Uでは、以下に限定 • 1ノード(36コア)、30分まで • 4ノード(144コア)、10分まで バッチジョブ実行 • バッチジョブシステムに処理を依頼して実行する • スパコン環境では一般的な方法。大規模実行用。 • 一般利用では、最大128ノード(4,608コア)、24時間まで。 • 本実習では最大8ノード(288コア)、10分まで。 Reedbush-Uに限らず、スパコン環境では以下の2通りがほとんど。バッチ処理とは?
ユーザ スパコン バッチ処理 システムが ジョブを取り出す 実行 バッチキュー ジョブの依頼 • 一般的なスパコン環境で大規模計算を行う場合、通常、インタラクティ ブ実行(コマンドラインで実行すること)はできません • ジョブはバッチ処理で実行します • キュー(Queue):待ち行列バッチキューの設定の仕方
• バッチ処理はAltair社のバッチシステムPBS Professionalで管理され ている • 以下、主要なコマンドの説明 • ジョブの投入 :qsub <ジョブスクリプトファイル名> • 自分が投入したジョブの状況確認 :rbstat • 投入ジョブの削除 :qdel <ジョブID> • バッチキューの状態を見る :rbstat --rsc • バッチキューの詳細構成を見る :rbstat --rsc -x • 投げられているジョブ数を見る :rbstat –b • 過去の投入履歴を見る :rbstat –H • 同時に投入できる数/実行できる数を見る :rbstat --limitJobスクリプトのサンプルの説明
C言語,Fortran共通 #!/bin/bash #PBS -q u-lecture #PBS –W group_list=gt24 #PBS -l select=8:mpiprocs=4:ompthreads=9 #PBS -l walltime=00:10:00 cd $PBS_O_WORKDIR . /etc/profile.d/modules.sh mpirun ./a.out リソースグループ名 :u-lecture → 授業時間中はu-lecture3 利用グループ名:gt03 利用ノード数 1ノード当たりのMPIプロセス数 実行時間制限:10分 カレントディレクトリ設定、環境変数設定 (必ず記入しておく) 上の例では、ジョブを32プロセス9スレッドの288並列(コア)で実行 (1ノード当たり4プロセス9スレッドでそれが8ノード分) 1プロセス当たりOpenMP スレッド数 Reedbush-Uは1ノー ド当たり36コア。本講義でのキュー名
本演習時間中のキュー名:u-lecture3(Reedbush-U, CPU only) 最大8ノード(288コア),10分まで h-lecture3(Reedbush-H, w/GPU) 最大2ノード、10分まで (CPU:36コア+GPU:2台)×2ノード 本演習時間以外(24時間)のキュー名: u-lecture(Reedbush-U) h-lecture(Reedbush-H) 利用条件は上と同じ ジョブスクリプトの#PBS -qの部分に記載するキューの種類
サンプルプログラムの起動
1.並列版Helloプログラムの実行
UNIXコマンド備忘録(1/3)
emacsエディタの起動: emacs 編集ファイル名 • ^x ^s (^は「controlを押しながら」) :テキストの保存 • ^x ^c :終了 (^zで終了すると、スパコンの負荷が上がる。絶対にしないこと) • ^g :訳がわからなくなったとき • ^k :カーソルより行末まで消す。 消した行は一時的に記憶される。 • ^y :^kで消した行を、現在のカーソルの場所にコピー • ^s 文字列 :文字列の箇所まで移動(検索) • ^M x goto-line :指定した行まで移動 (^MはESCキーを押して離す)UNIXコマンド備忘録(2/3)
• rm ファイル名 :ファイルを消す • ls :現在いるフォルダの中身を見る • cd ディレクトリ名 :ディレクトリに移動する • cd .. :一つ上のディレクトリへ移動する • cd :ホームディレクトリへ行く • cat ファイル名 :ファイルの中身を見る • make :Makefileがある場合、実行ファイルを作る • make clean :実行ファイルを消す (cleanがMakefile内で定義されていないと実行できない。)UNIXコマンド備忘録(3/3)
• less ファイル名 :ファイルの中身を見る (catでは画面がいっぱいになってしますとき) • スペースキー :1画面スクロール • / 文字列 :文字列の箇所まで移動 • q :終了(訳がわからなくなったとき)サンプルプログラム名
• C言語版・Fortran版共通ファイル: Samples.tar • tarで展開後、C言語とFortranのディレクトリが作られる。 C/ :C言語用 F/ :Fortran用 • 上記ファイルが置いてある場所 /lustre/gt03/t03000Samples.tarの中身
• Hello/ • 並列版Helloプログラム • Mat-vec/ • 行列・ベクトル積の計算プログラム • MPI/ • MPI集団通信のサンプルプログラム • Wa1/ • 逐次転送方法による総和演算プログラム • Wa2/ • 二分木通信方式による総和演算プログラム並列版Helloプログラムをコンパイル(1/2)
1. cdwコマンドを実行してlustreファイルシステムへ移動 $ cdw 2. サンプルプログラムの場所/lustre/gt03/t03000にある Samples.tarを自分のディレクトリにコピーする $ cp /lustre/gt03/t03000/Samples.tar ./ 3. Samples.tarを展開する $ tar xvf Samples.tar 4. Samplesディレクトリへ移動 $ cd Samples C言語 : $ cd C Fortran : $ cd F 5. Helloディレクトリへ移動 $ cd Hello並列版Helloプログラムをコンパイル(2/2)
6. ソースファイルをコンパイルする。すでにcompileファイルとい う実行ファイルが用意されているので、それを実行する。
$ ./compile
(以下のコマンドでもコンパイル可)
C言語 :mpiicc hello.c –o hello Fortran :mpiifort hello.f –o hello
7. 実行ファイル(hello)ができていることを確認する
並列版Helloプログラムの実行(ピュアMPI)
• このサンプルのJobスクリプトは hello.bash です。 • サンプルでは、キュー名が“u-lecture”,グループ名が “gt00”になっています。 • $ emacs hello.bash で、キュー名とグループ名をそれぞれ書き換えてください。 u-lecture3 gt03並列版Helloプログラムの実行(ピュアMPI)
1. Helloディレクトリの中で以下を実行 $ qsub hello.bash 2. 自分の導入されたジョブを確認 $ rbstat 3. 実行が終了すると、以下のファイルが生成される hello.bash.exxxxxx hello.bash.oxxxxxx (xxxxxxはJobID) 4. 上記の標準出力ファイルを見てみる cat hello.bash.oxxxxxx5. “Hello parallel world!”が36プロセス×8ノード =288表示されていたら実行成功。
バッチジョブ実行時の標準出力と標準エラー出力
• バッチジョブの実行が終了すると、標準出力ファイルと標準エ ラー出力ファイルがジョブ投入時のディレクトリに作成される。 • 標準出力ファイルにはジョブ実行中の標準出力、標準エラー出 力ファイルにはジョブ実行中のエラーメッセージが出力される。 ジョブ名.oXXXXX --- 標準出力ファイル ジョブ名.eXXXXX --- 標準エラー出力ファイル (XXXXX はジョブ投入時に表示されるジョブのJobID)並列版Helloプログラム(C言語)
#include <stdio.h> #include <mpi.h>
int main(int argc, char *argv[]){ int myid,nprc,ierr;
ierr=MPI_Init(&argc,&argv);
ierr=MPI_Comm_rank(MPI_COMM_WORLD,&myid); ierr=MPI_Comm_size(MPI_COMM_WORLD,&nprc);
printf("Hello parallel world! MyID: %d %d¥n",myid, nprc); ierr=MPI_Finalize(); return 0; } MPIの初期化 自分のrank IDを取得 :各プロセスで値は異なる 全体のプロセッサ台数 を取得 :各プロセスで値は同じ (演習環境では 最大288) MPIの終了 このプログラムは、全PEで起動される
program main implicit none include "mpif.h" integer::myid,nprc,ierr call mpi_init(ierr) call mpi_comm_rank(mpi_comm_world,myid,ierr) call mpi_comm_size(mpi_comm_world,nprc,ierr)
print *, "Hello parallel world! MyID:", myid, nprc call mpi_finalize(ierr)
stop
end program main
並列版Helloプログラム(Fortran)
MPIの初期化 自分のrank IDを取得 :各プロセスで値は異なる 全体のプロセッサ台数 を取得 :各プロセスで値は同じ (演習環境では 最大288) MPIの終了 このプログラムは、全PEで起動されるMPIの集団通信プログラム
前回の資料(計算科学概論0409.pdf)の85ページ
からを参照
プログラムをよく読んで、コンパイル・実行し、結果
を確認してください。
サンプルプログラムの起動
Samples.tarの中身
• Hello/ • 並列版Helloプログラム • Mat-vec/ • 行列・ベクトル積の計算プログラム • MPI/ • MPI集団通信のサンプルプログラム • Wa1/ • 逐次転送方法による総和演算プログラム • Wa2/ • 二分木通信方式による総和演算プログラム行列・ベクトル積の計算プログラム(Mat-vec)
実行結果が、
N = 10000
Elapsed time = 0.286047 [sec.] 699.185843 [MFLOPS] OK! N = 10000 Elapsed time[sec.] = 1.46469116210938 MFLOPS = 136.547557037191 OK! (C言語) (Fortran) のような結果が出たらOK
サンプルプログラムの説明
本プログラムでは、全プロセスが行列Aとベクトルxのデータ を持ち、y=Axの計算をしている。 (C言語) #define N 10000 (Fortran) integer,parameter::N=10000 Nを変更すると、行列サイズを変更できます。 (C言語) #define debug 1 (Fortran) integer,parameter::debug=1 「1」としてコンパイルすると、演算結果が正しいことがチェッ クできます。レポート課題(I)
下記について、実験環境(8ノード、288コア)を駆使して、問題サイズ や並列数を変化させるなどにより性能を評価し、レポートにまとめよ。 1. サンプルプログラムを並列化せよ。このとき、行列Aおよびベクト ルx、yのデータは、全PEでN×Nのサイズを確保してよい。 2. サンプルプログラムを並列化せよ。このとき、行列Aは、初期状態 では、各PEに割り当てられた分の領域しか確保してはいけない。レポート課題(I)の注意
本課題では、MPI通信関数は不要です。 このサンプルプログラムでは、演算結果検証部分 (debug=1にした場合に実行される部分)が並列化され ていないため、MatVec関数のみを並列化しても、検証 部でエラーとなります。 検証部分も、計算されたデータに各PEで対応するよう に、並列化してください。検証部分においても、行列-ベ クトル積と同様のループとなります。本実習プログラムのTIPS
• myid, nprcは大域変数です myid (=自分のID)、および、nprc(=全プロセス数)の変数 は大域変数です。MyMatVec関数内で、引数設定や宣 言なしに、参照できます。 • myid, nprcの変数を使う必要があります MyMatVec関数を並列化するには、 myidおよび、nprc変 数を利用しないと、並列化ができません。並列化の考え方(C言語)
for ( j=0; j<N; j++) { 内積( j, i ) } PE0 for ( j=0; j<N/4; j++) { 内積( j, i ) } PE1 for ( j=N/4; j<(N/4)*2; j++) { 内積( j, i ) } PE2 for ( j=(N/4)*2; j<(N/4)*3; j++) { 内積( j, i ) } PE3 for ( j=(N/4)*3; j<N; j++) { 内積( j, i ) } 各PEで 重複して 所有する 行列A ベクトルx n n SIMDアルゴリズムの考え方(4PEの場合)並列化の考え方(Fortran言語)
do j=1, N 内積( j, i ) enddo PE0 do j=1, N/4 内積( j, i ) enddo PE1 do j=N/4+1, (N/4)*2 内積( j, i ) enddo PE2 do j=(N/4)*2+1, (N/4)*3 内積( j, i ) enddo PE3 do j=(N/4)*3+1, N 内積( j, i ) enddo 各PEで 重複して 所有する 行列A ベクトルx n n SIMDアルゴリズムの考え方(4PEの場合)PE0 PE1 PE2 PE3
初心者が注意すること
A[N][N] A[N][N] A[N][N] A[N][N]
PE0 PE1 PE2 PE3
myid = 0 myid = 1 myid = 2 myid = 3
各PEでは、独立した配列が個別に確保されます。
myid変数は、MPI_Comm_rank()関数が呼ばれた段階で、各PE
1. 全PEで行列AをN×Nの大きさ、ベクトルx、yをNの大きさ、確保してよいと する。 2. 各PEは、担当の範囲のみ計算するように、ループの開始値と終了値を変 更する。ブロック分散方式では、以下になる。 (N が nprc で割り切れる場合) ib = N / nprc;
for ( nj=myid*ib; nj<(myid+1)*ib; nj++) { … }
3. (2の並列化が完全に終了したら)各PEで担当のデータ部分しか行列を確 保しないように変更する。上記のループは、以下のようになる。
for ( nj=0; nj<ib; nj++) { … }
1. 全PEで行列AをN×Nの大きさ、ベクトルx、yをNの大きさ、確保してよいと する。 2. 各PEは、担当の範囲のみ計算するように、ループの開始値と終了値を変 更する。ブロック分散方式では、以下になる。 (N が nprc で割り切れる場合) ib = N / nprc
do nj=myid*ib+1, (myid+1)*ib …. enddo
3. (2の並列化が完全に終了したら)各PEで担当の データ部分しか行列を確保しないように変更する。 上記のループは、以下のようになる。
do nj=1, ib …. enddo
並列化の方針(行列-ベクトル積)(C言語)
PE0 PE1 PE2 PE3 for ( nj=0; nj<(N/4); nj++) { 内積( nj, ni ) } for ( nj=(N/4); nj<(N/4)*2; nj++) { 内積( nj, ni ) } for ( nj=(N/4)*2; nj<(N/4)*3; nj++) { 内積( nj, ni ) } for ( nj=(N/4)*3; nj<N; nj++) { 内積( nj, ni ) } ※各PEで使われない領域が出るが、担当範囲指定がしやすいので実装がしやすい。 全PEでN×N行列を持つ場合並列化の方針(行列-ベクトル積)(Fortran言語)
PE0 PE1 PE2 PE3 do nj=1, N/4 内積( nj, ni ) enddo do nj=N/4+1, (N/4)*2 内積( nj, ni ) enddo do nj=(N/4)*2+1, (N/4)*3 内積( nj, ni ) enddo do nj=(N/4)*3+1, N 内積( nj, ni ) enddo 全PEでN×N行列を持つ場合 ※各PEで使われない領域が出るが、担当範囲指定がしやすいので実装がしやすい。並列化の方針(行列-ベクトル積)
PE0 PE1 PE2 PE3 = = = = この方針では、y=Axのベクトルyは、以下のように一部分しか計 算されないことに注意!並列化時の注意
演習環境は、最大288PEです。 並列化は、<できた>と思ってもバグっていることが多い! このサンプルの検証部分(debug=1の時に実行される部分)は、PE0がベ クトルyの要素すべてを所有することが前提となっています。 出力結果を考慮して検証部分も並列化してください。 Nを小さくして、printfで結果(ベクトルy)を目視することも、デバックになり ます。しかし、Nを目視できないほど大きくする場合にバグることがありま す。目視のみデバックは、経験上お勧めしません。 数学ライブラリ開発では、できるだけ数学(線形代数)の知識を利用した 方法で、理論的な解と結果を検証することをお勧めします。時間計測方法(C言語)
double t0, t1, t2, t_w; .. ierr = MPI_Barrier(MPI_COMM_WORLD); t1 = MPI_Wtime(); <ここに測定したいプログラムを書く> t2 = MPI_Wtime(); t0 = t2 - t1;ierr = MPI_Reduce(&t0, &t_w, 1, MPI_DOUBLE,MPI_MAX, 0, MPI_COMM_WORLD); バリア同期後、時間を 習得し保存 各プロセッサ(プロセス)で、 t0の値は異なる。 この場合は、最も遅いもの の値をプロセスID = 0 (rank0)が受け取る。
double precision t0, t1, t2, t_w double precision MPI_WTIME
..
call MPI_BARRIER(MPI_COMM_WORLD, ierr) t1 = MPI_WTIME(ierr) <ここに測定したいプログラムを書く> t2 = MPI_WTIME(ierr) t0 = t2 - t1 call MPI_REDUCE(t0, t_w, 1, & MPI_DOUBLE_PRECISION,
& MPI_MAX, 0, MPI_COMM_WORLD, ierr)
時間計測方法(Fortran)
バリア同期後、時間を 習得し保存 各プロセッサ(プロセス)で、 t0の値は異なる。 この場合は、最も遅いもの の値をプロセスID = 0 (rank0)が受け取る。サンプルプログラムの起動
Samples.tarの中身
• Hello/ • 並列版Helloプログラム • Mat-vec/ • 行列・ベクトル積の計算プログラム • MPI/ • MPI集団通信のサンプルプログラム • Wa1/ • 逐次転送方法による総和演算プログラム • Wa2/ • 二分木通信方式による総和演算プログラム総和演算プログラム(Wa1, 逐次転送方式)
各MPIプロセスが所有するデータを、全プロセスで加算し、あるプロセス1つが結果 を所有するという処理を考える。 素朴な方法(逐次転送方式) 1. (rankIDが0でなければ)左隣のプロセスからデータを受信 2. 左隣のプロセスからデータが来ていたら 1. 受信する 2. <自分のデータ>と<受信データ>を加算する 3. (255番でなければ)右隣のプロセスに<2の結果>を送信する 4. 処理を終了する 実装上の注意 • 左隣とは、(myid-1)のIDをもつプロセス • 右隣とは、(myid+1)のIDをもつプロセス • myid=0のプロセスは左隣はないので、受信はしない • myid=p-1のプロセスは右隣はないので、送信はしない逐次転送方式(バケツリレー方式)による加算
CPU0 CPU1 CPU2 CPU3
0 1 2 3 0 所有データ 0 + 1 = 1 1 1 + 2 = 3 3 3 + 3 = 6 送信 送信 送信 最終結果 所有データ 所有データ 所有データ
1対1通信利用例(Wa1, 逐次転送方式、C言語)
void main(int argc, char* argv[]) { … MPI_Status istatus; … dsendbuf=(double)myid; drecvbuf=0.0; if(myid!=0){ ierr=MPI_Recv(&drecvbuf,1,MPI_DOUBLE,myid-1,0,MPI_COMM_WORLD,&istatus); } dsendbuf=dsendbuf+drecvbuf; if(myid!=nprc-1){ ierr=MPI_Send(&dsendbuf,1,MPI_DOUBLE,myid+1,0,MPI_COMM_WORLD); } if(myid==nprc-1) printf("Total=%4.2lf¥n",dsendbuf); … } 受信用システム配列の確保 自分より一つ少ないID番号(myid-1)から、double 型データ1つを受信しdrecvbuf変数に代入 自分より一つ多いID番号(myid+1)に、dsendbuf変数 に入っているdouble型データ1つを送信
program main … integer istatus(mpi_status_size) … dsendbuf=dble(myid) drecvbuf=0.0d0 if(myid/=0) then call mpi_recv(drecvbuf,1,mpi_double_precision,myid-1,0,& mpi_comm_world,istatus,ierr) endif dsendbuf=dsendbuf+drecvbuf if(myid/=nprc-1) then call mpi_send(dsendbuf,1,mpi_double_precision,myid+1,0,& mpi_comm_world,ierr) endif if(myid==nprc-1) then
print *,"Total = ",dsendbuf endif
…
end program main
1対1通信利用例(Wa1, 逐次転送方式、Fortran)
受信用システム配列の確保 自分より一つ少ないID番号(myid-1)から、double precision型データ1つを受信しdrecvbuf変数に代入 自分より一つ多いID番号(myid+1)に、dsendbuf変数 に入っているdouble precision型データ1つを送信総和演算プログラム(Wa2, 二分木通信方式)
二分木通信方式
(256プロセスでの計算であることに注意)
1. nj = 1;
2. for (ni=0; ni < log2(nprc); ni++) 3. if ( (myid & nj) == nj) • (myid – nj)番プロセスからデータを受信; • 自分のデータと、受信データを加算する; • nj = nj * 2; 4. else • (myid + nj)番プロセスに、データを転送する; • 処理を終了する;