JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

32
並並並並MPI 並並 Introduction to Message Passing Interface 23 October 2015 / 並並並 並, Sei-Ichi Tanabe-Tanabu ※ 本本本本本本本本本本本本本本本本本本本本 本本本本本本本本 本本本本本本本本本本本本本 一、。 @n_scattering . seiichi.tanabetanabu . JAWS-UG HPC 本本本本 #2 LT

Transcript of JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

Page 1: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

並列処理・ MPI の第一歩Introduction to

Message Passing Interface

23 October 2015 / 田名部 誠一 , Sei-Ichi Tanabe-Tanabu

※ 本資料内容および本自己紹介は所属組織の統一的見解ではなく、個人的見解によるものです。

@n_scattering      .

seiichi.tanabetanabu   .

    JAWS-UG HPC 専門支部 #2 LT

Page 2: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

2

自己紹介

田名部 誠一 ( たなべ / たなぶ せいいち )• 所属 :– ビジュアルテクノロジー株式会社

HPC 事業本部 テクニカル & サポート部• 役割 :– HPC に有用な (?) 技術の調査、プログラムの開発

社内情報システム管理、極端に広く浅く• 好きな AWS サービス :– Amazon EC2 ( というか、それしか使ったことがない )

• 参加 JAWS-UG:– 初心者  ・中央線  に、 JAWS Days 2015 以降

参加2015/10/23 /30

AWS Summit Tokyo 2015After party - JAWS DAYS にて

JAWS-UG HPC 専門支部 #2 LT

Page 3: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

3

趣味 (?) にしていること

頻度が高めな順に

