(1)(2)並列計算の環境
• 並列計算:複数の計算ユニット(CPU, Core, PCなど)を使用して,
一つの問題(計算)を行わせる.
• 近年,並列計算を手軽に使用できる環境が急速に整いつつある。
>通常のPC ...CPU(Central Processing Unit)上に計算装置であるCoreが
複数含まれている。
Intel Core i7 シリーズ: 4つの計算装置(Core)
(3)通常のプログラム
(非並列)
• 通常のプログラミングは非並列
⇒一つの問題を一つの計算装置
(Core)で計算
計算
:
F =
A
i
i=1
400
∑
計算装置
(4 Cores)
Core 0
Core 1
Core 2
Core 3
時間
F =
A
i
i=1
400
∑
i=1〜400
の計算
何もしていない
(4)並列プログラム
• 一つの問題を一つの計算装置(Core)で計算
⇒
Core0 : i=1〜100, Core1: 101〜200, Core2: 201〜300, Core3: 301〜400
F
0
=
A
i
i=1
100
∑
Core 0
Core 1
Core 2
Core 3
F =
A
i
i=1
400
∑
i=1〜400
の計算
使用した
Core数
(並列数)に比例して
計算を高速化
F
1 =
A
i
i=101
200
∑
F
2 =
A
i
i=201
300
∑
F
3 =
A
i
i=301
400
∑
最後に
,
F = F
0
+ F
1
+ F
2
+ F
3
F
0
=
A
i
i=1
100
∑
F
1=
A
i
i=101
200
∑
F
2
=
A
i
i=201
300
∑
F
3
=
A
i
i=301
400
∑
非並列計算の時間
4Co
res
を
使用し
た
場合
F
3
F
2
F
1
データを転送
合算
F = F
0
+ F
1
+ F
2
+ F
3
データ転送など並列計算に伴う
,
計算以外の処理に時間が必要
⇒
並列数に比例することはない
。
(5)並列プログラムの実現方法
•
C言語,FORTRAN言語で並列計算を実現するライブラリを使用して拡張する.
ライブラリ・・・付加的な幾つかの関数等を予め用意したパッケージ
代表的な並列プログラミング環境
・
OpenMP ・・・・ 非並列プログラム中に幾つかの文を書き加えるのみ.
ネットワークで結合された並列計算は出来ない.
(1台のPC, コンピュータ上でのみOK)
・
MPI (Message Passing Interface)
・
PVM (Parallel Virtual Machine)
ネットワーク結合環境でも
OK
(6)ネットワーク結合環境・・・・計算機クラスター
, PCクラスター
• 複数の計算機
,PC(ノード)をネットワークでつなげる
TSUBAME2.0
CPU0
Xeon X5670
CPU1
12Cores
Node 0
Node 1 Node 2 Node 3 Node 4
1407
ノード
Infini Band(Gb EtherでもOK)
(7)MPI (Message Passing Interface)ライブラリ
• 並列計算に必要な関数の種類と仕様を規定したもの(設計書)
現在の最新仕様:
MPI 2.0
• 実際のライブラリは,ベンダーや各種団体にて実装されている.
• 無料のライブラリが幾つか開発されており,定評がある.
代表
Open MPI : hWp://www.open-mpi.org
MPICH : hWp://www.mpich.org
何れのライブラリを使用しても,関数は
MPI仕様書に従った形をしており,
MPIを使用したプログラムは何れのライブラリをインストールしているかに
関係無く実行可能となる.
(8)MPIで使用する代表的な関数
MPI計算の管理に関するもの
•
MPI_INIT
•
MPI_FINALIZE
•
MPI_COMM_SIZE
•
MPI_COMM_RANK
データの通信(受け渡し)に関するもの
•
MPI_SEND
•
MPI_RECV
基本的なプログラミングは6関数で実現可能!
(9)プログラミングの実際
• 基本スタンス:
SPMD (
S
ingle
P
rogram,
M
ulaple
D
ata)
同一のプログラムが異なる計算装置
(Core)上で複数実行される.
Core0 Core1 Core2 Core3
MPIで書かれた
プログラム
読込んで実行
A
A
A
A
REAL*8 A
INTEGER N
…..
それぞれが
”A”,”N”のデータを持つ.
Core0上のAは別の場所にあるので,Core1から直接参照することは出来ない
(MPI_RECV, MPI_SENDなどの通信関数を使用する)
通信で持ってくる
•
各プログラムは
”RANK”
と呼ばれる番号
(0,1,2,3,…)
が付けられ
、
他と区別される
。
(10)プログラム例
非並列
処理:
F=1/2+1/3+1/4 を行い,出力するプログラム
REAL*8 A, B, C
REAL*8 F
A=1.0/2.0
B=1.0/3.0
C=1.0/4.0
F=A+B+C
WRITE(*,*) F
END
(11)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
rank=0
rank=1
rank=2
A=1/2
B=1/3
C=1/4
A=1/2
B
C
F=A+B+C
WRITE F
C
を
転送
B
を
転送
B
C
A
B
C
C
A
A
B
A
B
C
A
B
C
(12)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
MPIの関数を使用する場合に必要なおまじない.
(
MPI_...関数の定義がmpif.hというファイルに書かれている)
(13)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
MPIの関数を使用する場合に必要なおまじない.
(他の
MPI_...関数を使用する前に,必ず書くこと)
書式
MPI_INIT( integer ierr)
ierr : Integer型の変数,
正しく実行されたのかを判定する値が
代入される.
(14)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
total_process=3
並列計算のプロセス
(rank)の総数を取得。
(プログラムの起動時に使用するプロセスを変更できる)
MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
MPI_COMM_WORLD : おまじない
INTEGER total_process : ランクの総数(例では”3”が代入)
INTEGER ierr : 正しく実行できたかのフラグ
(15)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
rank=0
rank=1 rank=2
total_process=3
プロセス自身の
rank数を取得。
(0〜total_process-1番まで個々のプロセスに番号がつく)
MPI_COMM_RANK(MPI_COMM_WORLD,
rank
, ierr)
MPI_COMM_WORLD : おまじない
INTEGER rank : 自身のランク数が代入される
INTEGER ierr : 正しく実行できたかのフラグ
(16)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
rank=0
rank=1
rank=2
A=1/2
B=1/3
C=1/4
B
C
A
B
C
C
A
A
B
A
B
C
A
B
C
自身のランク
(rank)数に応じて,動作を切り替える.
Rank=0: Aの計算
Rank=1: Bの計算
Rank=2: Cの計算
(17)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
rank=0
rank=1
rank=2
A=1/2
B=1/3
C=1/4
A=1/2
B
C
C
を
転送
B
を
転送
B
C
A
B
C
C
A
A
B
A
B
C
A
B
C
Cをrank=2からrank=0へ転送
Bをrank=1からrank=0へ転送
(18)IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
Bをrank=1からrank=0へ転送
rank=0
rank=1
B
B=1/3
MPIでのデータの転送の基本:
送信
(Send) & 受信(Recv) の組み合わせ
送信側
(rank=1)では,宛先(rank=0)と
通信を区別する
”タグ”を付けて相手に送る.
rank=0に向けて,
tag=10の通信
MPI_SEND( SentValue, SizeOfValue, MPI_DATA_TYPE, Dest, Tag, MPI_COMM_WORLD, ierr)
SentValue : 送信される変数 (“B”)
SizeOfValue : 送信する変数の大きさ( 今は”1”)
MPI_DATA_TYPE : 送信する変数の型 (MPI_DOUBLE_PRECISION, MPI_INTEGER,…)
Dest : 送信先のrank数
Tag : タグ(任意の整数)
MPI_COMM_WORLD : おまじない
ierr : エラー識別用
(19)IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
Bをrank=1からrank=0へ転送
rank=0
rank=1
B
B=1/3
MPIでのデータの転送の基本:
送信
(Send) & 受信(Recv) の組み合わせ
受信側
(rank=0)では,
送信元
(rank=1)と通信を区別する”タグ”によって受信するメッセージを選択.
rank=0に向けて,
tag=10の通信
MPI_RECV( RecvValue, SizeOfValue, MPI_DATA_TYPE, Dept, Tag, MPI_COMM_WORLD, istat, ierr)
RecvValue :
受信結果を格納する
変数
(“B”)
SizeOfValue : 格納する変数の大きさ( 今は”1”)
MPI_DATA_TYPE : 変数の型 (MPI_DOUBLE_PRECISION, MPI_INTEGER,…)
Dept : 送信元のrank数
Tag : タグ(任意の整数)
MPI_COMM_WORLD : おまじない
istat : 受信が完了したかなどの情報(おまじない)
ierr : エラー識別用
rank=1からの,
tag=10
のみ受信
(20)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
rank=0
rank=1
rank=2
A=1/2
B=1/3
C=1/4
A=1/2
B
C
F=A+B+C
WRITE F
C
を
転送
B
を
転送
B
C
A
B
C
C
A
A
B
A
B
C
A
B
C
rank=0のプロセスでのみ,
F=A+B+Cを計算して,出力する。
(21)MPIを用いた並列プログラム
INCLUDE ‘mpif.h’
INTEGER ierr
INTEGER istat
INTEGER rank
INTEGER total_process
REAL*8 A, B, C
REAL*8 F
CALL MPI_INIT(ierr)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, total_process, ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
IF(rank .eq. 0) A=1.0/2.0
IF(rank .eq. 1) B=1.0/3.0
IF(rank .eq. 2) C=1.0/4.0
IF(rank .eq. 1) THEN
CALL MPI_SEND( B, 1, MPI_DOUBLE_PRECISION, 0, 10, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( B, 1, MPI_DOUBLE_PRECISION, 1, 10, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 2) THEN
CALL MPI_SEND( C, 1, MPI_DOUBLE_PRECISION, 0, 20, MPI_COMM_WORLD, ierr)
ENDIF
IF(rank .eq. 0) THEN
CALL MPI_RECV( C, 1, MPI_DOUBLE_PRECISION, 2, 20, MPI_COMM_WORLD, istat, ierr)
ENDIF
IF(rank .eq. 0) THEN
F=A+B+C
WRITE(*,*) F
ENDIF
CALL MPI_FINALIZE(ierr)
END
rank=0
rank=1
rank=2
A=1/2
B=1/3
C=1/4
A=1/2
B
C
F=A+B+C
WRITE F
C
を
転送
B
を
転送
B
C
A
B
C
C
A
A
B
A
B
C
A
B
C
MPIを使用した場合には,必ず
MPI_FINALIZE(ierr)
を書くこと.
(22)MPIを使用したプログラムのコンパイル方法
•
gfortran や gcc に代えて,
> mpif90 -o run sample.f
> mpicc -o run sample.c
などの用に
, “mpif90” や “mpicc”を用いる。
(23)MPIを使用したプログラムの実行方法
MPIを使用したプログラムの実行は,以下のように行う.
> mpirun -np “総ランク数” “実行するプログラム”
例えば、
”run”というプログラムを,3個の総ランク数で実行する
場合には,
> mpirun -np 3 run
となる。
(24)プログラムの実行に要した時間の測定方法
プログラムの実行に費やした時間は,以下のように
”ame”コマンドで
計測できる。
> ame -p “プログラム”
結果は,
”real”, “user”, “sys” の3種類が出力されるが,“real” の値
が実際に経過した
”
秒数
”
である.
例えば、
”run”というプログラムを,3個の総ランク数で実行する場合
の経過秒を計測する場合には,
> ame -p mpirun -np 3 run
となる。
(25)TSUBAMEの利用方法
TSUBAMEへはネットワーク越しにログインして利用する.
“ターミナル”を起動して,
と打ち込む
(usernameは各自の教育システムへのログイン名)
パスワー認証ののち,
TSUBAMEへログイン完了となる。