Dentoo.LT12 並列処理・MPIの第一歩 20151025

32
並並並並MPI 並並 Introduction to Message Passing Interface 25 October 2015 / 於 : 於於於於於於 並並並 並, Sei-Ichi Tanabe-Tanabu ※ 於於於於於於於於於於於於於於於於於於於於 於於於於於於於於 於於於於於於於於於於於於於 一、。 @n_scattering . seiichi.tanabetanabu . Dentoo.LT #12 Lightning Talk Google+ 於 於於於於於於於

Transcript of Dentoo.LT12 並列処理・MPIの第一歩 20151025

Page 1: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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

Message Passing Interface

25 October 2015 / 於 : 電気通信大学 田名部 誠一 , Sei-Ichi Tanabe-Tanabu

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

@n_scattering      .

seiichi.tanabetanabu   .

Dentoo.LT #12 Lightning Talk

Google+もやっております。

Page 2: Dentoo.LT12 並列処理・MPIの第一歩 20151025

2

こんにちは!

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

Page 3: Dentoo.LT12 並列処理・MPIの第一歩 20151025

3

自己紹介

田名部 誠一 ( たなべ / たなぶ せいいち )• 所属 :– とある柳橋の計算機屋の末端社員

• 役割 :– ハイパフォーマンスコンピューティング (HPC) に

有用な (?) 技術の調査、プログラムの開発、社内情報システム管理など、極端に広く浅く

• 電通大との関わり :– 1994 年は落ち、 1995 年に電子物性工学科 (F 科 ) に

入学修士課程まで、渡辺信一研究室にいました。

– 別の大学で D を取ったが、研究者になりそこねた。2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

Page 4: Dentoo.LT12 並列処理・MPIの第一歩 20151025

4

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

頻度が高めな順に

• Ingress ( 前回 #11 でお話ししました。 )– http://www.slideshare.net/seiichitanabetanabu/dentoolt11-20150510-lt

–運動療法として始めたが、歩き過ぎに注意• 各種 IT 勉強会• 発達障害 ( 自閉症スペクトラム ) ・双極性障害の

当事者会への参加• 乗り鉄 ( なかなかできない )• 研究所・研究施設等の一般公開の見学2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

Page 5: Dentoo.LT12 並列処理・MPIの第一歩 20151025

5

なぜ HPC か、並列処理か?

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

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

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

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

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

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

Page 6: Dentoo.LT12 並列処理・MPIの第一歩 20151025

6

並列計算機について

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

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

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

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

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

メモリ

Page 7: Dentoo.LT12 並列処理・MPIの第一歩 20151025

7

MPI とは?

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

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

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

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

Page 8: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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 /30Dentoo.LT #12 @ 電気通信大学

Page 9: Dentoo.LT12 並列処理・MPIの第一歩 20151025

9

A. MPI_INIT

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

• MPI環境の初期化。• すべての MPIルーチンの最初に 1 回だけ

必ずコールする必要がある。• CALL MPI_INIT(ierr)– ierr: 完了コードが戻る

Page 10: Dentoo.LT12 並列処理・MPIの第一歩 20151025

10

B. MPI_FINALIZE

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

• MPI環境の終了処理。• すべての MPIルーチンの最後に 1 回だけ

必ずコールする必要がある。• CALL MPI_FINALIZE(ierr)– ierr: 完了コードが戻る

Page 11: Dentoo.LT12 並列処理・MPIの第一歩 20151025

11

C. MPI_COMM_RANK

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

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

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

– ierr: 完了コードが戻る

Page 12: Dentoo.LT12 並列処理・MPIの第一歩 20151025

12

D. MPI_COMM_SIZE

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

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

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

– ierr: 完了コードが戻る

Page 13: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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 /32Dentoo.LT #12 @ 電気通信大学

Page 14: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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 /32Dentoo.LT #12 @ 電気通信大学

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

A. MPI の初期化

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

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

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

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

Page 15: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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 /32Dentoo.LT #12 @ 電気通信大学

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

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

Page 16: Dentoo.LT12 並列処理・MPIの第一歩 20151025

16

並列版 Hello 実行結果 軽く

2015/10/25 /32Dentoo.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 の値で結果が変わる。 )

Page 17: Dentoo.LT12 並列処理・MPIの第一歩 20151025

17

E. MPI_SEND

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

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

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

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

Myid=0

Myid=1

Myid=2

MPI_SEND!!

MPI_RECVで受信 !!

メッセージ

Page 18: Dentoo.LT12 並列処理・MPIの第一歩 20151025

18

E. MPI_SEND 軽く

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

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

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

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

– ierr: 完了コードが戻る

Page 19: Dentoo.LT12 並列処理・MPIの第一歩 20151025

19

F. MPI_RECV

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

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

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

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

Myid=0

Myid=1

Myid=2

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

メッセージ

Page 20: Dentoo.LT12 並列処理・MPIの第一歩 20151025

20

F. MPI_RECV 軽く

2015/10/25 /32Dentoo.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: 完了コードが戻る

Page 21: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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 /32Dentoo.LT #12 @ 電気通信大学

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

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

Page 22: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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/25 /32Dentoo.LT #12 @ 電気通信大学

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

0から1に送信 !!

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

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

Page 23: Dentoo.LT12 並列処理・MPIの第一歩 20151025

23

並列版送受信実行結果 軽く

2015/10/25 /32Dentoo.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 確認

Page 24: Dentoo.LT12 並列処理・MPIの第一歩 20151025

24

G. MPI_BARRIER

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

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

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

– ierr: 完了コードが戻る

Page 25: Dentoo.LT12 並列処理・MPIの第一歩 20151025

25

H. MPI_WTIME

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

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

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

Page 26: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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 /32Dentoo.LT #12 @ 電気通信大学

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

Page 27: Dentoo.LT12 並列処理・MPIの第一歩 20151025

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 /32Dentoo.LT #12 @ 電気通信大学

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

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

結果の確認

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

時間の測定 (計算前 )

作業1

作業2

Page 28: Dentoo.LT12 並列処理・MPIの第一歩 20151025

28

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

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

• MPI_BARRIER で同期

• 同期しない場合

Myid=0

Myid=1

Myid=2

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

作業 1

作業 2経過時間

Myid=0

Myid=1

Myid=2

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

Page 29: Dentoo.LT12 並列処理・MPIの第一歩 20151025

29

(承前 )

elp2 = MPI_WTIME()

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

stop end

時間の測定 (計算後 )

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

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

Page 30: Dentoo.LT12 並列処理・MPIの第一歩 20151025

30

並列版時刻同期実行結果 軽く

2015/10/25 /32Dentoo.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

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

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

Page 31: Dentoo.LT12 並列処理・MPIの第一歩 20151025

31

最後に

2015/10/25 /32Dentoo.LT #12 @ 電気通信大学

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

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

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

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

Page 32: Dentoo.LT12 並列処理・MPIの第一歩 20151025

32

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

2015/10/25 /32Dentoo.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/