• Ingress (#0 の自己紹介参照 )–運動療法として始めたが、歩き過ぎに注意

• 各種 IT 勉強会 (JAWS-UG なども含む )• 発達障害 ( 自閉症スペクトラム ) ・双極性障害の

当事者会への参加• 乗り鉄 ( なかなかできない )• 研究所・研究施設等の一般公開の見学

2015/10/23 /30JAWS-UG HPC 専門支部 #2 LT

Page 4: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

4

• 学部・大学院での研究 : – 理論系 物理学 ( 原子衝突 ) ・化学 ( 分子ダイナミクス )

→ 大規模計算…じゃなかった。

– Pentium !!!, Pentium4 計算機 1 台でできる小規模な計算

– 一応プログラム ( 主に Fortran, C など ) やシェルスクリプト (# シェル芸 , CLI) は理解できる

• 最初の職場、前職など :– 全くもって HPC とは無縁な職場だった (Ex. 回路設計、 PG)

• 研究室と師匠との縁で、今の職場に :– http://v-t.jp/jp/profile/shain-ta.php ( 行儀の良い社員紹介 )

2015/10/23 /30JAWS-UG HPC 専門支部 #2 LT

私と High-Performance Computing (HPC) との関わり

Page 5: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

5

なぜ HPC か、並列処理か?

• 並列計算の経験がない!これはまずい!• 計算機周辺の性能の向上

• CPU 、メモリ、ストレージ、ネットワーク…

• だけど、ユーザーの要求も高い!• そこで、並列計算! ( 計算機の共同作業! )–計算時間の短縮• N並列ならば、 1/Nの計算時間になるのが理想

だが、そうはいかないのが実情… (チューニングなどの工夫 )

–大容量のメモリを必要とする計算も可能• 1 台でできないけど、クラスタにすればできる

2015/10/23 /30JAWS-UG HPC 専門支部 #2 LT

Page 6: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

6

並列計算機について

• 並列ではない計算機 (昔の PC)• 共有メモリ型並列計算機 ( 最近の PC も )

• 1筐体にプロセッサ■ (コア ) が複数• 全プロセッサが 1つのメモリ■を共有• 並列化の手段 : MPI 、 OpenMP

• 分散メモリ型並列計算機 ( クラスタ構成 )• 筐体 ( ノード ) が複数。ネットワーク接続• 各筐体が独自にメモリ■を所有• 並列化の手段 : MPI• →ノード間で通信をすることで、

 全ノードのメモリが使えるようになる

2015/10/23 /30JAWS-UG HPC 専門支部 #2 LT

メモリー

Page 7: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

7

MPI とは?

• Message Passing Interface分散メモリ間のメッセージ通信の規格

• 実装としては MPICH 、 OpenMPI が有名https://www.mpich.org/http://www.open-mpi.org/

• プログラマが細かなチューニングを行える• 明示的に手続きを記述する必要がある

2015/10/23 /30JAWS-UG HPC 専門支部 #2 LT

Page 8: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

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/23 /30JAWS-UG HPC 専門支部 #2 LT

Page 9: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

9

A. MPI_INIT

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• MPI環境の初期化。• すべての MPI ルーチンの最初に 1 回だけ必ずコールする必要がある。

• CALL MPI_INIT(ierr)– ierr: 完了コードが戻る

Page 10: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

10

B. MPI_FINALIZE

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• MPI環境の終了処理。• すべての MPI ルーチンの最後に 1 回だけ必ずコールする必要がある。

• CALL MPI_FINALIZE(ierr)– ierr: 完了コードが戻る

Page 11: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

11

C. MPI_COMM_RANK

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• コミュニケーター comm で指定したグループ ( 職場 ) 内での自分 (=コールしたプロセス ) のランク (「名前・社員番号」 )を取得する。

• CALL MPI_COMM_RANK(comm,rank,ierr)– comm: コミュニケーター ( 職場 )を指定( ここでは MPI_COMM_WORLD 、全体を指定します )

– rank: comm で指定したグループ内での自分 (=コールしたプロセス ) のランク ( 名前・社員番号 )

– ierr: 完了コードが戻る

Page 12: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

12

D. MPI_COMM_SIZE

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• コミュニケーター comm で指定したグループ ( 職場 ) に含まれるプロセスの数を得る。

( プロセッサ数、並列数、「従業員数」 )• CALL MPI_COMM_SIZE(comm,procs,ierr)– comm: コミュニケーター ( 職場 )を指定( ここでは MPI_COMM_WORLD 、全体を指定します )

– procs: comm で指定したグループ内に含まれるプロセスの数 (「従業員数」 )

– ierr: 完了コードが戻る

Page 13: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

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/23 /32JAWS-UG HPC 専門支部 #2 LT

Page 14: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

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/23 /32JAWS-UG HPC 専門支部 #2 LT

このプログラムは、全プロセス( 全従業員 ) で起動される

A. MPI の初期化

C. 自プロセスの ID番号「社員番号」(myid)を取得します。

( 各プロセス・従業員で番号が異なります。 )

D. 全体のプロセッサ台数「従業員数」(numprocs)を取得します。

( 各プロセス・従業員で値は同じ )B. MPI の終了

Page 15: JAWS-UG HPC #2 LT 並列処理・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/23 /32JAWS-UG HPC 専門支部 #2 LT

C言語では、関数名 (MPI_Init など ) の大文字・小文字の使い方が異なります

C言語では、完了コード (ierr)を得る方法が異なります

Page 16: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

16

並列版 Hello 実行結果

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

[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 の値で結果が変わる。 )

Page 17: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

17

E. MPI_SEND

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• 1対 1ブロッキング通信サブルーチン (送信 )

• 送信メッセージを宛先プロセスに送信。–特定の従業員に「仕事を指示する」作業

• ただし、その人が聞いているとは限らない。→指示した従業員に案件番号を指定し指示を聞いてもらう作業が必要

• 送信したメッセージは MPI_RECV で受信する。

Myid=0

Myid=1

Myid=2

MPI_SEND!!

MPI_RECVで受信 !!

メッセージ

Page 18: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

18

E. MPI_SEND

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• CALL MPI_SEND(buf,count,datatype, dest,tag,comm,ierr)– buf: 送信バッファーの先頭アドレス (変数 )– count: 送信メッセージの要素数 (※バイト数ではない )

– datatype: 送信メッセージのデータ型– dest: 宛先プロセスの comm内のランク ( 名前・社員番号 )

– tag: 送信メッセージの種類を区別するタグメッセージの「案件番号」

– comm: コミュニケーター「職場」を指定(ここでは MPI_COMM_WORLD 、全体を指定します )

– ierr: 完了コードが戻る

Page 19: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

19

F. MPI_RECV

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• 1対 1ブロッキング通信サブルーチン (受信 )

• 送信元プロセスから送信されたメッセージを受信する。–特定の誰かから「仕事の依頼を受ける」作業

• ただし、その人への指示、受けるべき依頼とは限らない。→受けるべき特定の誰かからの指示、案件内容が必要

• MPI_SEND で送信したメッセージを受信する。

Myid=0

Myid=1

Myid=2

MPI_SENDで送信した !!MPI_RECVで受信 !!

メッセージ

Page 20: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

20

F. MPI_RECV

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• CALL MPI_RECV(buf,count,datatype, source,tag,comm,status,ierr)– buf: 受信バッファーの先頭アドレス (変数 )– count: 受信バッファーの要素数 (※バイト数ではない )

– datatype: 受信メッセージのデータ型– source: 送信するプロセスの comm 内のランク (名前・社員番

号 )

– tag: 送信メッセージの種類を区別するタグ「案件番号」

– comm: コミュニケーター「職場」を指定( ここでは MPI_COMM_WORLD 、全体を指定します )

– status: 受信状況に関する情報 (整数配列 )– ierr: 完了コードが戻る

Page 21: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

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/23 /32JAWS-UG HPC 専門支部 #2 LT

myid( ランク・社員番号 ) が 0 のプロセスの変数 isbuf の変数を代入

MPI_RECV の処理で必要な変数受信状況に関する情報 ( 整数配列 )

Page 22: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

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 end2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

Myid( ランク・社員番号 ) が 1 のプロセスの変数 irbuf の内容を確認する。Myid=0 のプロセス ( 従業員 ) から、Myid=1 のプロセス ( 従業員 ) にデータが送信されている!

0 から1に送信 !!

0 から来たメッセージを1が受信 !!

処理の決定「案件番号」は 1

Page 23: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

23

並列版送受信実行結果

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

[tanabe@tanabe sample]$ mpif90 sample2.f90 -o sample2(コンパイル )[tanabe@tanabe sample]$ mpirun -n 2 sample2(2 並列、従業員数 2 名で実行 )IRBUF = 19750617(従業員 Myid=1 に対して、従業員 Myid=0 から送信された整数値を受信できたことを確認する。 )

Myid=0

Myid=1

MPI_SENDで送信した !!

MPI_RECVで受信 !!

19750617 確認

Page 24: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

24

G. MPI_BARRIER

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• コミュニケーター comm「職場」内の全プロセス「全従業員」間で同期をとる関数–ある職場の共同作業で、全部の結果が揃わな

いと次の作業ができない場合に、最後まで待つ

• CALL MPI_BARRIER(comm, ierr)– comm:コミュニケーター「職場」を指定( ここでは MPI_COMM_WORLD 、全体を指定します )

– ierr: 完了コードが戻る

Page 25: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

25

H. MPI_WTIME

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• 時刻を得る関数。 (※ たぶん Unix 時間 )

• 経過時間の測定をしたい部分の前後で実行し、得られた値 elp の差を取ると、その部分の実行時間が得られる。

• elp = MPI_WTIME ()– elp: ある過去の時点からの経過時間 (秒 )

Page 26: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

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/23 /32JAWS-UG HPC 専門支部 #2 LT

計算で必要な変数時間計測で必要な変数

Page 27: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

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/23 /32JAWS-UG HPC 専門支部 #2 LT

( 作業 1) Myid( ランク ) の値に応じた回数だけ足し算を行う。( 従業員により、かかる時間が異なる )

( 作業 2) 決まった回数だけ足し算を行う。( 従業員間でかかる時間はあまり変わらない )

結果の確認

全プロセスの同期を取る( 全従業員の作業が終わるまで待つ )

時間の測定 ( 計算前 )

作業1

作業2

Page 28: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

28

時刻同期プログラムの説明 (3)( プログラム 3, Fortran)

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• MPI_BARRIER で同期

• 同期しない場合

Myid=0

Myid=1

Myid=2

MPI_BARRIER で全プロセスの同期を取る( 全従業員の作業が終わるまで待つ )

作業 1

作業 2経過時間

Myid=0

Myid=1

Myid=2

作業 2 を行うためには、作業 1 を終わらせなくてはいけない!そのために、同期が必要なはず。意図した動作が行われない!!

Page 29: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

29

(承前 )

elp2 = MPI_WTIME()

write(*,*) 'ELAPSE=', elp2-elp1, 'myid=',myid call MPI_FINALIZE(ierr)

stop end

時間の測定 ( 計算後 )

時刻同期プログラムの説明 (4)( プログラム 3, Fortran)

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

計算前後時間の差を取る ( 経過時間 )

Page 30: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

30

並列版時刻同期実行結果

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

[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

同期がとれていて、プロセス間で経過時間の違いは ( そんなに ) ない。

同期がとれていないので、プロセスごとに経過時間がバラバラ。

Page 31: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

31

最後に

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• HPC 、大規模計算のためには並列化、特にメモリ分散型計算機 ( クラスター )を使います。

• メモリ分散型計算機で並列計算を行うためには MPI による実装が ( 今のところ )必須です。

• MPI のサブルーチンの数は多いが、少数の基礎的なもので入門可能です。

• この業界にいながら、職種の関係でクラスター構築の経験がほぼないのが悩み。

Page 32: JAWS-UG HPC #2 LT 並列処理・MPIの第一歩

32

参考となりそうな文献など

2015/10/23 /32JAWS-UG HPC 専門支部 #2 LT

• スパコンプログラミング入門 : 並列処理と 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/