More Related Content Similar to Dentoo.LT12 並列処理・MPIの第一歩 20151025
Similar to Dentoo.LT12 並列処理・MPIの第一歩 20151025 (20) More from HPCシステムズ株式会社 (20) Dentoo.LT12 並列処理・MPIの第一歩 201510251. 並列処理・MPIの第一歩
Introduction to
Message Passing Interface
25 October 2015 / 於: 電気通信大学
田名部 誠一, Sei-Ichi Tanabe-Tanabu
※本資料内容および本自己紹介は所属組織の統一的見解ではなく、個人的見解によるものです。
@n_scattering .
seiichi.tanabetanabu .
Dentoo.LT #12 Lightning Talk
Google+も
やっております。
3. 自己紹介
田名部 誠一 (たなべ/たなぶ せいいち)
• 所属:
– とある柳橋の計算機屋の末端社員
• 役割:
– ハイパフォーマンスコンピューティング(HPC)に
有用な(?)技術の調査、プログラムの開発、
社内情報システム管理など、極端に広く浅く
• 電通大との関わり:
– 1994年は落ち、1995年に電子物性工学科(F科)に入学
修士課程まで、渡辺信一研究室にいました。
– 別の大学でDを取ったが、研究者になりそこねた。
2015/10/25 3 /32
Dentoo.LT #12 @電気通信大学
4. 趣味(?)にしていること
頻度が高めな順に
• Ingress (前回#11でお話ししました。)
– http://www.slideshare.net/seiichitanabetanabu/dentoolt11-20150510-lt
– 運動療法として始めたが、歩き過ぎに注意
• 各種IT勉強会
• 発達障害(自閉症スペクトラム)・双極性障害の
当事者会への参加
• 乗り鉄 (なかなかできない)
• 研究所・研究施設等の一般公開の見学
2015/10/25 4 /32
Dentoo.LT #12 @電気通信大学
5. なぜHPCか、並列処理か?
• 並列計算の経験がない!これはまずい!
• 計算機周辺の性能の向上
• CPU、メモリ、ストレージ、ネットワーク…
• だけど、ユーザーの要求も高い!
• そこで、並列計算! (計算機の共同作業!)
– 計算時間の短縮
• N並列ならば、1/Nの計算時間になるのが理想
だが、そうはいかないのが実情…(チューニングなどの工夫)
– 大容量のメモリを必要とする計算も可能
• 1台でできないけど、クラスタにすればできる
2015/10/25 5 /32
Dentoo.LT #12 @電気通信大学
6. 並列計算機について
• 並列ではない計算機(昔のPC)
• 共有メモリ型並列計算機(最近のPCも)
• 1筐体にプロセッサ■(コア)が複数
• 全プロセッサが1つのメモリ■を共有
• 並列化の手段: MPI、OpenMP
• 分散メモリ型並列計算機(クラスタ構成)
• 筐体(ノード)が複数。ネットワーク接続
• 各筐体が独自にメモリ■を所有
• 並列化の手段: MPI
• →ノード間で通信をすることで、
全ノードのメモリが使えるようになる
2015/10/25 6 /32
Dentoo.LT #12 @電気通信大学
メモリ
7. MPIとは?
• Message Passing Interface
分散メモリ間のメッセージ通信の規格
• 実装としてはMPICH、OpenMPIが有名
https://www.mpich.org/
http://www.open-mpi.org/
• プログラマが細かなチューニングを行える
• 明示的に手続きを記述する必要がある
2015/10/25 7 /32
Dentoo.LT #12 @電気通信大学
8. MPI関数の紹介
• MPI関数は数百種類。必要最低限の関数
• 1. システム関数
– MPI_Init; MPI_Comm_rank; MPI_Comm_size; MPI_Finalize;
• 2. 1対1通信関数 (多対多の通信もあるが割愛)
– MPI_Send; MPI_Recv;
• 3-1. 通信の同期
– MPI_Barrier
• 3-2. 時間計測関数
– MPI_Wtime
2015/10/25 8 /30
Dentoo.LT #12 @電気通信大学
9. A. MPI_INIT
2015/10/25 9 /32
Dentoo.LT #12 @電気通信大学
• MPI環境の初期化。
• すべてのMPIルーチンの最初に1回だけ必ず
コールする必要がある。
• CALL MPI_INIT(ierr)
– ierr: 完了コードが戻る
10. B. MPI_FINALIZE
2015/10/25 10 /32
Dentoo.LT #12 @電気通信大学
• MPI環境の終了処理。
• すべてのMPIルーチンの最後に1回だけ必ず
コールする必要がある。
• CALL MPI_FINALIZE(ierr)
– ierr: 完了コードが戻る
11. C. MPI_COMM_RANK
2015/10/25 11 /32
Dentoo.LT #12 @電気通信大学
• コミュニケーターcommで指定したグループ(職
場)内での自分(=コールしたプロセス)のランク
(「名前・社員番号」)を取得する。
• CALL MPI_COMM_RANK(comm,rank,ierr)
– comm: コミュニケーター(職場)を指定
(ここではMPI_COMM_WORLD、全体を指定します)
– rank: commで指定したグループ内での自分(=コールした
プロセス)のランク(名前・社員番号)
– ierr: 完了コードが戻る
12. D. MPI_COMM_SIZE
2015/10/25 12 /32
Dentoo.LT #12 @電気通信大学
• コミュニケーターcommで指定したグループ(職
場)に含まれるプロセスの数を得る。
(プロセッサ数、並列数、「従業員数」)
• CALL MPI_COMM_SIZE(comm,procs,ierr)
– comm: コミュニケーター(職場)を指定
(ここではMPI_COMM_WORLD、全体を指定します)
– procs: commで指定したグループ内に含まれるプロセス
の数(「従業員数」)
– ierr: 完了コードが戻る
13. 並列版Helloプログラムの説明(1)
(プログラム1, Fortran) 軽く
program main
include "mpif.h"
common /mpienv/myid,numprocs
integer myid, numprocs
integer ierr
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, myid, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
print *, "Hello parallel world! Myid:", myid
call MPI_FINALIZE(ierr)
stop
end
2015/10/25 13 /32
Dentoo.LT #12 @電気通信大学
14. 並列版Helloプログラムの説明(2)
(プログラム1, Fortran) 軽く
program main
include "mpif.h"
common /mpienv/myid,numprocs
integer myid, numprocs
integer ierr
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, myid, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
print *, "Hello parallel world! Myid:", myid
call MPI_FINALIZE(ierr)
stop
end
2015/10/25 14 /32
Dentoo.LT #12 @電気通信大学
このプログラムは、全プロセス
(全従業員)で起動される
A. MPIの初期化
C. 自プロセスのID番号「社員番号」
(myid)を取得します。
(各プロセス・従業員で番号が異なります。)
D. 全体のプロセッサ台数「従業員数」
(numprocs)を取得します。
(各プロセス・従業員で値は同じ)
B. MPIの終了
15. 並列版Helloプログラムの説明
(C言語、参考) 軽く
#include <stdio.h>
#include "mpi.h"
int main(int argc, char* argv[]) {
int myid, numprocs;
int ierr, rc;
ierr = MPI_Init(&argc, &argv);
ierr = MPI_Comm_rank(MPI_COMM_WORLD, &myid);
ierr = MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
printf("Hello parallel world! Myid:%d n", myid);
rc = MPI_Finalize();
}
2015/10/25 15 /32
Dentoo.LT #12 @電気通信大学
C言語では、関数名(MPI_Initなど)の
大文字・小文字の使い方が異なります
C言語では、完了コード(ierr)を得る方法が異なります
16. 並列版Hello実行結果 軽く
2015/10/25 16 /32
Dentoo.LT #12 @電気通信大学
[tanabe@tanabe sample]$ mpif90 sample1.f90 -o sample1
(コンパイル)
[tanabe@tanabe sample]$ mpirun -n 2 sample1
(2並列「従業員数2名」で実行)
Hello parallel world! Myid: 0
Hello parallel world! Myid: 1
[tanabe@tanabe sample]$
(全プロセス「従業員」に対してHello parallel world!
と、ランク「名前・社員番号」を表示する。
同じ処理を実行しているが、Myidの値で結果が変わる。)
17. E. MPI_SEND
2015/10/25 17 /32
Dentoo.LT #12 @電気通信大学
• 1対1ブロッキング通信サブルーチン(送信)
• 送信メッセージを宛先プロセスに送信。
– 特定の従業員に「仕事を指示する」作業
• ただし、その人が聞いているとは限らない。
→指示した従業員に案件番号を指定し指示を聞いてもらう作業が必要
• 送信したメッセージはMPI_RECVで受信する。
Myid=0
Myid=1
Myid=2
MPI_SEND!!
MPI_RECVで
受信!!
メッセージ
18. E. MPI_SEND 軽く
2015/10/25 18 /32
Dentoo.LT #12 @電気通信大学
• CALL MPI_SEND(buf,count,datatype,
dest,tag,comm,ierr)
– buf: 送信バッファーの先頭アドレス(変数)
– count: 送信メッセージの要素数 (※バイト数ではない)
– datatype: 送信メッセージのデータ型
– dest: 宛先プロセスのcomm内のランク(名前・社員番号)
– tag: 送信メッセージの種類を区別するタグ
メッセージの「案件番号」
– comm: コミュニケーター「職場」を指定
(ここではMPI_COMM_WORLD、全体を指定します)
– ierr: 完了コードが戻る
19. F. MPI_RECV
2015/10/25 19 /32
Dentoo.LT #12 @電気通信大学
• 1対1ブロッキング通信サブルーチン(受信)
• 送信元プロセスから送信されたメッセージを受
信する。
– 特定の誰かから「仕事の依頼を受ける」作業
• ただし、その人への指示、受けるべき依頼とは限らない。
→受けるべき特定の誰かからの指示、案件内容が必要
• MPI_SENDで送信したメッセージを受信する。
Myid=0
Myid=1
Myid=2
MPI_SENDで
送信した!!
MPI_RECVで
受信!!
メッセージ
20. F. MPI_RECV 軽く
2015/10/25 20 /32
Dentoo.LT #12 @電気通信大学
• CALL MPI_RECV(buf,count,datatype,
source,tag,comm,status,ierr)
– buf: 受信バッファーの先頭アドレス(変数)
– count: 受信バッファーの要素数 (※バイト数ではない)
– datatype: 受信メッセージのデータ型
– source: 送信するプロセスのcomm内のランク(名前・社員番号)
– tag: 送信メッセージの種類を区別するタグ「案件番号」
– comm: コミュニケーター「職場」を指定
(ここではMPI_COMM_WORLD、全体を指定します)
– status: 受信状況に関する情報(整数配列)
– ierr: 完了コードが戻る
21. 並列版送受信プログラムの説明(1)
(プログラム2, Fortran) 軽く
program main
include “mpif.h”
common /mpienv/myid,numprocs
integer myid, numprocs
integer isbuf, irbuf, ierr
integer istatus(MPI_STATUS_SIZE)
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, myid, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
if (myid.eq.0) then
isbuf = 19750617
endif
(続く)
2015/10/25 21 /32
Dentoo.LT #12 @電気通信大学
myid(ランク・社員番号)が0のプロセスの
変数isbufの変数を代入
MPI_RECVの処理で
必要な変数
受信状況に関する
情報(整数配列)
準
備
22. 並列版送受信プログラムの説明(2)
(プログラム2, Fortran) 軽く
(続く)
if (myid.eq.0) then
call MPI_SEND (isbuf,1,MPI_INTEGER,1,1,MPI_COMM_WORLD,ierr)
elseif (myid.eq.1) then
call MPI_RECV (irbuf,1,MPI_INTEGER,0,1,MPI_COMM_WORLD,
istatus, ierr)
endif
if (myid.eq.1) then
write(*,*) "IRBUF =",irbuf
endif
call MPI_FINALIZE(ierr)
stop
end
2015/10/25 22 /32
Dentoo.LT #12 @電気通信大学
Myid(ランク・社員番号)が1のプロセス
の変数irbufの内容を確認する。
Myid=0のプロセス(従業員)から、
Myid=1のプロセス(従業員)にデータが
送信されている!
0から1に送信!!
0から来たメッセージ
を1が受信!!
処
理
の
決
定
「案件番号」は1
23. 並列版送受信実行結果 軽く
2015/10/25 23 /32
Dentoo.LT #12 @電気通信大学
[tanabe@tanabe sample]$ mpif90 sample2.f90 -o sample2
(コンパイル)
[tanabe@tanabe sample]$ mpirun -n 2 sample2
(2並列、従業員数2名で実行)
IRBUF = 19750617
(従業員Myid=0から従業員Myid=1に対して、送信された整数値
を受信できたことを確認する。)
Myid=0
Myid=1
MPI_SENDで
送信した!!
MPI_RECVで
受信!!
19750617 確認
24. G. MPI_BARRIER
2015/10/25 24 /32
Dentoo.LT #12 @電気通信大学
• コミュニケーターcomm「職場」内の全プロセス
「全従業員」間で同期をとる関数
– ある職場の共同作業で、全部の結果が揃わないと
次の作業ができない場合に、最後まで待つ
• CALL MPI_BARRIER(comm, ierr)
– comm:コミュニケーター「職場」を指定
(ここではMPI_COMM_WORLD、全体を指定します)
– ierr: 完了コードが戻る
25. H. MPI_WTIME
2015/10/25 25 /32
Dentoo.LT #12 @電気通信大学
• 時刻を得る関数。 (※たぶんUnix時間)
• 経過時間の測定をしたい部分の前後で実行し、
得られた値elpの差を取ると、その部分の実行
時間が得られる。
• elp = MPI_WTIME ()
– elp: ある過去の時点からの経過時間(秒)
26. 時刻同期プログラムの説明(1)
(プログラム3, Fortran) 軽く
program main
implicit none
include "mpif.h"
common /mpienv/myid,numprocs
integer myid, numprocs
integer ierr
integer*8 i, j, iinput, ioutput
real*8 elp1, elp2
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, myid, ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr)
(続く)
2015/10/25 26 /32
Dentoo.LT #12 @電気通信大学
計算で必要な変数
時間計測で必要な変数
心
の
準
備
27. 時刻同期プログラムの説明(2)
(プログラム3, Fortran) 軽く
(承前)
! preparation
elp1 = MPI_WTIME()
iinput=0
do i=1, 50000*(myid+1)
do j=1, 50000
iinput = iinput + 1
enddo
enddo
! mpi_barrier
call MPI_BARRIER(MPI_COMM_WORLD, ierr)
! summation
ioutput=0
do i=1, 50000
do j=1, 50000
ioutput = ioutput + 1
enddo
enddo
write(*,*) iinput, ioutput, 'myid=' , myid
(続く)
2015/10/25 27 /32
Dentoo.LT #12 @電気通信大学
(作業1) Myid(ランク)の値に応じた回数
だけ足し算を行う。
(従業員により、かかる時間が異なる)
(作業2) 決まった回数だけ足し算を行う。
(従業員間でかかる時間はあまり変わらない)
結果の確認
全プロセスの同期を取る
(全従業員の作業が終わるまで待つ)
時間の測定(計算前)
作
業
1
作
業
2
28. 時刻同期プログラムの説明(3)
(プログラム3, Fortran)
2015/10/25 28 /32
Dentoo.LT #12 @電気通信大学
• MPI_BARRIERで同期
• 同期しない場合
Myid=0
Myid=1
Myid=2
MPI_BARRIERで
全プロセスの同期を取る
(全従業員の作業が終わ
るまで待つ)
作業1
作業2経過時間
Myid=0
Myid=1
Myid=2
作業2を行うためには、作
業1を終わらせなくてはい
けない!
そのために、同期が必要
なはず。
意図した動作が行われな
い!!
29. (承前)
elp2 = MPI_WTIME()
write(*,*) 'ELAPSE=', elp2-elp1, 'myid=',myid
call MPI_FINALIZE(ierr)
stop
end
時間の測定(計算後)
時刻同期プログラムの説明(4)
(プログラム3, Fortran) 軽く
2015/10/25 29 /32
Dentoo.LT #12 @電気通信大学
計算前後時間の差を取る(経過時間)
30. 並列版時刻同期実行結果 軽く
2015/10/25 30 /32
Dentoo.LT #12 @電気通信大学
[tanabe@tanabe sample]$ mpif90 sample3.f90 –o sample3
(コンパイル)
[tanabe@tanabe sample]$ mpirun –n 2 sample3
(2並列、「従業員数2名」で実行)
5000000000 2500000000 myid= 1
ELAPSE= 31.489058017730713 myid= 1
2500000000 2500000000 myid= 0
ELAPSE= 33.371865987777710 myid= 0
MPI_BARRIERをしなかった場合
2500000000 2500000000 myid= 0
ELAPSE= 19.314102172851563 myid= 0
5000000000 2500000000 myid= 1
ELAPSE= 28.772753953933716 myid= 1
同期がとれていて、
プロセス間で経過時間の違
いは(そんなに)ない。
同期がとれていないので、
プロセスごとに経過時間が
バラバラ。
31. 最後に
2015/10/25 31 /32
Dentoo.LT #12 @電気通信大学
• HPC、大規模計算のためには並列化、特にメ
モリ分散型計算機(クラスター)を使います。
• メモリ分散型計算機で並列計算を行うために
はMPIによる実装が(今のところ)必須です。
• MPIのサブルーチンの数は多いが、少数の基
礎的なもので入門可能です。
• この業界にいながら、職種の関係で
クラスター構築の経験がほぼないのが悩み。
32. 参考となりそうな文献など
2015/10/25 32 /32
Dentoo.LT #12 @電気通信大学
• スパコンプログラミング入門: 並列処理とMPIの学習
(片桐 孝洋 著、東京大学出版会)
※他にも、OpenMPなどに着目した著書などもあり
• 並列プログラミング虎の巻MPI版
(青山 幸也 著、高度情報科学技術研究機構)
※OpenMP、チューニングのテキストもあり
http://www.hpci-office.jp/pages/seminar_text
• MPICHサイト
https://www.mpich.org/
• OpenMPIサイト
http://www.open-mpi.org/ などなど
• サンプルプログラムは、Githubにあります
https://github.com/sittncs/hpcstudy/