並列プログラミング入門( 編) · magna carta 1215 (the british library, uk) ... 1.2...

205
並列プログラミング入門(MPI編) 高度情報科学技術研究機構 神戸センター 宮内 敦 0

Upload: others

Post on 25-Jun-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

並列プログラミング入門(MPI編)

高度情報科学技術研究機構 神戸センター 宮内 敦

0

Page 2: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

本日の講義内容

並列プログラミングの予備知識

MPIの基礎知識

MPIプログラミングの初歩

MPI関数各論

並列性能評価

具体的な問題への応用 1

Page 3: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

並列プログラミングの予備知識

1. ハードウェア観点からの分類

2. ソフトウェア観点からの分類

3. 通信方法からの分類

2

Page 4: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

プロセッサ/メモリの配置による分類

共有記憶型 (Shared Memory)

分散記憶型 (Distributed Memory)

・全プロセッサが一つのメモリを共有 ・プロセッサ間の通信は不要 ・メモリアクセスの排他制御が必要 ・プロセッサ数~100

・プロセッサ毎に独立したメモリ ・プロセッサ間の通信が必要 ・局所メモリ内は排他制御不要 ・プロセッサ数~10,000

memory

interconnect

core

CPU

core

CPU

core

CPU

core

CPU

me

mo

ry

interconnect

core

CPU

core

CPU

core

CPU

core

CPU

me

mo

ry

me

mo

ry

me

mo

ry

3

Page 5: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

マルチコアの場合

共有記憶型 (Shared Memory)

・CPU内のメモリコントローラを 相互通信網の一部と見做せば シングルコアの場合と同じ

分散共有記憶型 (Distributed Shared Memory)

≒ 8core共有 ≒ 2core共有×4socket分散

・分散と共有の両方の 特徴を併せ持つ

CPU

memory

interconnect

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

bus arbiter

me

mo

ry

interconnect

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

me

mo

ry

me

mo

ry

me

mo

ry

CPU

bus arbiter

4

Page 6: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

GPUの場合

・分散共有記憶型の各ノード内にさらに共有記憶型を内包

異種分散共有記憶型 (Heterogeneously Distributed Shared Memory)

≒ (2core共有+12GPU-core共有)×4socket分散

GPU

bus arbiter

CPU

interconnect

local

memory

co

re

co

re

me

mo

ry co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

local

memory

co

re

co

re

me

mo

ry co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

local

memory

co

re

co

re

me

mo

ry co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

local

memory

co

re

co

re

me

mo

ry co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

co

re

5

Page 7: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

アドレス空間による分類

単一アドレス空間 (Single Address Space)

・すべてのプロセッサが一つのアドレス空間を共有

・プロセッサ毎に独立したアドレス空間 ・プロセッサ/メモリは分散記憶型

分散アドレス空間 (Distributed Address Space)

UMA (Uniform Memory Access)

・プロセッサ/メモリは共有記憶型 ・空間内のどのアドレスにもアクセス時間は同じ

・プロセッサ/メモリは分散記憶型 ・一部のアドレスへのアクセスは速い ・その他のアドレスへのアクセスは遅い ・通信用キャッシュを持つ場合は ccNUMA (cache coherent NUMA)

NUMA (Non-Uniform Memory Access)

6

Page 8: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

プロセッサの機能による分類 SMP (Symmetric Multi-Processing)

• 特権的なプロセッサがない、全てのプロセッサが同じ機能を持つ

AMP (Asymmetric Multi-Processing)

• メインプロセッサとサブプロセッサに分かれている

例: 共有記憶型 SGI-Origin 分散記憶型 京、地球シミュレータ、Beowulf etc.

例: 共有記憶型 分散記憶型 メインフレーム

7

• 1つのOSが管理する資源を複数のプロセッサが使用する • プロセッサ毎にOSが存在し、個別に資源を管理する

OSとプロセッサの関係による分類 密結合 (Tightly Coupled System)

疎結合 (Loosely Coupled System)

Page 9: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

相互結合網 (Interconnect) による分類

8

相互結合網のバリエーションは多岐に亘る ここに挙げたのは代表的なものだけ*

*富田真治著「並列計算機構成論」昭晃堂(1986)に比較的まとまった記述がある

バス 同時にバスにアクセス できるのは1ノードだけ

n次元メッシュ 隣接ノード間のみの通信 平均ホップ数は√N程度

n次元トーラス 隣接ノード間のみの通信 平均ホップ数は√N程度

最大ホップ数はメッシュの半分

ファットツリー ツリー結合で上位が太い 平均ホップ数はlog2N程度

n次元ハイパーキューブ 各ノードがn個のノードと結合 平均ホップ数はlog2N程度

クロスバー スイッチで動的結合 1ホップでN対N通信

結線 ノード スイッチON スイッチOFF

Page 10: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Flynnの分類 (Flynn’s Taxonomy)

SIMD (Single Instruction, Multiple Data stream)

• 並列計算黎明期の分類法

• 計算機の動作を命令列とデータ列で抽象化・単純化

• 以下の4種類に分類

SISD (Single Instruction, Single Data stream)

MIMD (Multiple Instruction, Multiple Data stream)

MISD (Multiple Instruction, Single Data stream)

M. J. Flynn, Very High-Speed Computing Systems, Proceedings of IEEE , Vol. 54, 1901-1909, 1966

命令列とデータ列の単位をどう解釈するかで分類が変わる(例:VLIW) 最近ではプロセッサのSIMD命令以外は使われなくなった

9

Page 11: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

並列プログラミングの予備知識

1. ハードウェア観点からの分類

2. ソフトウェア観点からの分類

3. 通信方法からの分類

10

Page 12: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

プログラム実行方法からの分類 SPMD (Single Program Multiple Data stream)

• 全てのプロセス上で同一のプログラムを実行 • 使用するデータはプロセス毎に異なる • 一般にプロセス間通信の比率は高い (例外的にパラメータ並列の場合はプロセス間通信不要)

• プロセス毎に異なったプログラムを実行 • 使用するデータもプロセス毎に異なる • 一般にプロセス間通信の比率は低い (実際には純粋なMPMDは少なくSPMDとのハイブリッドが多い)

• 本来は共有記憶型のSIMDモデル (例: Thinking Machine CM2)

• 分散記憶型のSPMDもこれに分類される場合がある (例: 領域分割)

• プログラムを複数のタスクに分割し各プロセッサで並列処理 • MISD/MIMDモデルに近い概念 (例:master-worker/client-server )

MPMD (Multiple Program Multiple Data stream)

11

データ並列 (Data parallelism)

タスク並列 (Task parallelism)

Page 13: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

並列プログラミングの予備知識

1. ハードウェア観点からの分類

2. ソフトウェア観点からの分類

3. 通信方法からの分類

12

Page 14: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

メッセージ交換

PVM (Parallel Virtual Machine) ・最初期の規格、比較的単純な機能

・複合データ型や集団通信を提供する

MPI-1/2/3 (Message Passing Interface)

直接メモリアクセス

PGAS (Partitioned Global Address Space) ・分散記憶型に単一アドレスを提供する ・通常は言語に組込まれている (UPC, Chapel, Coarray etc.) ・ライブラリではOpenSHMEMがある(CrayT3Dのshmemのオープンソース版)

・片側通信として提供される ・単一アドレスは提供されない(ユーザプログラムで実現可能)

MPI-2/3 (Message Passing Interface)

送信側と受信側で通信呼び出し

送信側または受信側のみで通信呼び出し

13

Page 15: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

結局・・・

・計算機の分類には様々な評価軸がある

・それぞれの軸は直交しておらず重複部分が少なくない

・最近の並列計算機は多層的・複合的な構成を持つ

・システム全体を一意に分類することは難しい

・様々な概念を理解することが重要

14

Page 16: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPIの基礎知識

1. MPI規格 (MPI standard)

2. MPIライブラリ

15

Page 17: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

•プロセス並列を前提としたプロセス間のメッセージ交換に関する標準仕様

•適用対象は分散記憶アーキテクチャー上の分散アドレス空間におけるSPMDモデル

•ネットワーク接続された異機種クラスター環境にも対応

•先行したPVM(Parallel Virtual Machine)に不足し

ていた機能を採り入れている

•現在ではスレッド並列・直接メモリアクセス・

MPMDの機能も提供されている

MPI とは

16

Page 18: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

•MPI Forumが発行する規格書

•全ての基準となる最も重要な文献

•最新版はversion3.1、現在4.0へ向け改訂作業中 (4.0の関心はHybrid programming, Fault tolerance等)

http://mpi-forum.org/docs/mpi-3.1/mpi31-report.pdf

MPI Standard

*MPI Forum = 大学・研究機関・ベンダーから構成されるボランティアベースの協議会

Magna Carta 1215 (The British Library, UK)

=

17

Page 19: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

バージョンの変遷と特徴

1.0 May ‘94

1.1 Jun ‘95

1.2 Jul ‘97

1.3 May ‘08

2.0 Jul ‘97

2.1 Jun ‘08

2.2 Sep ‘09

3.0 Sep ‘12

3.1 Jun ‘15

Point to Point Communication

Datatypes

Collective Communication

Process Topology

One-Sided Communications

Parallel I/O

Process Creation

Nonblocking Collectives

Enhancement in One-Sided Comm.

Enhancement in Process Topology

Tool Information Interface

Distributed Graph Topology

Final version

Minor Changes Error Corrections

18

Page 20: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

規格の内容 (MPI standard 3.1)

・要素通信 (Point-to-Point Communication)

・データ型 (Datatypes)

・集団通信 (Collective Communication)

・コミュニケータ (Groups, Contexts, Communicators and Cashing )

・トポロジ (Process Topologies)

・環境管理 (MPI Environmental Management)

・情報オブジェクト (The Info Object)

・プロセス生成 (Process Creation and Management)

・片側通信 (One-Sided Communications)

・外部インターフェイス (External Interfaces)

・ファイル入出力 (I/O)

・ツール情報 (Tool Support)

19

Page 21: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

注意すべき用語 ・バッファ(buffer)

MPIでは3種類のバッファが使われる

送受信バッファ(send/recv buffer)はデータを格納した変数・配列

システムバッファ(system buffer)はユーザに不可視(opaque)だが

デッドロックに関係する場合があり要注意

添付バッファ(attached buffer)はユーザ自身で割当てる

要素通信のバッファモードにおいてのみ使われる

・復帰(return)と完了(completion)

復帰は後続する命令を実行可能な状態 (注:returnを値を返すという意味で用いる場合もある)

完了は全ての手順が終了し通信前に戻った状態

・閉塞/非閉塞(blocking/nonblocking)

閉塞通信は送受信バッファが解放されるまで復帰しない

非閉塞通信は即座に復帰し、後で完了したか確認する

(これを遅延同期(defer synchronization)という)

・非同期通信(asynchronous communication)

非閉塞通信とは違う概念、MPIでは使わない* *The term asynchronous communication is not used in MPI, pp. 279, Using MPI, 2nd ed., MIT Press, 1999

20

Page 22: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

参考図書等

・Using MPI Second Edition*, W. Gropp, E. Lusk and A. Skjellum, MIT press, 1999

・Using Advanced MPI W. Gropp, T. Hoefler, R. Thakur and E. Lusk, MIT press, 2014

・Parallel Programming in C with MPI and OpenMP M. J. Quinn, McGraw-Hill, 2008

・Parallel Programming with MPI P. Pacheco, Morgan Kaufmann, 1996

・Tutorials http://www.mcs.anl.gov/research/projects/mpi/tutorial/

* Using MPI Third Edition (https://mitpress.mit.edu/using-MPI-3ed) **query words = MPI, parallel computing, high performance computing, message passing, etc.

21

Page 23: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPIの基礎知識

1. MPI規格(MPI Standard)

2. MPIライブラリ

22

Page 24: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

特徴 ・MPI Standardに準拠して開発される ・プロセス並列モデル ・プロセス間通信でメッセージ交換 ・オープンソフトから商用ソフトまで多数 ・ライブラリにより性能の違いやバグ

代表的ライブラリ ・OpenMPI FT, LA, LAM joint team ☆現在の最大勢力 ・MPICH* Argonne National Lab. ☆根強い人気 ・MVAPICH Ohio State Univ. ☆GPUに強み ・LAM/MPI Indiana Univ. ★かつてクラスタ向けに人気 ・CHIMP Edinburgh Center ★初期のライブラリ ・Cray-MPI, IBM-MPI, Intel-MPI, Fujitsu-MPI etc.

*MPICH is pronounced “Em Pee Eye See Aych,” not “Emm Pitch.”, pp. 329, Using MPI, 2nd ed., MIT Press, 1999

23

Page 25: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

実装状況(2016年6月)

Implementation Status(MPI3.1), as of June 2016 (http://mpi-forum.org/) c.f. NBC = NonBlocking Collective, RMA = Remote Memory Access, F08 = Fortran2008

24

Page 26: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPIプログラミングの初歩

1. Hello Wooooorld!

2. プロセス間通信の使用例

25

Page 27: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Hello World!

1 #include <stdio.h> 2 #include “mpi.h” 3 4 int main( int argc, char *argv[] ) 5 { 6 int size, rank; 7 MPI_Init( &argc, &argv ); 8 MPI_Comm_size( MPI_COMM_WORLD, &size ); 9 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 10 printf( “Hello World! I am %d of %d.¥n”, rank, size ); 11 MPI_Finalize(); 12 return 0; 13 } >mpicc –o hello hello.c >mpiexec –n 2 ./hello Hello World! I am 0 of 2. Hello World! I am 1 of 2. >

hello.c

関数や定数の定義

引数は省略可能

mpirun –np 2 ./hello でも可

26

Page 28: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

使用した関数・既定名・コマンド

関数 int MPI_Init(int argc, char ***argv) int MPI_Finalize(void) int MPI_Comm_size(MPI_Comm comm, int *size) int MPI_Comm_rank(MPI_Comm comm, int *rank)

既定名 MPI_COMM_WORLD 全プロセスを含む空間

コマンド mpicc MPI用のCコンパイラ・リンカ

mpiexec MPIプログラム実行コマンド

注: 引数の色は in,out,inout を示す (inは呼び出し前に設定、outは復帰後に値が返される)

27

Page 29: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Hello Worlds!

1 #include <stdio.h> 2 #include “mpi.h” 3 4 int main( int argc, char *argv[] ) 5 { 6 int size, rank; 7 MPI_Init( &argc, &argv ); 8 MPI_Comm_size( MPI_COMM_WORLD, &size ); 9 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 10 printf( “Hello World A! I am %d of %d¥n”, rank, size ); 11 MPI_Finalize(); 12 return 0; 13 } >mpicc –o helloA helloa.c >mpicc –o helloB hellob.c >mpiexec –n 2 ./helloa : -n 3 ./hellob Hello World A! I am 0 of 5 Hello World A! I am 1 of 5 Hello World B! I am 2 of 5 Hello World B! I am 3 of 5 Hello World B! I am 4 of 5 >

helloa.c

B in hellob.c

mpirun は原則不可

一つのMPI_COMM_WORLDの中に 全プログラムの全プロセスが入る

28

Page 30: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Hello lotta Worlds!

1 # comment 2 -n 2 ./helloa : -n 3 ./hellob 3 -n 1 ./helloc >mpicc –o helloA helloa.c >mpicc –o helloB hellob.c >mpicc –o helloC helloc.c >mpiexec –configfile myconf Hello World A! I am 0 of 6 Hello World A! I am 1 of 6 Hello World B! I am 2 of 6 Hello World B! I am 3 of 6 Hello World B! I am 4 of 6 Hello World C! I am 5 of 6 >

myconf

・構成ファイル(configuration file)を使って実行することもできる*

mpirun は原則不可

改行コードはOSによって異なる 異機種上での実行は要注意

’¥’で継続行にすることも可能

*未実装のライブラリも多い(OpenMPI etc.)

29

Page 31: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPIプログラミングの初歩

1. Hello Wooooorld!

2. プロセス間通信の使用例

30

Page 32: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

数値積分

・台形近似: 関数 の積分を離散点 での値

を用いて と近似する

2

1 + 𝑥2

1

−1

𝑑𝑥 = 𝜋 ・例題: を数値的に求める

𝑓 𝑥 𝑑𝑥 ≅ 1

2𝑓𝑖+1 + 𝑓𝑖 𝑥𝑖+1 − 𝑥𝑖

𝑖

𝑓(𝑥) 𝑓𝑖 𝑥𝑖

𝑥𝑖 𝑥𝑖+1

𝑓𝑖+1

𝑓𝑖

31

Page 33: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

1 #include <stdio.h> 2 #include “mpi.h” 3 4 int main( int argc, char *argv[] ) 5 { 6 int size, rank, n, err; 7 MPI_Init( &argc, &argv ); 8 MPI_Comm_size( MPI_COMM_WORLD, &size ); 9 MPI_Comm_rank( MPI_COMM_WORLD, &rank ); 10 11 if( rank==0 ) 12 { 13 printf( “Enter the number of intervals¥n” ); 14 err = scanf( “%d”, &n ); 15 } 16 MPI_Bcast( &n, 1, MPI_INT, 0, MPI_COMM_WORLD ); 17 const double h = 2.0/n; 18 19 double sum = 0.0, pi = 0.0; 20 for( int i=rank; i<n; i+=size ) 21 { 22 const double x0 = i *h – 1.0; 23 const double x1 = (i+1)*h – 1.0; 24 const double f0 = 2.0 / ( 1.0 + x0*x0 ); 25 const double f1 = 2.0 / ( 1.0 + x1*x1 ); 26 sum += 0.5*( f0 + f1 )*( x1 – x0 ); 27 } 28 MPI_Reduce( &sum, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD ); 29 30 if( rank==0 ) 31 printf( “pi is approximately %.16f¥n”, pi ); 32 33 MPI_Finalize(); 34 Return 0; 35 }

trapezoid.c

台形近似

blocking 集団通信

32

Page 34: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

>mpicc –o trapeziod trapezoid.c >time mpiexec –n 2 ./trapezoid Enter the number of intervals 10000 pi is approximately 3.1415926469231268 real 0m4.861s user 0m3.804s sys 0m0.044s >

intervals pi -n real 100 3.1415259869232535 2 0m4.036s 1000 3.1415919869231264 4 0m6.651s 10000 3.1415926469231268 8 0m7.685s 100000 3.1415926535231264 16 0m7.333s 1000000 3.1415926535891265 32 0m5.577s ...

実行例

33

Page 35: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Bcast と MPI_Reduce の動作

MPI_COMM_WORLD

P0

P3 P1

P2

n

n n

n

MPI_Bcast( &n, 1, MPI_INT, 0, … );

ポインタ&nから始まる1つの整数を プロセス0からその他のプロセスに送る

MPI_Reduce( &n, &m, 1, MPI_INT, MPI_SUM, 0, … );

ポインタ&nから始まる1つの整数を プロセス0以外からプロセス0に送り

総和を計算し&mに格納する

MPI_COMM_WORLD

P0

P3 P1

P2

m=Σn

n n

n

n

34

Page 36: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

使用した関数等

関数 int MPI_Bcast(void* buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) int MPI_Reduce(const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)

データ型・演算 MPI_INT 整数型

MPI_DOUBLE 倍精度実数型

MPI_SUM 加算

35

Page 37: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

命名規則(Naming conventions)他

全ての名前は接頭辞 MPI_ で始まる 定数・型・状態・演算等は全て大文字

例: MPI_COMM_WORLD, MPI_INT,

MPI_SUCCESS, MPI_SUM, etc. 関数は最初の一文字のみ大文字、残りは全て小文字

例: MPI_Comm_rank(), MPI_Init(),

MPI_Send(), MPI_Bcast(), etc. 通信が成功した時の戻り値は MPI_SUCCESS

if(MPI_Xxx())は期待通りに動作しない場合あり

失敗したときの値も実装依存 36

Page 38: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

37

Page 39: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

集団通信とは

コミュニケータ内の多プロセス間で一斉に行う通信 一般に要素通信を用いて実装される

注意点

コミュニケータ内の全プロセスで関数呼出しが必要

実際に全てのプロセスが送受信するとは限らない

引数の値は基本的に全てのプロセスで同じ

root, comm は全てのプロセスで同じ値を指定する

送受信バッファはプロセス毎に異なっても良い

関数名にvの付くものはプロセス毎にデータ数が異なる (bcast/scatter/scatterv/gather/gatherv/reduceで 使用されないバッファには MPI_BOTTOM を指定できる)

38

Page 40: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

集団通信関数一覧

MPI_Bcast

MPI_Scatter

MPI_Scatterv

MPI_Gather

MPI_Gatherv

MPI_Reduce

MPI_Scan

MPI_Exscan

MPI_Allgather

MPI_Allgatherv

MPI_Alltoall

MPI_Alltoallv

MPI_Alltoallw

MPI_Allreduce

MPI_Reduce_scatter_block

MPI_Reduce_scatter

MPI_Barrier

MPI_Ibcast

MPI_Iscatter

MPI_Iscatterv

MPI_Igather

MPI_Igatherv

MPI_Ireduce

MPI_Iscan

MPI_Iexscan

MPI_Iallgather

MPI_Iallgatherv

MPI_Ialltoall

MPI_Ialltoallv

MPI_Ialltoallw

MPI_Iallreduce

MPI_Ireduce_scatter_block

MPI_Ireduce_scatter

MPI_Ibarrier

Blocking Nonblocking

One to All

All to One

All to All

Some to All

✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔

Intercomm MPI_IN_PLACE

39

Page 41: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Bcast

int MPI_Bcast( void* buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm )

int buf[2];

MPI_Bcast(buf, 2, MPI_INT, 1, MPI_COMM_WORLD);

Bcast

MPI_COMM_WORLD

P0

P1

P2

P3

buf

0 1

buf

0 1

buf

0 1

buf

0 1

MPI_COMM_WORLD

P0

P1

P2

P3

buf

0 1

buf

0 1

buf

0 1

buf

0 1

Function prototype

Example (bcast.c)

• root の持つデータを全プロセスにコピーする

40

Page 42: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Scatter

int MPI_Scatter( const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm )

int sbuf[8], rbuf[2];

MPI_Scatter(sbuf, 2, MPI_INT, rbuf, 2, MPI_INT, 1, MPI_COMM_WORLD);

Scatter

MPI_COMM_WORLD

sbuf

0 1 2 3 4 5 6 7

P0

P1

P2

P3

sbuf

0 1 2 3 4 5 6 7

sbuf

0 1 2 3 4 5 6 7

sbuf

0 1 2 3 4 5 6 7

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1

rbuf

0 1

rbuf

0 1

rbuf

0 1

Function prototype

Example (scatter.c)

• root の持つデータを全プロセスに分配する

41

Page 43: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Scatterv

int MPI_Scatterv( const void* sendbuf, const int sendcounts[], const int displs[], MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm )

int sbuf[11], rbuf[3];

int scounts[4]={1,2,3,2}, displs[4]={0,2,5,9}; MPI_Scatterv(sbuf, scounts, displs, MPI_INT,

rbuf, 3, MPI_INT, 1, MPI_COMM_WORLD);

Scatterv

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1 2 3 4 5 6 7 8 9 10

sbuf

0 1 2 3 4 5 6 7 8 9 10

sbuf

0 1 2 3 4 5 6 7 8 9 10

sbuf

0 1 2 3 4 5 6 7 8 9 10

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1 2

rbuf

0 1 2

rbuf

0 1 2

rbuf

0 1 2

Function prototype

Example (scatterv.c)

42

Page 44: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Scatter/MPI_Scatterv の注意点

MPI_Scatterv は MPI_Scatter をデータ長可変にしたもの

送信側パラメータ (sendbuf, sendcount, sendcounts[], displs[], sendtype)

• root の値のみ有効、それ以外の値は無視される

受信側パラメータ (recvbuf, recvcount, recvtype)

• recvcount は受信するデータ長以上であれば良い

• recvcount が受信するデータ長未満の場合はエラー

• Scatterv の recvcount は本来プロセス毎に異なる

通常は sendcounts[rank] とする(3でも正常動作)

• recvbuf の配列長は recvcount 以上必要

• recvbuf の不要な配列要素は無視される

• recvtype と sendtype は異なっても良いが

受信データ長が送信より少ないとエラー

分割されたデータの送信先はプロセス番号順

43

Page 45: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Gather

int MPI_Gather( const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm )

int sbuf[2], rbuf[8];

MPI_Gather(sbuf, 2, MPI_INT, rbuf, 2, MPI_INT, 1, MPI_COMM_WORLD);

Gather

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1

sbuf

0 1

sbuf

0 1

sbuf

0 1

MPI_COMM_WORLD

rbuf

0 1 2 3 4 5 6 7

P0

P1

P2

P3

rbuf

0 1 2 3 4 5 6 7

rbuf

0 1 2 3 4 5 6 7

rbuf

0 1 2 3 4 5 6 7

Function prototype

Example (gather.c)

• 全プロセスのデータを root に収集する

44

Page 46: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Gatherv

int MPI_Gatherv( const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, int root, MPI_Comm comm )

int sbuf[3], rbuf[11];

int rcounts[4]={1,2,3,2}, displs[4]={0,2,5,9}; MPI_Gatherv(sbuf, 3, MPI_INT,

rbuf, rcounts, displs, MPI_INT, 1, MPI_COMM_WORLD);

Gatherv

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1 2 3 4 5 6 7 8 9 10

rbuf

0 1 2 3 4 5 6 7 8 9 10

rbuf

0 1 2 3 4 5 6 7 8 9 10

rbuf

0 1 2 3 4 5 6 7 8 9 10

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1 2

sbuf

0 1 2

sbuf

0 1 2

sbuf

0 1 2

Function prototype

Example (gatherv.c)

45

Page 47: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Gather/MPI_Gathervの注意点

MPI_Gatherv は MPI_Gather をデータ長可変にしたもの

送信側パラメータ(sendbuf, sendcount, sendtype)

• Gatherv の sendcount はプロセス毎に異なる

通常は recvcounts[rank] とする

受信側パラメータ (recvbuf, recvcount, recvcounts[], displs[], recvtype)

• root の値のみ有効、それ以外の値は無視される

• recvcount, recvcounts[] は受信するデータ長以上であれば良い

• recvcount, recvcounts[] が受信するデータ長未満の場合はエラー

• recvcounts[] の各要素の値は本来異なる gatherv.cの場合 recvcounts[]={1,2,3,2}でも{3,3,3,3}でも正常に動作

• recvbuf の配列長は (recvcount or recvcounts[])*nproc以上必要

• recvbuf の不要な配列要素は無視される

• recvtype と sendtype は異なっても良いが

受信データのバイト数が不足するとエラー

受信データの開始位置はプロセス番号順

46

Page 48: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Reduce

int MPI_Reduce( const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm )

int sbuf[2], rbuf[2];

MPI_Reduce(sbuf, rbuf, 2, MPI_INT, MPI_SUM, 1, MPI_COMM_WORLD);

Reduce

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1

2 5

sbuf

0 1

0 7

sbuf

0 1

6 3

sbuf

0 1

4 1

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1

rbuf

0 1

12 16

rbuf

0 1

rbuf

0 1

12=2+0+6+4

16=5+7+3+1

Function prototype

Example (reduce.c)

• 全プロセスのデータを root に収集して総和

47

Page 49: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Scan

int MPI_Scan( const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm )

int sbuf[2], rbuf[2];

MPI_Scan(sbuf, rbuf, 2, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

• 自分を含め自分より番号の若いプロセス上の値の総和

Scan

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1

2 5

sbuf

0 1

0 7

sbuf

0 1

6 3

sbuf

0 1

4 1

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1

2 5

rbuf

0 1

2 12

rbuf

0 1

8 15

rbuf

0 1

12 16

2=2+0

12=5+7

8=2+0+6

15=5+7+3

12=2+0+6+4

16=5+7+3+1

2=2

5=5

Function prototype

Example (scan.c)

48

Page 50: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Exscan

int MPI_Exscan( const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm )

int sbuf[2], rbuf[2];

MPI_Exscan(sbuf, rbuf, 2, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

• 自分を除く自分より番号の若いプロセス上の値の総和

Exscan

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1

2 5

sbuf

0 1

0 7

sbuf

0 1

6 3

sbuf

0 1

4 1

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1

-- --

rbuf

0 1

2 5

rbuf

0 1

2 12

rbuf

0 1

8 15

2=2

5=5

2=2+0

12=5+7

8=2+0+6

15=5+7+3

--=--

--=--

Function prototype

Example (exscan.c)

49

Page 51: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Reduce/MPI_Scan/MPI_Exscanの注意点

受信バッファ(recvbuf) の値

• MPI_Reduce では root のみ値を代入

• MPI_Scan では全プロセスで値を代入

• MPI_Exscan ではプロセス0以外で値を代入

50

Page 52: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int in, out; in = 10; // local array size out = 0; MPI_Exscan( &in, &out, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD ); printf(“rank %d begins from %d¥n”, rank, out);

MPI_Scan/MPI_Exscanの代表的な使い方

大域配列のオフセット値を求める

Process0 Process1 Process2 Process3

0 9 0 9 0 9 0 9

0 9 10 19 20 29 30 39

分散配列

大域配列

>mpiexec –n 4 ./a.out rank 0 begins from 0 rank 1 begins from 10 rank 2 begins from 20 rank 3 begins from 30 >

51

Page 53: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_MAX

MPI_MIN

MPI_MAXLOC

MPI_MINLOC

MPI_SUM

MPI_PROD

MPI_LAND

MPI_LOR

MPI_LXOR

MPI_BAND

MPI_BOR

MPI_BXOR

定義済みの主なデータ型と演算

Integer: MPI_INT, MPI_LONG, MPI_UNSIGNED, etc.

Floating point: MPI_FLOAT, MPI_DOUBLE, etc.

Complex: MPI_C_COMPLEX, MPI_C_DOUBLE_COMPLEX, etc.

Logical: MPI_C_BOOL, etc.

Byte: MPI_BYTE

Integer Floating Complex Logical Byte

✔ ✔ ✔

✔ ✔

✔ ✔

✔ ✔

最大値

最小値

最大値と指標

最小値と指標

総和

総積

論理積

論理和

論理排他和

ビット積

ビット和

ビット排他和

52

Page 54: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

struct{ float value; int index; } in[2], out[2]; in[0].value = ...; in[0].index = ...; in[1].value = ...; in[1].index = ...; MPI_Reduce( in, out, 2, MPI_FLOAT_INT, ¥ MPI_MAXLOC, 1, MPI_COMM_WORLD );

MPI_MAXLOC/MPI_MINLOCの使い方

in[0].value in[0].index in[1].value in[1].index Process0 1.2 3 4.2 9 Process1 3.5 4 1.3 2 Process2 2.3 1 8.4 7 Process3 4.8 0 5.7 3 out[0].value out[0].index out[1].value out[1].index Process1 4.8 0 8.4 7

プロセス1には以下の値が格納される

最大の実数値とその指標を探す

• 指標は必ず整数 • valueが整数の場合はMPI_2INT型(MPI_INT_INTではない)

Example (maxloc.c)

53

Page 55: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

ユーザ定義演算

typedef struct{ float vx, vy; } fvec2;

void addvec(void *invec, void* iovec, int *len, MPI_Datatype *dptr) { fvec2 *a = (fvec2 *)invec; // in vector fvec2 *b = (fvec2 *)iovec; // inout vector for(int i=0; i<*len; ++i) { b->vx += a->vx; b->vy += a->vy; ++a; ++b; } }

MPI_Datatype vtype; MPI_Type_contiguous(2, MPI_FLOAT, &vtype); MPI_Type_commit(&vtype);

MPI_Op myOp; MPI_Op_create(addvec, 1, &myOp);

fvec2 in[4], sum[4]; MPI_Reduce(in, sum, 4, vtype, myOp, 1, MPI_COMM_WORLD);

MPI_Op_free(&myOp);

2次元ベクトル合成

戻り値なし

可換演算は true (実装依存)を指定

fvec2をMPI_Datatypeに変換

演算本体(結果を iovec 側に格納する)

Example (reduceop.c)

dptrは省略不可

この例では4が代入される

54

Page 56: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Allgather

int MPI_Allgather( const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm )

int sbuf[2], rbuf[8];

MPI_Allgather(sbuf, 2, MPI_INT, rbuf, 2, MPI_INT, MPI_COMM_WORLD);

Allgather

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1

sbuf

0 1

sbuf

0 1

sbuf

0 1

MPI_COMM_WORLD

rbuf

0 1 2 3 4 5 6 7

P0

P1

P2

P3

rbuf

0 1 2 3 4 5 6 7

rbuf

0 1 2 3 4 5 6 7

rbuf

0 1 2 3 4 5 6 7

Function prototype

Example (allgather.c)

• 引数はGatherとほぼ同じ(rootが無い)、動作はGather+Bcast

55

Page 57: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Allgatherv

int MPI_Allgatherv( const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, MPI_Comm comm )

int sbuf[3], rbuf[11];

int rcounts[4]={1,2,3,2}, displs[4]={0,2,5,9}; MPI_Allgatherv(sbuf, 3, MPI_INT,

rbuf, rcounts, displs, MPI_INT, MPI_COMM_WORLD); 注:rcounts, displsはrootの値だけ有効、sendcountの値はプロセス毎に異なる(この例ではプロセス2)

・引数はGathervとほぼ同じ(rootが無い)、動作はGatherv+Bcast

Allgatherv

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1 2 3 4 5 6 7 8 9 10

rbuf

0 1 2 3 4 5 6 7 8 9 10

rbuf

0 1 2 3 4 5 6 7 8 9 10

rbuf

0 1 2 3 4 5 6 7 8 9 10

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1 2

sbuf

0 1 2

sbuf

0 1 2

sbuf

0 1 2

Function prototype

Example (allgatherv.c)

56

Page 58: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Allreduce

int MPI_Allreduce( const void* sendbuf, void* recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm )

int sbuf[2], rbuf[2];

MPI_Allreduce(sbuf, rbuf, 2, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

• 引数はReduceとほぼ同じ(rootが無い)

• 動作はReduce+Bcast

Allreduce

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1

2 5

sbuf

0 1

0 7

sbuf

0 1

6 3

sbuf

0 1

4 1

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1

12 16

rbuf

0 1

12 16

rbuf

0 1

12 16

rbuf

0 1

12 16

12=2+0+6+4

16=5+7+3+1

12=2+0+6+4

16=5+7+3+1

12=2+0+6+4

16=5+7+3+1

12=2+0+6+4

16=5+7+3+1

Function prototype

Example (allreduce.c)

57

Page 59: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Reduce_scatter_block

int MPI_Reduce_scatter_block( const void* sendbuf, void* recvbuf, int recvcount, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm )

int sbuf[8], rbuf[2];

MPI_Scatter_block(sbuf, rbuf, 2, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

• 引数はReduceとほぼ同じ(rootが無い)

• 動作はReduce+Scatter(sumにReduceしてScatter)

Reduce _scatter

_block

MPI_COMM_WORLD

sbuf 0 4 2 5 1 6 3 7

0 1 2 3 4 5 6 7

P0

P1

P2

P3

sbuf 2 3 0 1 4 6 5 7

0 1 2 3 4 5 6 7

sbuf 5 7 6 2 3 0 1 4

0 1 2 3 4 5 6 7

sbuf 7 0 1 4 5 3 6 2

0 1 2 3 4 5 6 7

MPI_COMM_WORLD

P0

P1

P2

P3

rbuf

0 1

14 15

rbuf

0 1

12 14

rbuf

0 1

20 9

rbuf

0 1

13 15

sum

14 15 12 14 20 9 13 15

14=2+0+5+7

15=5+3+1+6

12=1+5+2+4

14=3+4+7+0

20=7+7+4+2

9=0+2+6+1

13=4+1+3+5

15=6+6+0+3

Function prototype

Example (reducescatterblock.c)

58

Page 60: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Reduce_scatter

int MPI_Reduce_scatter( const void* sendbuf, void* recvbuf, const int recvcounts[], MPI_Datatype datatype, MPI_Op op, MPI_Comm comm )

int sbuf[8], rbuf[3];

int rcounts[4]={1,2,3,2}; MPI_Scatter(sbuf, rbuf, rcounts, MPI_INT, MPI_SUM, MPI_COMM_WORLD);

• Reduceとほぼ同じ(引数にrootが無い、recvcountが配列)

• 動作はReduce+Scatterv(sumにReduceしてScatterv)

Reduce _scatter

MPI_COMM_WORLD

sbuf 0 4 2 5 1 6 3 7

0 1 2 3 4 5 6 7

P0

P1

P2

P3

sbuf 2 3 0 1 4 6 5 7

0 1 2 3 4 5 6 7

sbuf 5 7 6 2 3 0 1 4

0 1 2 3 4 5 6 7

sbuf 7 0 1 4 5 3 6 2

0 1 2 3 4 5 6 7

sum

14 15 12 14 20 9 13 15

14=2+0+5+7

15=5+3+1+6

12=1+5+2+4

14=3+4+7+0

20=7+7+4+2

9=0+2+6+1

13=4+1+3+5

15=6+6+0+3

MPI_COMM_WORLD

P0

P1

P2

P3

sbuf

0 1 2

14

sbuf

0 1 2

15 12

9 sbuf

0 1 2

14 20

sbuf

0 1 2

13 15

Function prototype

Example (reducescatter.c)

59

Page 61: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Alltoall

int MPI_Alltoall( const void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm )

int sbuf[8], rbuf[8];

MPI_Alltoall(sbuf, 2, MPI_INT, rbuf, 2, MPI_INT, MPI_COMM_WORLD);

• 引数はGatherとほぼ同じ(rootが無い)

• 動作はプロセス毎にsbufの開始位置を変えてGather, またはプロセス毎にrbufの開始位置を変えてScatter

• sbuf, rbufに十分な大きさがあればsendcount!=recvcountも可能(intercommの場合など)

Alltoall

MPI_COMM_WORLD

sbuf

0 1 2 3 4 5 6 7

sbuf

0 1 2 3 4 5 6 7

sbuf

0 1 2 3 4 5 6 7

sbuf

0 1 2 3 4 5 6 7

P0

P1

P2

P3

MPI_COMM_WORLD

rbuf

0 1 2 3 4 5 6 7

rbuf

0 1 2 3 4 5 6 7

rbuf

0 1 2 3 4 5 6 7

rbuf

0 1 2 3 4 5 6 7

P0

P1

P2

P3

Function prototype

Example (alltoall.c)

60

Page 62: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Alltoallv

int MPI_Alltoallv( const void* sendbuf, const int sendcounts[], const int sdispls[], MPI_Datatype sendtype, void* recvbuf, const int recvcounts[], const int rdispls[], MPI_Datatype recvtype, MPI_Comm comm )

scounts rcounts Process0 { a0, a1, a2, a3 } { a0, b0, c0, d0 } Process1 { b0, b1, b2, b3 } { a1, b1, c1, d1 } Process2 { c0, c1, c2, c3 } { a2, b2, c2, d2 } Process3 { d0, d1, d2, d3 } { a3, b3, c3, d3 }

• scounts, rcountsの値は互いに転置関係

scounts, sdispls, rcounts, rdisplsの値は整合的でなければならない

• sendbuf, recvbufには十分な大きさが必要

int sendbuf[ssize]; // ssize > sdispls[0]+sdispls[1]+...

int recvbuf[rsize]; // rsize > rdispls[0]+rdispls[1]+...

• 引数はAlltoallとほぼ同じ(sendcount, recvcountが配列)

• 動作は各プロセスがsbufとrbufの開始位置を変えてGather

Function prototype

61

Page 63: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[13], rbuf[13];

int scounts[4], sdispls[4], rcounts[4], rdispls[4]; MPI_Alltoallv(sbuf, scounts, sdispls, MPI_INT,

rbuf, rcounts, rdispls, MPI_INT, 1, MPI_COMM_WORLD);

scounts sdispls rcounts rdispls Process0 { 2, 1, 3, 2 } { 0, 2, 4, 8 } { 2, 1, 2, 3 } { 0, 3, 5, 9 } Process1 { 1, 2, 2, 3 } { 1, 3, 5, 7 } { 1, 2, 3, 2 } { 2, 4, 7,11 } Process2 { 2, 3, 1, 2 } { 2, 5, 8,11 } { 3, 2, 1, 2 } { 0, 4, 8,10 } Process3 { 3, 2, 2, 1 } { 2, 6, 9,12 } { 2, 3, 2, 1 } { 1, 3, 6, 9 }

• プロセス数が4で上記のパラメータの場合

Alltoallv

MPI_COMM_WORLD

sbuf

0 1 2 3 4 5 6 7 8 9 10 11 12

sbuf

0 1 2 3 4 5 6 7 8 9 10 11 12

sbuf

0 1 2 3 4 5 6 7 8 9 10 11 12

sbuf

0 1 2 3 4 5 6 7 8 9 10 11 12

P0

P1

P2

P3

MPI_COMM_WORLD

rbuf

0 1 2 3 4 5 6 7 8 9 10 11 12

rbuf

0 1 2 3 4 5 6 7 8 9 10 11 12

rbuf

0 1 2 3 4 5 6 7 8 9 10 11 12

rbuf

0 1 2 3 4 5 6 7 8 9 10 11 12

P0

P1

P2

P3

Example (alltoallv.c)

62

Page 64: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Alltoallw

int MPI_Alltoallw( const void* sendbuf, const int sendcounts[], const int sdispls[], const MPI_Datatype sendtypes[], void* recvbuf, const int recvcounts[], const int rdispls[], const MPI_Datatype recvtypes[], MPI_Comm comm )

プロセス毎に異なったDatatype

sendbuf, recvbufには十分な大きさが必要

sdispls, rdisplsはバイト数で指定する

• 引数はAlltoallvとほぼ同じ(sendtypes, recvtypesが配列)

sdispls[0] = rdispls[0] = 0; for(int i=0; i<size-1; ++i) { sdispls[i+1] = sdispls[i] + sizeof(sendtypes[i])*nsendcounts[i]; rdispls[i+1] = rdispls[i] + sizeof(recvtypes[i])*nrecvcounts[i]; }

Function prototype

Example (alltoallw.c)

63

Page 65: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Barrier

int MPI_Barrier( MPI_Comm comm )

全プロセスがコールするまで待ち合わせる

全プロセスが同時に復帰する訳ではない(タイムラグ有り)

ハードウェアによって高速化している場合もある

MPI_Barrier(MPI_COMM_WORLD);

Function prototype

Example

64

Page 66: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int MPI_Reduce_local( const void* inbuf, void* inoutbuf, int count, MPI_Datatype datatype, MPI_Op op )

引数にrootとMPI_Commが無い、プロセス内のみでreduce

int ibuf[2], iobuf[2];

MPI_Reduce_local(ibuf, iobuf, 2, MPI_INT, MPI_SUM );

int MPI_Op_commutative (MPI_Op op, int *commute )

演算が可換か否かを返す(true or false)

int iscommutative;

MPI_Op_commutative(MPI_INT, &iscommutative );

その他の関数 Function prototype

Function prototype

Example

Example

65

Page 67: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

非閉塞(Nonblocking)通信

通信相手の状態に関係なく即座に復帰

後からTest/Wait関数で完了

ノード内に通信用コプロセッサ等を持つ場合には Linuxカーネルを改造し通信処理を荷卸し(off-load) することで通信の隠蔽(overwrap)が可能な場合あり*

荷卸しできない場合はTest/Wait関数の中で 通信を開始するので通信は隠蔽できない (multi-thread化すれば隠蔽可能)

非閉塞通信は本来デッドロックを避けるために導入 MPI standardの中に隠蔽に関する規定は無い

*With suitable hardware, … may proceed concurrently with computations ... , pp. 47, MPI Standard 3.1

*whether such overlapping is possible may depend on the hardware environment, pp. 109, Using MPI, 2nd ed., MIT Press, 1999

66

Page 68: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int buf[3] = ... , sbuf[2] = ... , rbuf[2] = ... ; // buffers MPI_Request req[2]; MPI_Ibcast( buf, 3, MPI_INT, MPI_COMM_WORLD, &req[0] ); // some workloads MPI_Ireduce( sbuf, rbuf, 2, MPI_INT, MPI_SUM, 1, MPI_COMM_WORLD, &req[1] ); // another workloads MPI_Waitall(2, req, MPI_STATUSES_IGNORE);

非閉塞通信の使い方

IbcastとIreduceを使う場合

即座に復帰

待ち合せて完了

閉塞通信より引数が一つ(&req[ ])増えただけ

Waitall が復帰するまで buf, sbuf, rbuf にアクセスできない

その他の集団通信の使い方も上記と同じ

Wait, Testについては要素通信の中で説明する

即座に復帰

集団通信でstatusは不要

Example

67

Page 69: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

送受信バッファの共通化

送信バッファにMPI_IN_PLACEを指定するもの rootの指定のみ有効

MPI_Gather, MPI_Gatherv, MPI_Reduce 全プロセスで指定必要

MPI_Scan, MPI_Exscan, MPI_Allgather, MPI_Allgatherv, MPI_Allreduce, MPI_Alltoall, MPI_Alltoallv, MPI_Alltoallw, MPI_Reduce_scatter_block, MPI_Reduce_scatter

受信バッファにMPI_IN_PLACEを指定するもの rootの指定のみ有効

MPI_Scatter, MPI_Scatterv

非対応 MPI_Bcast , MPI_Barrier, MPI_Reduce_local, MPI_Op_commutative

非閉塞通信も閉塞通信と全く同じ メモリ節約に有効だが、同一アドレスへのread/write発生により効率面で不利 C言語ではポインタを使えばメモリコピー不要で配列入替えが可能

68

Page 70: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

69

Page 71: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

要素通信とは

最も基本的な通信方法 コミュニケータ内の一対のプロセス間の通信 一方が送信し、他方が受信する 送信側が制御する push mechanism 送受信を一つにまとめた複合通信が用意されている オーバーヘッドが軽い持続通信が用意されている

注意点

送信側にはモードがある 不適切なモード選択はデッドロックを引き起こす

70

Page 72: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

要素通信関数一覧

✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔

MPI_Send

MPI_Ssend

MPI_Bsend

MPI_Rsend

MPI_Recv

MPI_Mrecv*

MPI_Probe

MPI_Mprobe*

MPI_Sendrecv

MPI_Sendrecv_replace

MPI_Send_init

MPI_Ssend_init

MPI_Bsend_init

MPI_Rsend_init

MPI_Recv_init

MPI_Isend

MPI_Issend

MPI_Ibsend

MPI_Irsend

MPI_Irecv

MPI_Imrecv*

MPI_Iprobe

MPI_Improbe*

MPI_Start

MPI_Startall

Blocking Nonblocking

Send

Recv

Probe

Intercomm

✔ ✔ ✔ ✔

✔ ✔

✔ ✔

✔ ✔ ✔ ✔ ✔

Persistent

Combined

71 * MPI_Mrecv, MPI_Mprobe, MPI_Imrecv, MPI_Improbe はマルチスレッドで説明する

Page 73: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

要素通信関数一覧(続)

MPI_Wait

MPI_Waitany

MPI_Waitall

MPI_Waitsome

Buffer

Complete

MPI_Test

MPI_Testany

MPI_Testall

MPI_Testsome

Request

Status

MPI_Cancel

MPI_Request_free

MPI_Request_get_status

MPI_Test_cancelled

MPI_Get_count

MPI_Get_element*

MPI_Get_element_x*

MPI_Buffer_attach

MPI_Buffer_detach

72

Blocking Nonblocking

* MPI_Get_element, MPI_Get_element_x の説明は省略

Page 74: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Send

int MPI_Send( const void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm )

int buf[2];

MPI_Send(buf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD);

MPI_Recv

int MPI_Recv( void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status )

int buf[2];

MPI_Status status; MPI_Recv(buf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD, &status );

bufから始まる2つの整数にタグ9を付けてプロセス1に送る

タグ9が付いた2つの整数をプロセス0から受け取りbufに格納する

タグは通信の順序を識別するためにユーザが付ける整数 statusはMPI_SOURCE, MPI_TAG, MPI_ERRORからなる構造体 source/dest, tag, commの三つ組みをエンベロープ(envelope)と呼ぶ

73

Function prototype

Function prototype

Page 75: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Send( sbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD ); } else if(rank==1) MPI_Recv( rbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE );

2プロセスの例

Proc0からProc1にデータを送る

注:statusは必要ないのでMPI_STATUS_IGNOREで無効にしている

① Proc0がSendを開始

② Proc1がRecvを開始

③ Proc1のRecvが復帰(完了)

④ Proc0のSendが復帰(完了)

Proc0 Proc1

Send Recv

正常終了

① ②

③ ④

74

Example (sendrecv01.c)

Page 76: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Send( sbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==1) { sbuf[0] = 20; sbuf[1] = 30; MPI_Recv( rbuf, 2, MPI_INT, 0, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); MPI_Send( sbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD ); }

Proc0とProc1がデータを交換する(その1)

Proc0 Proc1

Send Recv

正常終了

① ②

Recv Send

④ ⑤ ⑥

⑦ ⑧

① Proc0がSendを開始

② Proc1がRecvを開始

③ Proc1のRecvが復帰(完了)

④ Proc0のSendが復帰(完了)

⑤ Proc1がSendを開始

⑥ Proc0がRecvを開始

⑦ Proc0のRecvが復帰(完了)

⑧ Proc1のSendが復帰(完了)

75

Example (sendrecv02.c)

Page 77: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Recv( rbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); MPI_Send( sbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD ); } else if(rank==1) { sbuf[0] = 20; sbuf[1] = 30; MPI_Recv( rbuf, 2, MPI_INT, 0, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); MPI_Send( sbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD ); }

Proc0とProc1がデータを交換する(その2)

① Proc0がRecvを開始

② Proc1がRecvを開始

③ 相手側がSendを開始するまで Recvは復帰できない ④ Recvが復帰しないと

Sendを開始できない

Proc0 Proc1

Recv Recv

② ①

互いに相手を待ち続ける

76

Example (sendrecv03.c)

Page 78: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Send( sbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==1) { sbuf[0] = 20; sbuf[1] = 30; MPI_Send( sbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 0, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); }

Proc0とProc1がデータを交換する(その3)

① Proc0がSendを開始

② Proc1がSendを開始

③ Proc0がデータをバッファリング

④ Proc1がデータをバッファリング

⑤ Proc0のSendが復帰

⑥ Proc1のSendが復帰

⑦ Proc0がRecvを開始

⑧ Proc1がRecvを開始

⑨ Proc0のRecvが復帰 ⑩ Proc1のRecvが復帰 正常終了

システムバッファ

Proc0 Proc1

Send Send ① ② ④

Recv Recv

⑥ ⑤

⑨ ⑩

⑧ ⑦

データが小さい場合(<16KB)

バッファリング閾値は実装依存 !! 77

Example (sendrecv04.c)

Page 79: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Send( sbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==1) { sbuf[0] = 20; sbuf[1] = 30; MPI_Send( sbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 0, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); }

Proc0とProc1がデータを交換する(その4)

① Proc0がSendを開始

② Proc1がSendを開始

③ 相手側がRecvを開始するまで Sendは復帰できない ④ Sendが復帰しないと

Recvを開始できない

データが大きい場合(>16KB) Proc0 Proc1

Send Send

② ①

互いに相手を待ち続ける

78

Example (sendrecv05.c)

Page 80: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

通信モード

送信関数には4種類のモードがある

• Standard mode

MPI_Send, MPI_Isend, MPI_Send_init

• Synchronous mode

MPI_Ssend, MPI_Issend, MPI_Ssend_init

• Ready mode

MPI_Rsend, MPI_Irsend, MPI_Rsend_init

• Buffered mode

MPI_Bsend, MPI_Ibsend, MPI_Bsend_init

MPI_Recv, MPI_Irecv, MPI_Recv_init

受信関数にはモードがない (push mechanism)

79

Page 81: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

• Standard データが小さい場合はシステムバッファにバッファリング

データが大きい場合は受信側とハンドシェイク

• Synchronous バッファリングせず受信側とハンドシェイク

最もデッドロック起き易い

このモードでデッドロックしないプログラムはsafe programと呼ばれる

• Ready

受信側の状態に関係なく即座に送信

受信側が既に待機している場合のみ開始可能

それ以外はエラーまたは不定状態

• Buffered

ユーザが設定した添付バッファにバッファリング

各モードの特徴

80

Page 82: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

• MPICHでは2つの通信プロトコルを定義*

• Rendezvous protocol まずエンベロープだけ送り、準備整ったらデータを送信

• Eager protocol エンベロープとデータを続けて即座に送信

• 送信関数の4つのモードで使い分けている

• Standard (Rendezvous or Eager with system-buffer)

• Synchronous (Rendezvous always without system-buffer)

• Ready (Eager always without system-buffer)

• Buffered (Rendezvous with attached-buffer)

*MPI standardに規定はない

通信モードの実装方法

81

Page 83: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Bsend( sbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==1) { sbuf[0] = 20; sbuf[1] = 30; MPI_Ssend( sbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 0, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); }

① Proc0がBsendを開始

② Proc1がSsendを開始

③ 添付バッファにバッファリング

④ Proc0がBsendから復帰

⑤ Proc0がRecvを開始 ⑥ Proc1がSsendから復帰

⑦ Proc1がRecvを開始

⑧ Proc0がRecvから復帰

⑨ Proc1がRecvから復帰 正常終了

• プロセス0でMPI_SendをMPI_Bsendに置き換える. • プロセス1はバッファリングを抑止するためMPI_Ssendを使う.

Proc0 Proc1

Bsend Ssend

① ②

Recv Recv

⑥ ④

⑧ ⑨

⑦ ⑤

通信モードを使ってデッドロックを避ける

82

Example (mode01.c)

Page 84: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Buffer_attach/MPI_Buffer_detach/ MPI_Bsend/MPI_Ssend

int MPI_Buffer_attach( void* buffer, int size ) int MPI_Buffer_detach( void* buffer_addr, int* size ) int MPI_Bsend( const void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm )

#define BUFFER_SIZE 10000 int bufsize = sizeof(int)*BUFFER_SIZE; void *buf = malloc((size_t)bufsize); MPI_Buffer_attach(buf, bufsize); if(rank==0) MPI_Bsend(buf, 5000, MPI_INT, 1, 9, MPI_COMM_WORLD); else if(rank==1) MPI_Recv(buf, 5000, MPI_INT, 0, 9, MPI_COMM_WORLD); MPI_Buffer_detach(buf, &bufsize);

ユーザ定義のバッファを生成・解放する

注:バッファサイズの指定はバイト数! Buffer_detachのsizeはポインタ型!

83

Function prototype

Page 85: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Send( sbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 2, 7, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==1) { sbuf[0] = 30; sbuf[1] = 40; MPI_Send( sbuf, 2, MPI_INT, 2, 8, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==2) { sbuf[0] = 50; sbuf[1] = 60; MPI_Send( sbuf, 2, MPI_INT, 0, 7, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); }

正常終了できるかはバッファリングに依存

3プロセスのデータ交換

周期境界の場合

Buffered modeを使う

Proc0 Proc1 Proc2

Send

Recv

Send

Recv

Send

Recv

84

Example (mode02.c)

Page 86: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Bsend( sbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 2, 7, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==1) { sbuf[0] = 30; sbuf[1] = 40; MPI_Ssend( sbuf, 2, MPI_INT, 2, 8, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==2) { sbuf[0] = 50; sbuf[1] = 60; MPI_Ssend( sbuf, 2, MPI_INT, 0, 7, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); }

添付バッファサイズが十分なら 正常終了

• プロセス0でMPI_SendをMPI_Bsendに置き換える. • プロセス1と2はバッファリングを抑止するためMPI_Ssendを使う.

① tag=7の送受信が完了

② tag=8の送受信が完了

③ tag=9の送受信が完了 しかし送受信は逐次的 ⇒ 非効率

int MPI_Ssend( const void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm )

85

Example (mode03.c)

Function prototype

Page 87: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Bsend( sbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 2, 7, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==1) { sbuf[0] = 30; sbuf[1] = 40; MPI_Bsend( sbuf, 2, MPI_INT, 2, 8, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==2) { sbuf[0] = 50; sbuf[1] = 60; MPI_Bsend( sbuf, 2, MPI_INT, 0, 7, MPI_COMM_WORLD ); MPI_Recv( rbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); }

添付バッファサイズが十分なら 正常終了

• 全てのプロセスでMPI_SendをMPI_Bsendに置き換える..

通信は並列に実行可能 しかしメモリコピーの時間が必要

データサイズが大きな場合非効率

⇒ 非閉塞Synchronous通信を使う! 86

Example (mode04.c)

Page 88: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

正常終了(並列的・メモリコピー不要)

MPI_Issend

MPI_Request req; int sbuf[2], rbuf[2]; if(rank==0) { sbuf[0] = 10; sbuf[1] = 20; MPI_Issend( sbuf, 2, MPI_INT, 1, 9, MPI_COMM_WORLD, &req ); MPI_Recv( rbuf, 2, MPI_INT, 2, 7, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==1) { sbuf[0] = 30; sbuf[1] = 40; MPI_Issend( sbuf, 2, MPI_INT, 2, 8, MPI_COMM_WORLD, &req ); MPI_Recv( rbuf, 2, MPI_INT, 0, 9, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } else if(rank==2) { sbuf[0] = 50; sbuf[1] = 60; MPI_Issend( sbuf, 2, MPI_INT, 0, 7, MPI_COMM_WORLD, &req ); MPI_Recv( rbuf, 2, MPI_INT, 1, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); } MPI_Wait( &req, MPI_STATUS_IGNORE );

• 全てのプロセスでMPI_SendをMPI_Issendに置き換える. • 後からMPI_Waitで完了させる.

但しリクエストの完了が必要

int MPI_Issend( const void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm , MPI_Request *request )

87

Example (mode05.c)

Function prototype

Page 89: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

88

完了関数の基本動作

• 閉塞通信では復帰=完了なので不要 • 非閉塞通信(持続通信も含む)では 通信ハンドル(request)を生成して即座に復帰する • 通信の完了には request を引数にWaitまたはTest関数を呼ぶ • 通信が完了していれば request から status が生成される • recv側は MPI_Get_count で status から受信データ数を得る • send側の request は MPI_request_free ですぐに解放しても良い

Wait関数 (MPI_Wait, MPI_Waitall, MPI_Waitany, MPI_Waitsome)

• Wait は request の完了まで待ち、完了後に status を返す • Wait の動作は非局所的(他プロセスに依存)で blocking

Test関数 (MPI_Test, MPI_Testall, MPI_Testany, MPI_Testsome) • Test は request の状態を flag に返して復帰する • status の値は flag=true の時には正常値、 flag=false の時は不定値となる • Test の動作は局所的(自プロセスで完結)で nonblocking

Page 90: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int MPI_Request int int int MPI_Status MPI_Wait ( ----- request, ----- ----- ----- *status ) MPI_Test ( ----- request, ----- *flag, ----- *status ) MPI_Wait_all ( count, requests[], ----- ----- ----- statuses[] ) MPI_Test_all ( count, requests[], ----- *flag, ----- statuses[] ) MPI_Wait_any ( count, requests[], ----- ----- *index, *status ) MPI_Test_any ( count, requests[], ----- *flag, *index, *status ) MPI_Wait_some ( incount, requests[], *outcount, ----- indices[], statuses[] ) MPI_Test_some ( incount, requests[], *outcount, ----- indices[], statuses[] )

89

完了関数の引数一覧

• all は requests[0, …, count-1]全てについて Wail/Test • any は requests[0, …, count-1]のどれか一つ(indexにその番号を返す) • some は requests[0, …, incount-1]の内 *outcount 個、番号は indices • Test_some は all, any と仕様が違うので注意 • 既に完了した request を再度 Wait, Test しても問題ない

• 非閉塞集団通信の場合の status の内容は不定(記述無し)

Page 91: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

90

完了関数の引数一覧(続き)

• Cancel は request を取り消すが、その後に MPI_Wait か MPI_Test で完了するか、MPI_Request_free で解放する必要がある • 非閉塞の要素通信は cancel できるが、集団通信はできない • Cancel は重い処理なのでなるべく使用しない • Request_free は request の割当てを解除(deallocate)する 解放された request は MPI_Wait や MPI_Test の引数に指定できない • Request_get_status は request が完了したかどうかを調べ 結果を flag と status に返す

MPI_Request int MPI_Status MPI_Cancel ( *request, ----- ----- ) MPI_Request_free ( *request, ----- ----- ) MPI_Request_get_status ( request, *flag, *status )

const MPI_Status int MPI_Test_cancelled ( *status, *flag )

• statusを調べて対応する通信が cancel に成功したかを flag に返す

Page 92: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

複合通信 (Combined communication)

int MPI_Sendrecv ( const void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, MPI_Comm comm, MPI_Status *status ) int MPI_Sendrecv_replace ( void *buf, int count, MPI_Datatype datatype, int dest, int sendtag, int source, int recvtag, MPI_Comm comm, MPI_Status *status )

91

Function prototype

自プロセス内の送信と受信を一つの関数で実行する

一対の送受信ではないことに注意

通信相手側は通常の send, recv で受けてることもできる

バッファを共通化した関数もある

閉塞通信のみ

int sbuf[2], rbuf[2], buf[2]; int left, right; MPI_sendrecv( sbuf, 2, MPI_INT, left, 9, rbuf, 2, MPI_INT, right, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); MPI_sendrecv_replace( buf, 2, MPI_INT, left, 9, right, 8, MPI_COMM_WORLD, MPI_STATUS_IGNORE );

Example (-----.c)

• replaceではデータ型とサイズは送信と受信で同じでなければならない

Page 93: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int MPI_Send_init( const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request ) int MPI_Ssend_init( const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request ) int MPI_Bsend_init( const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request ) int MPI_Rsend_init( const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request ) int MPI_Recv_init( const void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request ) int MPI_Start( MPI_Request *request ) int MPI_Startall( int count, MPI_Request array_of_requests [] )

持続通信 (Persistent communication)

92

Function prototype

最初に作った request を何度も再利用できる

通信開始は request を start させるだけでよい

非閉塞通信と同様に test, wait を呼んで完了させる

Page 94: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

93

int sbuf[100], rbur[100]; MPI_Request req[2]; MPI_Send_init( sbuf, 100, MPI_INT, left, 9, MPI_COMM_WORLD, &(req[0]) ); MPI_Recv_init( rbuf, 100, MPI_INT, left, 8, MPI_COMM_WORLD, &(req[1]) ); for(int n=0; n<NSTEP; ++n) { // setup sbuf

MPI_Startall( 2, req );

// overlap calculations

MPI_Waitall( 2, req, MPI_STATUSES_IGNORE );

// read rbuf }

Example (-----.c)

Page 95: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

データを一斉に隣のプロセスに送るシフト通信の場合 両端のプロセスは送信または受信のみとなる

送受信関数の dest/source に MPI_PROC_NULL を指定すると

通信せずに復帰する

これを使うとシフト通信のプログラムが少し見易くなる

MPI_PROC_NULLを使う

int sbuf[10], rbuf[10]; int size, rank; MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); int dest = ( rank<size-1 ? rank+1 : MPI_PROC_NULL ); int src = ( rank>0 ? rank-1 : MPI_PROC_NULL );

MPI_Send( sbuf, 10, MPI_INT, dest, 1, MPI_COMM_WORLD ); MPI_Recv( rbuf, 10, MPI_INT, src , 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE );

Proc0 Proc1 Proc2

Send

Recv

Send

Recv

Send

Recv

MPI_PROC_NULL

MPI_PROC_NULL 94

Page 96: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

マスターワーカモデル(Master-Worker model)では各ワーカがマスターに送ってくるタイミングが不定

プロセス番号とタグを指定して受信する方法では無駄な待ちが発生 ⇒ 順不同にデータを受け取りたい

受信関数の source, tag に MPI_ANY_SOURCE, MPI_ANY_TAG を指定すると到着した順(First come, first served)に受信する

countは実際に受信するデータより大きな値でも可

しかし送信されたデータのサイズが予め分らないので 受信バッファ rbuf のサイズを決められない

不足すると segmentation fault 等を発生しエラー終了

⇒ MPI_Probe で事前に status のみ取得する!

MPI_ANY_SOURCE/MPI_ANY_TAGを使う

int rbuf[100]; int count; if( master ) MPI_Recv( rbuf, count, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE );

95

Page 97: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Probe はデータは受け取らず status のみ受け取る

MPI_Iprobeはその非閉塞版、flagはtrueまたはfalseを返す

MPI_Get_countは status から受信データのサイズを抽出する

MPI_Probe/MPI_Iprobe/MPI_Get_count

int MPI_Probe( int source, int tag, MPI_Comm comm , MPI_Status *status ) int MPI_Iprobe( int source, int tag, MPI_Comm comm , int *flag, MPI_Status *status ) int MPI_Get_count( const MPI_Status *status, MPI_Datatype datatype, int *count ) Int MPI_Alloc_mem( MPI_Aint size, MPI_Info info, void *baseptr )

int *rbuf; int count; MPI_Status status; if( master ) { MPI_Probe( MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status ); MPI_Get_count( &status, MPI_INT, &count ); MPI_Alloc_mem( count*sizdof(int), MPI_INFO_NULL, rbuf ); MPI_Recv( rbuf, count, MPI_INT, status.MPI_SOURCE, status.MPI_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE ); }

注:statusはMPI_SOURCE, MPI_TAG, MPI_ERROR等をメンバとして持つ構造体

Probe / Iprobeはマルチスレッド実行時に問題あり 96

Page 98: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

97

Page 99: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

片側通信とは

各プロセスのメモリ上にウィンドウ(window)と呼ばれる公開領域を設定、これの領域に対して送受信する

注意点

ウィンドウ初期化、送受信、同期の3ステップがある

送受信関数の呼び出しは送信側または受信側のみ

比較・演算を組合わせた送受信も可能

送受信関数には request を返すものもある

通信は request が無くても同期が必要

同期方法には2種類の能動的同期(active target

synchronization)と1種類の受動的同期(passive target

synchronization)がある

98

Page 100: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

片側通信関数一覧

Nonlocal Local

Communi-

cation

Initialization

MPI_Rput

MPI_Rget

MPI_Raccumurate

MPI_Rget_accumurate

MPI_Put

MPI_Get

MPI_Accumurate

MPI_Get_accumurate

MPI_Fetch_and_op

MPI_Compare_and_swap

99

MPI_Win_create

MPI_Win_allocate

MPI_Win_allocate_shared*

MPI_Win_create_dynamic

MPI_Win_free

MPI_Win_attach

MPI_Win_detach

* MPI_Win_allocate_shared, MPI_Win_shared_query はマルチスレッドで説明する

Query MPI_Win_shared_query*

Page 101: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

片側通信関数一覧(続)

Synchro-

nization

100

MPI_Win_Fence

MPI_Win_Start

MPI_Win_Post

MPI_Win_Complete

MPI_Win_Wait

MPI_Win_Test

Active target Passive target

MPI_Win_lock

MPI_Win_lock_all

MPI_Win_unlock

MPI_Win_unlock_all

MPI_Win_flush

MPI_Win_flush_all

MPI_Win_flush_local

MPI_Win_flush_local_all

MPI_Win_sync

Group MPI_Win_get_group*

Info MPI_Win_set_info*

MPI_Win_get_info*

* MPI_Win_get_group, MPI_Win_set_info, MPI_Win_get_info の説明は省略

Page 102: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

101

初期化関数の引数

• どちらも local call、size はバイト数指定 • base, size はプロセス毎に異なってもよい

• MPI_Win_detach の引数 *base は正確には const void

MPI_Win void MPI_Aint MPI_Win_attach ( win *base size ) MPI_Win_detach ( win *base ----- )

• 全て collective call である、size と disp_unit はバイト数を指定する • base, size, disp_unit, info はプロセス毎に異なってもよい • MPI_Win_create は base から始まる size バイトの領域を設定する

size==0 の場合は base に MPI_BOTTOM を指定してもよい

• MPI_Win_allocate はシステムが size バイトの領域を確保、その先頭番地を

baseptr で返す(symmetric allocation できれば create より scalability 良い可能性)

• MPI_Win_create_dynamic は領域を確保せずにウィンドウを作成する

通信する前に MPI_Win_attach でメモリ割当てが必要

MPI_Win_detach で解放してから再度割り当てることができる

function void MPI_Aint int MPI_Info MPI_Comm void MPI_Win

MPI_Win_create *base size disp_unit info comm ----- *win

MPI_Win_allocate ----- size disp_unit info comm *baseptr *win

MPI_Win_create_dynamic ----- ----- ----- ----- comm ----- *win

MPI_Free ----- ----- ----- ----- ----- ----- *win

Page 103: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

102

送受信関数の引数

• 呼出し側(caller)プロセスを origin、相手側(callee)を target と呼ぶ

• データ移動の始点を source、終点を destination と呼ぶ MPI_Put ⇒ origin=source, target=destination

MPI_Get ⇒ origin=destination, target=source

• target 側のデータは memory window 内側、origin 側のデータは外側

function origin compare result target

void int Datatype void void int Datatype int Aint int Datatype Op Win Request

MPI_Put *addr count type ----- ----- ----- ----- rank disp count type ----- win -----

MPI_Get *addr count type ----- ----- ----- ----- rank disp count type ----- win -----

MPI_Accumulate *addr count type ----- ----- ----- ----- rank disp count type op win -----

MPI_Get_accumulate *addr count type ----- *addr count type rank disp count type op win -----

MPI_Fetch_and_op *addr ----- ----- ----- *addr ----- type rank disp ----- ----- op win -----

MPI_Compare_and_swap *addr ----- ----- *addr *addr ----- type rank disp ----- ----- ----- win -----

MPI_Rput *addr count type ----- ----- ----- ----- rank disp count type ----- win *request

MPI_Rget *addr count type ----- ----- ----- ----- rank disp count type ----- win *request

MPI_Raccumulate *addr count type ----- ----- ----- ----- rank disp count type op win *request

MPI_Rget_accumulate *addr count type ----- *addr count type rank disp count type op win *request

c.f. abbreviations: MPI_Datatype => Datatype, MPI_Aint => Aint, MPI_Op => Op, MPI_Win => Win, MPI_Request => Request

また origin と compare の void は正確には const void

Page 104: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

103

送受信関数の引数(続)

• 動作は非閉塞的であり、必ず同期が必要

• Put は origin の内容を target に代入、Get は target の内容を origin に代入

• Op は既定義の操作のみ(ユーザ定義は不可)、 origin と target の間で演算

• Accumurate は演算結果を target に格納 Op = MPI_REPLACE の場合は origin の内容を target に代入

• Get_accumulate は target の内容を result に保存後、演算結果を target に格納 Op = MPI_REPLACE の場合は origin の内容を target に代入

Op = MPI_NO_OP の場合は origin と target の内容は不変

• Fetch_and_op は target は Get_accumulate でデータが1要素の場合に特化

• Compare_and_swap も1要素のみ対象、target の内容を result に保存し、

compare と target の内容が等しい場合のみ origin の内容を target に代入

• Rのついた関数は request を返し MPI_Test, MPI_Wait 等で local に同期できる (但し、passive target synchronization でしか使えない)

Page 105: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

104

同期関数の引数 function int int MPI_Group int MPI_Win int

MPI_Win_fence ----- ----- ----- assert win -----

MPI_Win_start ----- ----- group assert win -----

MPI_Win_complete ----- ----- ----- ----- win -----

MPI_Win_post ----- ----- group assert win -----

MPI_Win_wait ----- ----- ----- ----- win -----

MPI_Win_test ----- ----- ----- ----- win “flag

MPI_Win_lock type rank ----- assert win -----

MPI_Win_unlock ----- rank ----- ----- win -----

MPI_Win_flush ----- rank ----- ----- win -----

MPI_Win_flush_local ----- rank ----- ----- win -----

MPI_Win_lock_all ----- ----- ----- assert win -----

MPI_Win_unlock_all ----- ----- ----- ----- win -----

MPI_Win_flush_all ----- ----- ----- ----- win -----

MPI_Win_flush_local_all ----- ----- ----- ----- win -----

MPI_Win_sync ----- ----- ----- ----- win -----

Page 106: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

105

同期の方法

Active target: • origin と target の両側で同期関数を呼ぶ • origin は access epoch の間だけ通信できる • target は exposure epoch の間だけウィンドウを公開する • 以下の2種類の方法がある

a. MPI_Win_fence b. MPI_Win_start + MPI_Win_complete / MPI_Win_post + MPI_Win_wait

Passive target: • origin 側のみが同期関数を呼ぶ

• origin は access epoch の間だけ通信できる • target は同期関数を呼ばないので epoch はない • 方法は下記1種類のみ a. MPI_Win_lock + MPI_Win_unlock,

(MPI_Win_lock_all + MPI_Win_unlock_all)

Page 107: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

106

Active target (collective synchronization)

MPI_Win_fence を使う

MPI_Win_fence は collective call である

MPI_Win_fence と MPI_Win_fence の間が epoch になり、

後ろのMPI_Win_fence がその間の通信を完了する

通信関数を呼ぶと origin なので access epoch と解釈される

通信関数を呼ばない場合は exposure epoch と解釈される

コミュニケータ内の全プロセスが全ウィンドウにアクセス可能

通信相手の数が多く、しかも頻繁に変わる場合に使う

MPI_Win_fence

MPI_Put

MPI_Get

MPI_Win_fence

MPI_Win_fence

MPI_Win_fence

origin process target process

buffer

window

access epoch exposure epoch buffer

Page 108: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

107

Active target (restricted synchronization)

origin 側に MPI_Win_start/MPI_Win_complete 、

target 側に MPI_Win_post/MPI_Win_wait を使う

ウィンドウアクセスの相手は MPI_Win_start で group を指定

ウィンドウを公開する相手はMPI_Win_post で group を指定

実装によって target が post するまで通信は始まらず

origin が complete した後に wait が復帰する (strong synchronization)

バッファリングする実装ではこの制約は無い (weak synchronization)

通信相手の数が少なく、しかも固定的な場合に使う

MPI_Win_start( group, … )

MPI_Put

MPI_Get

MPI_Win_complete

MPI_Win_post( group, … )

MPI_Win_wait

origin process target process

buffer

window

access epoch exposure epoch buffer

*MPI_Win_test はMPI_Win_wait の非閉塞版

Page 109: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

108

Passive target (lock synchronization)

origin 側に MPI_Win_lock/MPI_Win_unlock 、

または MPI_Win_lock_all/MPI_Win_unlock_all を使う

ウィンドウアクセスの相手は lock/unlock では rank のみ

lock_all/unlock_all では win の全プロセス

lock_all/unlock_all は collective call ではない

target のウィンドウを複数のプロセスで同時に使う場合

type に MPI_LOCK_SHARED を1つのプロセスが排他的(atomic)

に使用する場合 MPI_LOCK_EXCLUSIVE を指定する

MPI_Win_lock( type, rank, … )

MPI_Put

MPI_Get

MPI_Win_unlock( rank, … )

origin process target process

buffer

window

access epoch buffer

• 一般に flush は待ち状態の送受信を

強制的に完了させる

• MPI_Win_flush は rank に対する送受信、

MPI_Win_fllush_all は win 内の全送受信

を origin, target の両側で完了させる

• MPI_Win_flush_local, MPI_Win_flush_local_all

は origin 側のみ完了させる

• MPI_Win_sync はウィンドウを整合化し

epoch を仕切りなおす

Page 110: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

109

Page 111: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

マルチスレッド時のMPI関数実行

MPIではマルチスレッド時の実行に関して

低い順に以下の4つのレベルが設定されている

実行環境により設定可能なレベルは異なる

• MPI_THREAD_SINGLE

シングルスレッド時のみ実行可能

• MPI_THREAD_FUNNELED

マルチスレッド時はマスタースレッドのみ実行可能

• MPI_THREAD_SERIALIZED

マルチスレッド時は同時に一つのスレッドのみ実行可能*

• MPI_THREAD_MULTIPLE

マルチスレッド時も制約なしにどのスレッドも実行可能

*スレッド間の排他制御はユーザの責任

110

Page 112: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

レベル指定付き初期化

int MPI_Init_thread( int *argc, char ***argv, int required, int *provided )

int MPI_Query_thread( int *provided ) int MPI_Is_thread_main( int *flag )

int provided; MPI_Init_thread( argc, argv, MPI_THREAD_MULTIPLE, &provided ); if( provided!=MPI_THREAD_MULTIPLE ) printf( “MPI_THREAD_MULTIPLE is not supported!¥n” );

int provided, flag; MPI_Query_thread( &provided ); if( provided!=MPI_THREAD_MULTIPLE ) printf( “MPI_THREAD_MULTIPLE is not supported!¥n” ); MPI_Is_thread_main( &flag ); if( flag ) printf( “I am master thread!¥n” );

注:MPI_Init 同様、 argc, argv は省略可能

requiredはプロセス毎に異なる値でも可

Function prototype

Example (thread01.c)

Function prototype

Example (thread02.c)

問い合わせ関数

111

Page 113: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

スレッド共有記憶の設定

112

MPI_Comm oldcomm, newcomm; MPI_Info info = MPI_INFO_NULL; int type = MPI_COMM_TYPE_SHARED; int key = ; MPI_Comm_split_type( oldcomm, type, key, info, newcomm );

Example (-----.c)

int MPI_Win_allocate_shared( MPI_Aint size, int disp_unit, MPI_Info info, MPI_Comm comm, void *baseptr, MPI_Win win )

Function prototype

• comm のプロセスが共有する size バイトのメモリウィンドウ win

を割当てそのポインタを baseptr に返す

int MPI_Win_shared_query( MPI_Win win, int rank, MPI_Aint size, int disp_unit, void *baseptr )

Function prototype

• MPI_Win_allocate_shared で割当てたメモリウィンドウの情報を返す

Page 114: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

スレッド共有記憶の設定

113

MPI_Comm oldcomm, newcomm; MPI_Info info = MPI_INFO_NULL; int type = MPI_COMM_TYPE_SHARED; int key = ; MPI_Comm_split_type( oldcomm, type, key, info, newcomm );

Example (-----.c)

int MPI_Comm_split_type( MPI_Comm comm, int split_type, int key, MPI_Info info, MPI_Comm newcomm )

Function prototype

• 共有記憶領域毎に分離したコミュニケータを生成

MPI_Comm_create_group ( comm, group, tag, *newcomm )

・comm はイントラのみ ・group 内で collective call ・tag はマルチスレッド実行の時に使う

Page 115: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Mprobe/MPI_Mrecv /MPI_Improbe/MPI_Imrecv

複数のスレッドがMPI_Probeを実行した時、タイミングによって後続の MPI_Recvがデータを取り違える可能性がある

MPI_THREAD_MULTIPLE環境では thread safe な MPI_Mprobe と MPI_Mrecv (Matching Probe/Recv)を使う

MPI_Improbe と MPI_Imrecv はその非閉塞バージョン

ProbeとRecvは閉塞と非閉塞を組み合わせてもよい

int MPI_Mprobe( int source, int tag, MPI_Comm comm, MPI_Message *message, MPI_Status *status ) int MPI_Mrecv( void *buf, int count, MPI_Datatype datatype, MPI_Message *message, MPI_Status *status ) int MPI_Improbe( int source, int tag, MPI_Comm comm, int *flag, MPI_Message *message, MPI_Status *status ) int MPI_Imrecv( void *buf, int count, MPI_Datatype datatype, MPI_Message *message, MPI_Request *request )

注:MPI_Improbeの引数にはrequestが無い(Wait/Test不要)、代わりにflagがある(受信可能なデータの有無)。

またMPI_Imrecvの引数にはstatusが無い(Wait/Testで取得)

Function prototype

114

Page 116: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int *rbuf; int count; MPI_Status status; MPI_Message message; if( master ) { MPI_Mprobe( MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &message, &status ); MPI_Get_count( &status, MPI_INT, &count ); MPI_Alloc_mem( count*sizdof(int), MPI_INFO_NULL, rbuf ); MPI_Mrecv( rbuf, count, MPI_INT, &message, MPI_STATUS_IGNORE ); }

int *rbuf; int count, flag; MPI_Status status; MPI_Message message; MPI_Request request; if( master ) { MPI_Improbe( MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &message, &status ); if( !flag ) continue; MPI_Get_count( &status, MPI_INT, &count ); MPI_Alloc_mem( count*sizdof(int), MPI_INFO_NULL, rbuf ); MPI_Imrecv( rbuf, count, MPI_INT, &message, &request ); MPI_Wait( &request, MPI_STATUS_IGNORE ); }

Example (mprobe.c)

Example (improbe.c)

115

Page 117: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

116

Page 118: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

派生データ型とは

基本型を組み合わせてユーザが定義する構造を持ったデータ型

ギャップを挟んだデータや異なった型をメンバーにもつ構造体なども定義できる

さらに派生データ型を組み合わせた派生データ型も定義可能

注意点

関数名に一部整合的でないものが存在する(動詞Createが欠けている)

長さの指定が要素数の場合とバイト数の場合がある ギャップを詰めて圧縮したい場合は MPI_Pack で圧

縮し MPI_Unpack で復元する

117

Page 119: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

派生データ型関数一覧

Definition

118

MPI_Type_contiguous

MPI_Type_vector

MPI_Type_create_indexed_block

MPI_Type_indexed

MPI_Type_create_struct

MPI_Type_create_subarray*

MPI_Type_create_darray*

MPI_Type_create_resized*

Elements Bytes

MPI_Type_create_hvector

MPI_Type_create_hindexed_block

MPI_Type_create_hindexed

management

MPI_Type_commit

MPI_Type_free

MPI_Type_dup*

MPI_Get_address*

* MPI_Type_create_subarray, MPI_Type_create_darray はファイルI/Oで説明する MPI_Type_create_resized, MPI_Type_dup, MPI_Get_address の説明は省略

Page 120: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

派生データ型関数一覧(続)

119

Information

MPI_Type_size

MPI_Type_get_extent*

MPI_Type_get_true_extent*

MPI_Type_get_elements*

MPI_Type_get_envelope*

MPI_Type_get_contents*

int/Aint

MPI_Type_size_x*

MPI_Type_get_extent_x*

MPI_Type_get_true_extent_x*

MPI_Type_get_elements_x*

MPI_Count

MPI_Unpack

MPI_Unpack_external*

MPI_Pack

MPI_Pack_size

MPI_Pack_external*

MPI_Pack_external_size*

Deposit Withdrawal

Pack/Unpack

* MPI_Type_size, MPI_Pack , MPI_Unpack , MPI_Pack_size 以外の説明は省略

Page 121: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Type_contiguous

int MPI_Type_contiguous( int count , MPI_Datatype oldtype , MPI_Datatype *newtype )

MPI_Datatype newtype;

MPI_Type_contigous(4, MPI_INT, &newtype);

Function prototype

Example (-----.c)

• oldtype のデータを count 個連接した型を定義する

120

newtype = int int int int

Page 122: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Type_vector/MPI_Type_create_hvector

int MPI_Type_vector(int count , int blocklength, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype) int MPI_Type_create_hvector(int count , int blocklength, MPI_Aint stride, MPI_Datatype oldtype, MPI_Datatype *newtype)

MPI_Datatype newtype;

MPI_Type_vector(3, 2, 4, MPI_INT, &newtype);

Function prototype

Example (-----.c)

• 連続する blocklengh 個のデータを count 回繰り返す

• ブロック間の距離は stride で指定する

• stride の単位は vector は要素数、hvector はバイト数(h は heterogeneous の頭文字)

121

newtype = int int int int int int int int int int

blocklength

count

stride

(注:これはvectorの場合)

Page 123: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Type_create_indexed_block /MPI_Type_create_hindexed_block

int MPI_Type_create_indexed_block(int count , int blocklength, const int array_of_displacements[], MPI_Datatype oldtype, MPI_Datatype *newtype) int MPI_Type_create_hindexed_block(int count , int blocklength, const MPI_Aint array_of_displacements[], MPI_Datatype oldtype, MPI_Datatype *newtype)

MPI_Datatype newtype;

const int displacements = {4,3,0}; MPI_Type_indexed_block(3, 2, displacements, MPI_INT, &newtype);

Function prototype

Example (-----.c)

• MPI_Type_vector で stride の指定を可変にしたもの

• array_of_displacements の単位は indexed_block は要素数、hindexed_block はバイト数

122

newtype = int int int int int int int int int

blocklength

count

displacements[0] displacements[1]

(注:これはindexed_blockの場合)

Page 124: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Type_indexed/MPI_Type_create_hindexed

int MPI_Type_indexed(int count , const int array_of_blocklengths[], const int array_of_displacements[], MPI_Datatype oldtype, MPI_Datatype *newtype) int MPI_Type_create_hindexed(int count , const int array_of_blocklengths[], const MPI_Aint array_of_displacements[], MPI_Datatype oldtype, MPI_Datatype *newtype)

MPI_Datatype newtype;

const int blocklengths = {2,1,3}; const int displacements = {4,3,0};

MPI_Type_indexed(3, blocklengths, displacements, MPI_INT, &newtype);

Function prototype

Example (-----.c)

• MPI_Type_vector で blocklengh, stride の指定を可変にしたもの

• array_of_displacements の単位は indexed は要素数、hindexed はバイト数

123

newtype = int int int int int int int int int int

blocklengths[0]

count

displacements[0]

blocklengths[1] blocklengths[2]

displacements[1]

(注:これはindexedの場合)

Page 125: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Type_create_struct

int MPI_Type_create_struct(int count , const int array_of_blocklengths[], const MPI_Aint array_of_displacements[], MPI_Datatype array_of_types[], MPI_Datatype *newtype)

MPI_Datatype newtype;

const int blocklengths = {2,1,3}; const int displacements = {16,24,0};

MPI_Datatype types = {MPI_INT, MPI_FLOAT, MPI_CHAR};

MPI_Type_indexed(3, blocklengths, displacements, types, &newtype);

Function prototype

Example (-----.c)

• MPI_Type_vector で blocklengh, stride, oldtype の指定を可変にしたもの

• array_of_displacements の単位はバイト数

124

newtype =

blocklengths[0]

count

displacements[0]

blocklengths[1] blocklengths[2]

displacements[1]

int int float char char char

Page 126: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Type_commit

int MPI_Type_commit(MPI_Datatype *datatype)

MPI_Datatype newtype;

MPI_Type_commit(&newtype);

Function prototype

Example (-----.c)

• 派生データ型を通信に使えるよう有効化する

125

MPI_Type_free

int MPI_Type_free(MPI_Datatype *datatype)

MPI_Datatype newtype;

MPI_Type_free(&newtype);

Function prototype

Example (-----.c)

• 派生データ型を解放する(deallocateする)

Page 127: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Pack

int MPI_Pack(const void *inbuf, int incount, MPI_Datatype datatype, void *outbuf, int outsize, int *position, MPI_Comm comm)

Function prototype

• inbuf から始まる incount 個のdatatype 型データを outbuf から始まる長さ outsize の

バッファに push した後にカレントポインタ position を返す

126

float in0[2] = {0.1, 0.2};

int in1[3] = {11, 12, 13}; int position = 0;

char out[1000];

MPI_Comm comm = MPI_COMM_WORLD; MPI_Pack(in0, 2, MPI_FLOAT, out, 1000, &position, comm);

MPI_Pack(in1, 3, MPI_INT, out, 1000, &position, comm);

MPI_Send(out, position, MPI_PACKED, 1, 9, MPI_COMM_WORLD);

Example (-----.c)

outbuf = float int int float int

1000 bytes

incount

float float inbuf =

incount

int inbuf = int int

position position position

Page 128: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Function prototype

127

MPI_Unpack

• inbuf から始まる長さ insize のバッファのカレントポインタ position から、

outcount 個のdatatype 型データを pop して outbuf に格納する

int MPI_Unpack(const void *inbuf, int insize, int *position, void *outbuf, int outcount, MPI_Datatype datatype, MPI_Comm comm)

float out0[2];

int out1[3]; int position = 0;

char in[1000];

MPI_Comm comm = MPI_COMM_WORLD; MPI_Recv(in, 1000, MPI_PACKED, 0, 9, comm, MPI_STATUS_IGNORE);

MPI_Pack(in, 1000, &position, out0, 2, MPI_FLOAT, comm);

MPI_Pack(in, 1000, &position, out1, 3, MPI_INT, comm);

Example (-----.c) • MPI_recv の recvsize が position でないことに注意

outcount

float float outbuf =

outcount

int outbuf = int int

inbuf = float int int float int

1000 bytes

position position position

Page 129: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Type_size

int MPI_Type_size(MPI_Datatype datatype, int *size)

MPI_Datatype mytype;

int size; MPI_Type_size(mytype, &size);

Function prototype

Example (-----.c)

• datatype 型の大きさをバイト数で size に返す

128

MPI_Pack_size

int MPI_Pack_size(int incount, MPI_Datatype datatype, MPI_Comm comm, int *size)

MPI_Datatype mytype;

int size; MPI_Pack_size(10, mytype, MPI_COMM_WORLD, &size);

Function prototype

Example (-----.c)

• incount 個の datatype 型データを pack するために必要なバイト数を size に返す

Page 130: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

129

Page 131: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

#define BUFSIZE 100 int buf[BUFSIZE]; char fname[128]; sprintf( fname, “myfile%.4d”, rank ); // myfile0000 fp = fopen( fname, “w” ); fwrite( buf, sizeof(int), BUFSIZE, fp ); fclose( fp );

書式なし分離ファイルの使用法

MPI_I/Oの特徴

書式なしファイル(unformatted file)のみ

主に共通ファイル(common file)が対象

分離ファイル(separate files)は作成のみ対応

a) POSIX

b) MPI

130

MPI_COMM_SELF

Page 132: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

File I/O

MPI_File_open,

MPI_File_close,

MPI_File_delete,

MPI_File_preallocate,

MPI_File_set_view,

MPI_File_get_view,

MPI_File_set_size,

MPI_File_get_size,

MPI_File_set_info,

MPI_File_get_into,

MPI_File_set_atomicity,

MPI_File_get_atomicity,

MPI_File_seek,

MPI_File_seek_shared,

MPI_File_get_position,

MPI_File_get_position_shared,

MPI_File_get_byte_offset,

MPI_File_get_type_extent,

MPI_Register_datarep,

MPI_File_get_group,

MPI_File_get_amode,

MPI_File_sync,

131

Page 133: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_File_read MPI_File_iread

MPI_File_read_at MPI_File_iread_at

MPI_File_read_shared MPI_File_iread_shared

MPI_File_read_all MPI_File_read_all_begin/end

MPI_File_read_at_all MPI_File_read_at_all_begin/end

MPI_File_read_ordered MPI_File_read_ordered_begin/end

MPI_File_write MPI_File_iwrite

MPI_File_write_at MPI_File_iwrite_at

MPI_File_write_shared MPI_File_iwrite_shared

MPI_File_write_all MPI_File_write_all_begin/end

MPI_File_write_at_all MPI_File_write_at_all_begin/end

MPI_File_write_ordered MPI_File_write_ordered_begin/end

Blocking

Read

Nonblocking

Write

individual-file-pointer

explicit_offset

shared-file-pointer

seek relatively with pointers

access directly without pointer

seek relatively with a pointer

collective I/O function

split collective I/O function

Independent I/O function

132

Page 134: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Type_create_subarray

int MPI_Type_create_subarray(int ndims , const int array_of_sizes[], const int array_of_subsizes[], const int array_of_starts[], int order, MPI_Datatype oldtype, MPI_Datatype *newtype)

MPI_Datatype newtype;

const int sizes = {100, 100}; const int subsizes = {25, 25};

const int starts = {20, 40};

MPI_Type_create_subarray(2, sizes, subsizes, starts, MPI_ORDER_C, MPI_INT, &newtype);

Function prototype

Example (-----.c)

• ファイルI/Oでfiletypeに指定し、配列全体の一部だけ読み書きするために用いる

133

Page 135: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

134

Page 136: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

グループ・コミュニケータ・トポロジーの関係

135

イントラ・コミュニケータ

グループ

ranks = {0, 1, 2, …, n-1}

コンテキスト アトリビュート

・トポロジーは1つのイントラ・コミュニケータと 仮想トポロジーから構成される ・仮想トポロジーはアトリビュートの一種で ノード間の結合や重みなどの高次情報

・コミュニケータには2種類ある ・イントラ・コミュニケータはグループを1つ持つ ・インター・コミュニケータはグループを2つ持つ ・グループはランク番号の単純集合 ・コンテキストは通信範囲を限定する機能を持つ ・アトリビュートはユーザによって与えられる情報

インター・コミュニケータ

グループ

ranks = {0, 1, 2, …, n-1}

グループ

ranks = {0, 1, 2, …, m-1}

コンテキスト アトリビュート

仮想トポロジー

トポロジー

イントラ・コミュニケータ

グループ

ranks = {0, 1, 2, …, n-1}

コンテキスト アトリビュート

Page 137: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

グループの編集

136

MPI_Group_size( group, *size )

・group1 の ranks1[i] 番のプロセスが group2 では何番に対応するかを rank2[i] に返す ・対応するものがなければ M MPI_UNDEFINED を返す

・group1とgroup2を比較する, 完全に同じ場合は result に MPI_IDENT, 順序だけ異なる場合は MPI_SIMILAR, その他は MPI_UNEQUAL を返す

MPI_Group_translate _ranks( group1, n, ranks1[ ], group2, *ranks2[ ] )

MPI_Group_free( *group )

・groupの要素数を返す

MPI_Group_rank( group, *rank )

・自プロセスのrank番号を返す、存在しない場合は MPI_UNDEFINED を返す

MPI_Group_compare( group1, group2, *result )

・group に MPI_GROUP_NULLを代入し無効にする

* MPI_Comm_group と MPI_Group_xxx は全て non-collective

・コミュニケータ comm からグループ group を返す ・comm がインター・コミュニケータの場合は local group の group を返す

MPI_Comm_group( comm, *group )

Page 138: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

グループの編集(続)

137

MPI_Group_union( group1, group2, *newgroup )

MPI_Group_intersection( group1, group2, *newgroup )

MPI_Group_difference( group1, group2, *newgroup )

group1 = {0, 1, 2, 3, 4, 5},

group2 = {2, 4, 6, 8,10}

*newgroup = {0, 1, 2, 3, 4, 5, 6, 8,10}

*newgroup = {2, 4}

*newgroup = {0, 1, 3, 5}

group 1 group 2

*newgroup

MPI_Group_union

group 1 group 2

*newgroup

MPI_Group_intersection

group 1 group 2

*newgroup

MPI_Group_difference

・ユーザが新規にグループを定義することはできない ・既存のコミュニケータから抽出したグループを編集する

* 空集合の場合は MPI_GROUP_EMPTY が返される

Page 139: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

グループの編集(続)

138

MPI_Group_incl( group, 5, ranks, *newgroup )

MPI_Group_excl( group, 5, ranks, *newgroup )

group = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12}, ranks = {1, 3, 6, 9,12}

*newgroup = {1, 3, 6, 9,12}

*newgroup = {0, 2, 4, 5, 7, 8,10,11}

・ranges は (first, last, stride) の組の繰り返し 上の例では(0,7,2)と(8,12,3)の2組

・各組は first から last まで stride おきの番号を指定する ・指定された番号が group の要素に無い時はエラーになる ・range_incl は group から指定された番号を抜き出す ・range_excl は group から指定された番号を削除する ・range_incl と range_excl の和集合は group になる

group = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12}, ranges = {0, 7, 2, 8,12, 3}

MPI_Group_range_incl( group, 2, ranges, *newgroup )

MPI_Group_range_excl( group, 2, ranges, *newgroup )

*newgroup = {0, 2, 4, 6, 8,11}

*newgroup = {1, 3, 5, 7, 9,10,12}

・ranks の要素が group の要素に無い時はエラーになる ・incl は group から ranks で指定したランクを抜き出す ・excl は group から ranks で指定したランクを削除する ・incl と excl の和集合は group になる

(0,7,2) (8,12,3)

Page 140: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

コミュニケータの編集

139

MPI_Comm_size( comm, *size )

・comm1 と comm2 を比較し, 完全に一致する場合は MPI_IDENT, ランク番号の順序だけ異なる場合は MPI_SIMILAR, context だけ異なる場合は MPI_CONGRUENT, その他は MPI_UNEQUAL を result に返す ・comm 内で non-collective call

・comm の要素数を返す ・comm がインター・コミュニケータの場合は local group の要素数を返す ・comm 内で non-collective call

MPI_Comm_rank( comm, *rank )

・自プロセスの rank 番号を返す ・comm がインター・コミュニケータの場合は local group 内の rank 番号を返す ・comm 内で non-collective call

MPI_Comm_compare( comm1, comm2, *result )

Page 141: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

コミュニケータの編集(続)

140

・MPI_Comm_dup の非閉塞版 ・comm 内で collective call

MPI_Comm_free( *comm )

・comm の複製を *newcomm に返す ・comm 内で collective call

・comm を複製し info を上書きして *newcomm に返す ・comm 内で collective call

・comm に MPI_COMM_NULLを代入し無効にする ・MPI_COMM_WORLD には適用しない(できない) ・comm 内で collective call

MPI_Comm_dup ( comm, *newcomm )

MPI_Comm_dup_with_info (comm, info, *newcomm )

MPI_Comm_idup ( comm , *newcomm , *request )

Page 142: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

コミュニケータの編集(続)

141

MPI_Comm_create( comm, group, *newcomm )

・comm の部分集合 group のコミュニケータを作成し *newcomm に返す ・group に属さないプロセスには *newcomm に MPI_COMM_NULL を返す ・comm はイントラ・インターどちらも可、*newcomm は comm と同種 ・comm の attribute は引き継がない ・comm 内で collective call

インター・コミュニケータ

イントラ・コミュニケータ インター・コミュニケータ で group が1つの場合と同じ

MPI_Comm_create_group ( comm, group, tag, *newcomm )

・マルチスレッドの項で説明

MPI_Comm_group

MPI_Gtoup_incl etc. MPI_Comm_create

group group

sub-group sub-group *newcomm

sub-group sub-group

comm

group group

Page 143: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

コミュニケータの編集(続)

142

・color 毎に comm の部分コミュニケータを同名で作成し *newcomm に返す ・ランク番号は key の値が小さいものから 0, 1, 2, … の順に付けられる ・color=MPI_UNDEFINED と指定すると *newcomm には MPI_COMM_NULL を返す ・comm 内で collective call

MPI_Comm_split ( comm, color, key, *newcomm )

MPI_Comm_split_type ( comm, color, key, *newcomm )

・マルチスレッドの項で説明

MPI_Comm_split

+

(color,key)

comm

group

(red,1) (red,2)

(blue,3) (blue,1)

group

(red,0) (red,2)

(blue,1)

*newcomm

group

rank=0 rank=1

group

rank=0 rank=1

*newcomm

group

rank=1 rank=0

group

rank=0

インター・コミュニケータの場合

イントラ・コミュニケータの場合 インター・コミュニケータ で group が1つに同じ

Page 144: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

インター・コミュニケータの編集

143

MPI_Comm_remote_group ( comm, *group )

・comm がインター・コミュニケータであれば flag に true を返す ・comm 内で non-collective call

MPI_Comm_remote_size ( comm, *size )

・remote group の size を返す ・comm 内で non-collective call

MPI_Comm_test_inter ( comm, *flag )

・remote group を返す ・comm 内で non-collective call

MPI_Intercomm_merge ( intercomm, high, *newintracomm )

・intercomm を イントラ・コミュニケータに変換して *newintracomm に返す ・high=false の group から昇順にランク番号を付ける ・intercomm 内で collective call

Page 145: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

144

インター・コミュニケータの編集(続)

MPI_Intercomm_create ( local_comm, local_leader, peer_comm, remote_leader, tag, *newintercomm )

・local_comm と remote_leader が属するコミュニケータから インター・コミュニケータを生成し *newintercomm に返す ・両方のコミュニケータに属するプロセスが存在してはならない (disjoint communicators) ・peer_comm は local_comm と remote_comm を包含するコミュニケータ ・local_leader は local_comm 内のランク番号 ・remote_leader は peer_comm 内のランク番号 ・local_comm と peer_comm 内で collective call

group

local_comm

group

remote_comm

peer_comm peer_comm

group group

*newintercomm MPI_Intercomm_create

MPI_Intercomm_merge peer_comm

group

*newintracomm

peer_comm

group group

intercomm

Page 146: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

インター・コミュニケータの作成例

MPI_COMM_WORLDからイントラ・コミュニケータを2つ(Fluid,Solid)作る 各々のコミュニケータ内でランク番号が設定される (F0, F1, F2, S0, S1, S2, S3) FluidとSolidからインター・コミュニケータAircraftを作る

MPI_COMM_WORLD

P3

Fluid

P2,F2

P1,F1

P0,F0

Solid

P6,S2

P5,S1 P7,S3

P4,S0

Aircraft

145

Page 147: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

int main( int argc, char *argv[] ) { int rank, size; MPI_Init( &argc, &argv ); MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Group MPI_GROUP_WORLD, fgroup, sgroup; MPI_Comm_group( MPI_COMM_WORLD, &MPI_GROUP_WORLD ); int franks[3] = { 0, 1, 2 }; int sranks[4] = { 4, 5, 6, 7 }; MPI_Group_incl( MPI_GROUP_WORLD, 3, franks, &fgroup ); MPI_Group_incl( MPI_GROUP_WORLD, 4, sranks, &sgroup ); MPI_Comm Fluid, Solid, Aircraft; MPI_Comm_create( MPI_COMM_WORLD, fgroup, &Fluid ); MPI_Comm_create( MPI_COMM_WORLD, sgroup, &Solid ); if( fcomm!=MPI_COMM_NULL ) { const int fleader = 0; const int sleader = 4; MPI_Intercomm_create( Fluid, fleader, MPI_COMM_WORLD, sleader, 0, &Aircraft ); } if( scomm!=MPI_COMM_NULL ) { const int sleader = 0; const int fleader = 0; MPI_Intercomm_create( Solid, sleader, MPI_COMM_WORLD, fleader, 0, &Aircraft ); } MPI_Finalize(); return 0; }

WORLDから部分集合 のグループを2つ作る

Example (intercomm.c)

146

それぞれのグループから コミュニケータを生成する

2つのコミュニケータから インター・コミュニケータを生成する

Page 148: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

インター通信(Inter-communication)

2つのgroup間で通信する

集団通信では MPI_IN_PLACE は使えない

要素通信では dest, source に remote の rank を指定

片側通信はインター通信できない

147

Page 149: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Bcast

Fluidのプロセス1からSolidにBcastする場合

comm=Aircraftに設定する

rootを以下のよう設定する F0: root = MPI_PROC_NULL

F1: root = MPI_ROOT

F2: root = MPI_PROC_NULL

S0: root = 1

S1: root = 1

S2: root = 1

S3: root = 1

MPI_COMM_WORLD

P3

Fluid

P2,F2

P1,F1

P0,F0

Solid

P6,S2

P5,S1 P7,S3

P4,S0

Aircraft

148

Page 150: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Scatter/MPI_Scatterv

comm=Aircraftに設定する

rootを以下のよう設定する

Fluidのプロセス1の値が分割されSolidの全プロセスに格納

通信はBcastと同方向

F0: root = MPI_PROC_NULL

F1: root = MPI_ROOT

F2: root = MPI_PROC_NULL

S0: root = 1

S1: root = 1

S2: root = 1

S3: root = 1

MPI_COMM_WORLD

P3

Fluid

P2,F2

P1,F1

P0,F0

Solid

P6,S2

P5,S1 P7,S3

P4,S0

Aircraft

149

Page 151: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Gather/MPI_Gatherv/MPI_Reduce

MPI_COMM_WORLD

P3

Fluid

P2,F2

P1,F1

P0,F0

Solid

P6,S2

P5,S1 P7,S3

P4,S0

Aircraft

comm=Aircraftに設定する

rootを以下のよう設定する

Solid内の全プロセスの値が集められFluidのプロセス1に格納

通信はBcastと逆方向

F0: root = MPI_PROC_NULL

F1: root = MPI_ROOT

F2: root = MPI_PROC_NULL

S0: root = 1

S1: root = 1

S2: root = 1

S3: root = 1

150

Page 152: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Allgather/MPI_Allgatherv/MPI_Allreduce comm=Aircraftに設定する

rootは設定不要 Solid内の全プロセスの値が集められFluidの各プロセスに格納

Fluid内の全プロセスの値が集められSolidの各プロセスに格納 通信は双方向のAllgather!

sendcount=0にすると単方向のAllgatherになる

MPI_COMM_WORLD

P3

Fluid

P2,F2

P1,F1

P0,F0

Solid

P6,S2

P5,S1 P7,S3

P4,S0

Aircraft

151

Page 153: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Alltoall/MPI_Alltoallv/MPI_Alltoallw comm=Aircraftに設定する

rootは設定不要 Solid内の全プロセスの値が分割されFluidの各プロセスに連結格納

Fluid内の全プロセスの値が分割されSolidの各プロセスに連結格納 通信は双方向のAlltoall!

sendcount=0にすると単方向のAlltoallになる

MPI_COMM_WORLD

P3

Fluid

P2,F2

P1,F1

P0,F0

Solid

P6,S2

P5,S1 P7,S3

P4,S0

Aircraft

152

Page 154: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI_Reduce_scatter_block/MPI_Reduce_scatter comm=Aircraftに設定する

rootは設定不要 Solid内の全プロセスの値が総和されFluidの各プロセスに分割格納

Fluid内の全プロセスの値が総和されSolidの各プロセスに分割格納 通信は双方向のReduce_scatter!

MPI_Barrier comm=Aircraftに設定する

Solid内の全プロセスがコールまでFluidのプロセスは待機

Fluid内の全プロセスがコールまでSolidのプロセスは待機

非閉塞通信の動作・使用方法も

完了手順を除いて閉塞通信と同じ

153

Page 155: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Topology

MPI_Neighbor_allgather, MPI_Ineighbor_allgather,

MPI_Neighbor_allgatherv, MPI_Ineighbor_allgatherv,

MPI_Neighbor_alltoall, MPI_Ineighbor_alltoall,

MPI_Neighbor_alltoallv, MPI_Ineighbor_alltoallv,

MPI_Neighbor_alltoallw, MPI_Ineighbor_alltoallw,

MPI_Graph_create,

MPI_Topo_test,

MPI_Graphdims_get,

MPI_Graph_get,

MPI_Graph_neighbors_count,

MPI_Graph_neighbors,

MPI_Graph_map,

MPI_Cart_create,

MPI_Dims_create,

MPI_Cartdim_get,

MPI_Cart_get,

MPI_Cart_rank,

MPI_Cart_coords,

MPI_Cart_shift,

MPI_Cart_sub,

MPI_Cart_map,

MPI_Dist_graph_create_adjacent,

MPI_Dist_graph_create,

MPI_Dist_graph_neighbors_count,

MPI_Dist_graph_neighbors,

154

Inter-communication はできない

Page 156: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

155

Page 157: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

プロセス生成とは

MPIプログラム実行中、動的にプロセスを生成可能 Unixのforkに似た機能 生成したプロセス上で任意のプログラムを実行可能 呼出し側プロセスはインター・コミュニケータの local に、

生成されたプロセスは remote に置かれる コミュニケータを共有しないプロセス間にも

socketのようなポートを設定することで通信可能

注意点

呼出し側は必ずイントラ・コミュニケータ 生成しても MPI_COMM_WORLD は不変

(インター・コミュニケータに包含される)

ポートの動作は実装や環境に依存する(Ubuntuは不可?)

156

Page 158: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

157

プロセス生成の例

最初 MPI_COMM_WORLD は4つのプロセスを持つとする MPI_Comm_spawn を使い comm 以外の引数を以下のように仮定する

・ command=“worker” プログラム名はworker ・ argv[]=MPI_ARGV_NULL オプションは無し ・ maxprocs=3 3つのプロセスを生成する ・ info=MPI_INFO_NULL infoは無し ・ root=0 rootはランク0番とする ・ errcode[]=MPI_ERROCODES_IGNORE エラーコードは無視する

・ comm の値が MPI_COMM_WORLD か MPI_COMM_SELF かによって生成されるプロセスの構成が異なる

MPI_Comm_spawn ( command , *argv[], maxprocs, info , root, comm, *intercomm, errcode[] )

・maxprocs 個のプロセスを生成し argv をオプションとして command を実行する ・生成したプロセスを remote とするインター・コミュニケータを inter_comm に返す

MPI_Comm_get_parent( *parent )

・親プロセス parent に返す

MPI_Comm_spawn_multiple(…)

・MPI_Comm_spawn で command が複数の場合、command 毎に argv 等を設定する

• MPI_Comm_join には Berkeley socket interface が 必要なので説明は省略

Page 159: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

#include <stdio.h> #include “mpi.h” int main( int argc, char *argv[] ) { int rank, size; MPI_Init( &argc, &argv ); MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm intercomm; MPI_Comm comm = MPI_COMM_SELF; // MPI_Comm comm = MPI_COMM_WORLD; int maxprocs = 3, root = 0; MPI_Comm_spawn( “worker”, MPI_ARGV_NULL, maxprocs, MPI_INFO_NULL, root, comm, &intercomm, MPI_ERROCODES_IGNORE ); int wrank, wsize, rsize; MPI_Comm_size( intercomm, &wsize ); MPI_Comm_rank( intercomm, &wrank ); MPI_Comm_remote_size( intercomm, &rsize ); MPI_Finalize(); return 0; }

Example (commspawn.c)

158

インター・コミュニケータのサイズとランクを取得

プロセスを3つ生成し worker を実行

Remote group のサイズを取得

Page 160: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

#include <stdio.h> #include “mpi.h” int main( int argc, char *argv[] ) { MPI_Comm parent; int rank, size, rsize; MPI_Init( &argc, &argv ); MPI_Comm_get_parent( &parent ); MPI_Comm_remote_size( parent, &rsize ); MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Finalize(); return 0; }

Example (worker.c)

159

親プロセスを取得

親プロセスのサイズを取得

Page 161: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

160

comm == MPI_COMM_WORLD

local remote

inter

comm == MPI_COMM_SELF

inter inter

local

remote

local

remote

local local

remote remote

inter inter

・ local group はMPI_COMM_WORLD ・ remote group は生成した3つのプロセス ・ intercomm は1つ

最初のMPI_COMM_WORLDのプロセス

・ local group は各プロセス(i.e. MPI_COMM_SELF)

・ 各プロセスに3プロセスの remote group ・ intercomm は4つ

Page 162: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

ポートを使ったプロセス間通信

MPI_Open_port,

MPI_Close_port,

MPI_Comm_accept,

MPI_Comm_connect,

MPI_Comm_disconnect,

MPI_Publish_name,

MPI_Unpublish_name,

MPI_Lookup_name,

161

Page 163: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI関数各論

1. 集団通信

2. 要素通信

3. 片側通信

4. マルチスレッド

5. 派生データ型

6. ファイルI/O

7. コミュニケータ・トポロジー

8. プロセス生成

9. その他

162

Page 164: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Environmental

MPI_Get_version,

MPI_Get_library_version,

MPI_Get_processor_name,

MPI_Alloc_mem,

MPI_Free_mem,

MPI_Wtime,

MPI_Wtick,

163 * MPI_Init_thread, MPI_Query_thread, MPI_Is_thread_main はマルチスレッドで説明する

バージョン、ノード名、メモリ割当て、時刻 MPIプログラムの初期化、終了、スレッド

MPI_Init,

MPI_Init_thread*,

MPI_Initialized,

MPI_Finalize,

MPI_Finalized,

MPI_Abort,

MPI_Query_thread*,

MPI_Is_thread_main*,

MPI_Get_version は整数、MPI_Get_library_version は文字列で返す MPI_Get_processor_name は Unix のhostname と同じ MPI_Alloc_mem, MPI_Free_mem は通常 malloc, free と同じだが最適化している場合もある MPI_Wtime は時刻、MPI_Wtick はサイクル数を返す

Page 165: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Info

164

コミュニケータ・ウィンドウ・ファイル・トポロジの関数引数に与える性能最適化のためのヒントを Info オブジェクトと呼ぶ

以下のような関数が利用可能

MPI_Info_create,

MPI_Info_dup,

MPI_Info_free,

MPI_Info_set,

MPI_Info_get,

MPI_Info_get_valuelen,

MPI_Info_get_nkeys,

MPI_Info_get_nthkey,

MPI_Info_delete,

MPI_Win_create,

MPI_Win_allocate,

MPI_Win_allocate_shared,

MPI_Win_create_dynamic,

MPI_Win_set_info,

MPI_Win_get_info,

MPI_File_open,

MPI_File_delete,

MPI_File_set_view,

MPI_File_set_info,

MPI_File_get_info,

Info オブジェクトを引数に持つ関数

MPI_Comm_spawn,

MPI_Comm_spawn_multiple,

MPI_Comm_dup_with_info,

MPI_Comm_accept,

MPI_Comm_connect,

MPI_Comm_open_port,

MPI_Comm_lookup_name,

MPI_Comm_publish_name,

MPI_Comm_unpbulish_name,

MPI_Comm_set_info,

MPI_Comm_get_info,

MPI_Dist_graph_create,

MPI_Dist_graph_create_adjucent,

Infoで利用可能な値は各ライブラリの ユーザマニュアル等に記載されている

Page 166: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Caching

165

コミュニケータ・ウィンドウ・派生データ型にAttributeと呼ばれる付加情報を持たせるために用いる

トポロジはコミュニケータにAttributeを加えることで実現されている

以下のような関数が利用可能

MPI_Comm_create_keyval,

MPI_Comm_free_keyval,

MPI_Comm_set_attr,

MPI_Comm_get_attr,

MPI_Comm_delete_attr,

MPI_Win_create_keyval,

MPI_Win_free_keyval,

MPI_Win_set_attr,

MPI_Win_get_attr,

MPI_Win_delete_attr,

MPI_Type_create_keyval,

MPI_Type_free_keyval,

MPI_Type_set_attr,

MPI_Type_get_attr,

MPI_Type_delete_attr,

typedef int MPI_Comm_copy_attr_function( MPI_Comm oldcomm, int keyval, void “val_in, void *val_out, int “flag );

typedef int MPI_Win_copy_attr_function( MPI_Win oldwin, int keyval, void “val_in, void *val_out, int “flag );

typedef int MPI_Type_copy_attr_function( MPI_Datatype oldtype, int keyval, void “val_in, void *val_out, int “flag );

typedef int MPI_Comm_delete_attr_function( MPI_Comm comm, int keyval, void *val, void *state );

typedef int MPI_Win_delete_attr_function( MPI_Win win, int keyval, void *val, void *state );

typedef int MPI_Type_delete_attr_function( MPI_Datatype type, int keyval, void *val, void *state );

create_keyval には以下のコールバック関数を指定する

Page 167: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Naming

166

コミュニケータ・ウィンドウ・派生データ型に文字列型の名前を持たせるために用いる

以下のような関数が利用可能

MPI_Comm_set_name,

MPI_Comm_get_name,

MPI_Win_set_name,

MPI_Win_get_name,

MPI_Type_set_name,

MPI_Type_get_name,

Page 168: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Error handling

167

コミュニケータ・ウィンドウ・ファイルにエラーハンドラを持たせるために用いる

エラークラスや文字列の注釈も設定できる 以下のような関数が利用可能

MPI_Comm_create_errhandler,

MPI_Comm_set_errhandler,

MPI_Comm_get_errhandler,

MPI_Comm_call_errhandler,

MPI_Win_create_errhandler,

MPI_Win_set_errhandler,

MPI_Win_get_errhandler,

MPI_Win_call_errhandler,

MPI_File_create_errhandler,

MPI_File_set_errhandler,

MPI_File_get_errhandler,

MPI_File_call_errhandler,

MPI_Error_class,

MPI_Error_string,

MPI_Errhandler_free, MPI_Add_error_class,

MPI_Add_error_code,

MPI_Add_error_string,

Page 169: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

External interfaces

Generalized request:

MPI_Grequest_start,

MPI_Grequest_complete,

Status:

MPI_Status_set_elements,

MPI_Status_set_elements_x,

MPI_Status_set_cancelled,

168

ユーザ独自の非閉塞通信を定義するためのもの generalized request と status の振舞いを定義する 以下のような関数が利用可能

Page 170: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Tool support

Profiling interface:

MPI_Pcontrol,

Tool information interface:

MPI_T_pvar_get_num,

MPI_T_pvar_get_info,

MPI_T_pvar_get_index,

MPI_T_pvar_handle_alloc,

MPI_T_pvar_handle_free,

MPI_T_pvar_read,

MPI_T_pvar_write,

MPI_T_pvar_session_create,

MPI_T_pvar_session_free,

MPI_T_pvar_start,

MPI_T_pvar_stop,

MPI_T_pvar_reset,

MPI_T_pvar_readreset,

MPI_T_cvar_get_num,

MPI_T_cvar_get_info,

MPI_T_cvar_get_index,

MPI_T_cvar_handle_alloc,

MPI_T_cvar_handle_free,

MPI_T_cvar_read,

MPI_T_cvar_write,

MPI_T_enum_get_info,

MPI_T_enum_get_item,

MPI_T_Init_thraed,

MPI_T_finalize,

MPI_T_category_get_num,

MPI_T_category_get_info,

MPI_T_category_get_cvars,

MPI_T_category_get_pvars,

MPI_T_category_get_categories,

MPI_T_category_changed,

169

・ Tool information interface は MPI_T_init_thread と MPI_T_finalize の間で呼べる ・ MPI_Init の前や MPI_Finalize の後でも呼ぶことができる ・ pvar は performance variables、cvar は control variables の略 ・ C のみ定義されている(Fortranからは使えない)

Page 171: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

並列性能評価

1. 並列性能について

2. 通信性能について

170

Page 172: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

1. Strong scaling (Amdahl’s law)

2. Weak scaling (Gustafson’s law)

タスクを細分した場合の処理速度(speedup)

Gene M. Amdahl, Validity of the single processor approach to achieving large scale computing capabilities, AFIPS Conference Proceedings, (30), 483-485, 1967

John L. Gustafson, Reevaluating Amdahl’s law, Communication of the ACM, 31(5), 532-533, 1988

スケーリング性能

タスクを追加した場合の単位時間当たり処理量(throughput)

t=T0 t=T0/4 t=T0/9

x-FLOPS 4x-FLOPS 9x-FLOPS

171

Page 173: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

• Amdahl’s law

逐次処理時間の内で並列部分(分割可能)を p 逐次部分を s とすると

並列処理時間は下図のようになる

𝑆 =𝑠 + 𝑝

𝑠 + 𝑝 𝑁 = 𝑁

𝛼 + 1

𝑁𝛼 + 1, 𝐸𝑎 =

𝑆

𝑁=

𝛼 + 1

𝑁𝛼 + 1 α =

𝑠

𝑝

逐次処理時間を並列処理時間で除した値を速度向上(Speedup)、

速度向上をプロセス数N で除した値を効率(Efficiency)と定義する

逐次処理

s p

並列処理

s p/N

十分な効率を得るには α は小さな値が必要

α 0.1 0.01 0.001 0.0001

N

10 0.550 0.918 0.991 0.999

100 0.100 0.505 0.909 0.990

1000 0.010 0.091 0.500 0.909

10000 0.001 0.010 0.090 0.500

Ea の例

172

Page 174: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

• Gustafson’s law

並列処理時間の内で比例部分(並列可能)を p’ 定数部分を s’ とする、

もしこれを逐次処理した場合、処理時間は下図のようになる

𝐺 =𝑠 + 𝑁𝑝′

𝑠 + 𝑝′= 𝑁

1 + 𝛼′ 𝑁

1 + 𝛼′, 𝐸𝑔 =

𝐺

𝑁=1 + 𝛼′ 𝑁

1 + 𝛼′ 𝛼′ =

𝑠

𝑝′

逐次処理時間を並列処理時間で除した値を処理向上(throughput gain)

処理向上をプロセス数N で除した値を効率(Efficiency)と定義する

並列処理

s p’

比較的大きな 𝛼′ でも効率は良い値となる (c.f. 𝛼′ = 𝑁𝛼)

α’ 0.4 0.2 0.1 0.05

N

10 0.742 0.850 0.918 0.957

100 0.717 0.835 0.909 0.952

1000 0.714 0.833 0.909 0.952

10000 0.714 0.833 0.909 0.952

Eg の例

逐次処理

s Np’

173

Page 175: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

・Strong scaling

•実測時間を用いた性能評価

プロセス数 n と m の2点で評価する (但しn>mとする)

𝑇𝑛 = 𝑠 + 𝑝 𝑛 , 𝑇𝑚 = 𝑠 + 𝑝 𝑚 , 𝑇𝑛はプロセス数 𝑛 の実測時間

𝑠 =𝑛𝑇𝑛 −𝑚𝑇𝑚𝑛 −𝑚

, 𝑝 =𝑛𝑚 𝑇𝑚 − 𝑇𝑛

𝑛 − 𝑚

Amdahl’s lawに従うと仮定すると

この式を解いて

従って

𝛼 =𝑠

𝑝=

𝑛𝑇𝑛 −𝑚𝑇𝑚𝑛𝑚 𝑇𝑚 − 𝑇𝑛

=𝑛 𝑚 − 𝑇𝑚 𝑇𝑛

𝑛 𝑇𝑚 𝑇𝑛 − 1

𝐸𝑎 =𝛼 + 1

𝑛𝛼 + 1, 𝑆 = 𝑛𝐸𝑎,

効率と速度向上は 𝛼 と 𝑛 を用いて以下の式で表される

一般に𝑚 が𝑛 に近い程良い値になる

𝑚 = 1 で評価できれば理想的

174

Page 176: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

・Weak scaling

𝑇𝑛 = 𝑠 + 𝑝′, 𝑇𝑚 =𝑚

𝑛𝑠 + 𝑝′, 𝑇𝑛はプロセス数𝑛の実行時間

この式を解いて

プロセス数 n と m の2点で評価する (但しn>mとする)

𝑠 =𝑛 𝑇𝑛 − 𝑇𝑚𝑛 −𝑚

, 𝑝′ =𝑛𝑇𝑚 −𝑚𝑇𝑛𝑛 − 𝑚

従って

𝛼′ =𝑠

𝑝′=𝑛 𝑇𝑛 − 𝑇𝑚𝑛𝑇𝑚 −𝑚𝑇𝑛

=1 − 𝑇𝑚 𝑇𝑛

𝑇𝑚 𝑇𝑛 − 𝑚 𝑛

効率と処理向上は 𝛼 と 𝑛 を用いて以下の式で表される

𝐸𝑔 =1 + 𝛼′ 𝑛

1 + 𝛼′, 𝐺 = 𝑛𝐸𝑔,

Gustafson’s lawに従い、さらに 𝑠 はプロセス数に比例すると仮定 ∗

* Weak scalingの場合, 𝑠が通信, 𝑝′が計算タスクを含むと考えるのが合理的である

従って通信オーバーヘッド等プロセス数に依存するのは𝑠と見做すべきあるが、

解を得るには依存性に何らかの仮定が必要である 175

Page 177: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

並列性能評価

1. 並列性能について

2. 通信性能について

176

Page 178: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Ping-pong 2つのプロセス間で交互に送受信

Full-bisection 全プロセスの半分が送信、残りが受信

Exchange 全プロセスが隣接プロセスと送受信

Intel MPI Benchmark(IMB) MPI関数の網羅的ベンチマークスイート

レイテンシ(Latency)と帯域幅(Band width)

ベンチマーク手法

177

データサイズ

時間

[KB]

[msec]

レイテンシ(usec)

帯域幅(GB/s)

典型的な通信性能

パケット長

レイテンシ: 通信準備等に必要な固定時間 帯 域 幅: 定常的な通信速度のこと

通信時間はデータサイズが小さい時はレイテンシに律速され、パケット長を超える辺りから帯域幅が効いてくる

Page 179: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

具体的な問題への応用

1. 構造格子系(差分法)

2. 非構造格子系(有限要素法,有限体積法)

3. フーリエ変換

4. MPI Tips

178

Page 180: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

• 領域分割法(Domain Decomposition)

2次元差分法 ヤコビ法によるポアソン方程式(∆𝜑 = 𝑓)の解法

計算格子全体を分割して各プロセスで分担

領域分割

全格子(18x10格子点) 6プロセスで領域分割 部分格子は6x5格子点

差分計算に必要となる内部境界点 (赤色)は隣接プロセスと通信 外部境界(青色)は境界条件を適用

境界のデータは隣接プロセスとの通信で取得

179

Page 181: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

• ステンシル(Stencil)による通信パターンの違い

5点差分: 𝑤𝑖,𝑗 =1

4𝜑𝑖+1,𝑗 + 𝜑𝑖−1,𝑗 + 𝜑𝑖,𝑗+1 + 𝜑𝑖,𝑗−1 − ℎ2𝑓𝑖,𝑗

𝑤𝑖,𝑗 =1

8 𝜑𝑖+1,𝑗 + 𝜑𝑖−1,𝑗 + 𝜑𝑖,𝑗+1 + 𝜑𝑖,𝑗−1

+𝜑𝑖+1,𝑗+1 + 𝜑𝑖−1,𝑗+1 + 𝜑𝑖+1,𝑗−1 + 𝜑𝑖−1,𝑗−1 − 3ℎ2𝑓𝑖,𝑗

𝑖 + 1 𝑖 − 1 𝑖

𝑗 + 1

𝑗 − 1

𝑗

9点差分:

𝑖 + 1 𝑖 − 1 𝑖

𝑗 + 1

𝑗 − 1

𝑗

隣接する4つの

プロセスと通信

隣接する8つの

プロセスと通信

180

Page 182: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

• 5点差分におけるMPI通信のポイント

カーテシアン・トポロジ(MPI_Cart_create)を使う 隣接プロセスの特定が容易なので間違う可能性が低い

プロセスの物理的配置(Affinity)をユーザ自身で最適化するのは困難だが、

(インターコネクトの物理的形状や通信バンド幅等の知識が必要)

ベンダー提供ライブラリでは最適化されている可能性がある

注:MPI_Dims_createの因数分解は(特に高次元で)あまり賢くない (例: 9=1x9 )

派生データ型を使う 派生データ型は一度定義しておけばPack/Unpackの必要がなく便利

ベンダーによっては特定ハードウェアに最適化している可能性がある

注:ベクトル化・マルチスレッド化したPack/Unpackの方が速い場合もある

複合通信(MPI_Send_recv)を使う 複数の送受信の順序をユーザ自身で最適化するのは困難

非閉塞通信も通信チャネル数や帯域幅が十分でないと無駄な待ちが発生する

多プロセス数のシフト通信(一斉に隣に送る)では特に効果的

注:閉塞通信なので通信の隠蔽はできない

181

Page 183: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

( 1, 1, &a, &b )

Process b a

( 1, -1, &a, &b )

Process a b

MPI_Cart_shift が返すプロセス番号 a, b の位置関係

( 0, 1, &a, &b )

Process

a

b

( 0, -1, &a, &b )

Process

b

a

16 // define a cartesian topology 17 MPI_Comm cart2d; 18 int ndims = 2; 19 int reorder = true; 20 int dims[2] = { 0, 0 }; 21 int periods[2] = { false, false }; 22 int east, west, north, south; 23 MPI_Dims_create( size, ndims, dims ); 24 MPI_Cart_create( basecomm, ndims, dims, periods, reorder, &cart2d ); 25 MPI_Cart_shift( cart2d, 1, 1, &west, &east ); 26 MPI_Cart_shift( cart2d, 0, 1, &south, &north );

jacobi2d5p.c

5点差分(通信隠蔽無し)

1. コミュニケータ(cart2d)の定義

プロセス配置は2次元

プロセス並替えを許可

sizeを因数分解した値をdimsに返す

境界は非周期

182

Page 184: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

49 // define derived datatypes 50 MPI_Datatype xghost, yghost; 51 MPI_Type_vector( 1, ny, ny+2, MPI_FLOAT, &xghost ); 52 MPI_Type_vector( nx, 1, ny+2, MPI_FLOAT, &yghost ); 53 MPI_Type_commit( &xghost ); 54 MPI_Type_commit( &yghost );

jacobi2d5p.c

nx

2. 派生データ型(xghost, yghost)の定義

yghost xghost

ny ny+2 ny+2

1

1

strid

e

strid

e

count count

blo

ck

len

gth

blo

ck

len

gth

注:データはY軸方向に連続

183

Page 185: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

56 // send buffers // recv buffers 57 void *sbuf_n = &(phi[1][ny]); void *rbuf_n = &(phi[1][ 0]); 58 void *sbuf_s = &(phi[1][ 1]); void *rbuf_s = &(phi[1][ny+1]); 66 // shift northward 67 MPI_Sendrecv( sbuf_n, 1, yghost, north, 0 68 rbuf_n, 1, yghost, south, 0, cart2d, status ); 69 // shift southward 70 MPI_Sendrecv( sbuf_s, 1, yghost, south, 0, 71 rbuf_s, 1, yghost, north, 0, cart2d, status );

jacobi2d5p.c

3. Y軸方向の通信

184

southward Self

yghost

yghost

rbuf_s

sbuf_s

buffers

recv

south

north

send

northward Self

yghost

yghost

sbuf_n

rbuf_n

buffers

send

recv

south

north

Page 186: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

59 void *sbuf_e = &(phi[nx][1]); void *rbuf_e = &(phi[ 0][1]); 60 void *sbuf_w = &(phi[ 1][1]); void *rbuf_w = &(phi[nx+1][1]); 72 // shift eastward 73 MPI_Sendrecv( sbuf_e, 1, xghost, east, 0 74 rbuf_e, 1, xghost, west, 0, cart2d, status ); 75 // shift westward 76 MPI_Sendrecv( sbuf_w, 1, xghost, west, 0, 77 rbuf_w, 1, xghost, east, 0, cart2d, status );

jacobi2d5p.c

4. X軸方向の通信

185

eastward

xg

ho

st

xg

ho

st

sbuf_e rbuf_e buffers

send

west

recv

Self east

westward

xg

ho

st

xg

ho

st

rbuf_w sbuf_w buffers

recv

west

send

Self east

Page 187: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

67 // shift northward 68 MPI_Isend( sbuf_n, 1, yghost, north, 0, cart2d, &(req[0]) ); 69 MPI_Irecv( rbuf_n, 1, yghost, south, 0, cart2d, &(req[1]) ); 70 // shift southward 71 MPI_Isend( sbuf_s, 1, yghost, south, 0, cart2d, &(req[2]) ); 72 MPI_Irecv( rbuf_s, 1, yghost, north, 0, cart2d, &(req[3]) ); 73 // shift eastward 74 MPI_Isend( sbuf_e, 1, xghost, east, 0, cart2d, &(req[4]) ); 75 MPI_Irecv( rbuf_e, 1, xghost, west, 0, cart2d, &(req[5]) ); 76 // shift westward 77 MPI_Isend( sbuf_w, 1, xghost, west, 0, cart2d, &(req[6]) ); 78 MPI_Irecv( rbuf_w, 1, xghost, east, 0, cart2d, &(req[7]) );

jacobi2d5poverlap.c

5点差分(通信隠蔽有り)

• カーテシアン・トポロジと派生データ型は隠蔽無しと同じ

• 通信を隠蔽するために非閉塞通信を使い MPI_Waitall で完了する

• 完了するまでの間に領域内部の計算を行う

• 通信完了後に領域境界の計算を行う

1. Y-X軸方向の通信

186

Page 188: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

80 // Jacobi iteration, interior 81 for( int i=2; i<=nx-1; ++i ) 82 for( int j=2; j<=ny-1; ++j ) 83 w[i][j] = 0.25*( phi[i+1][j ] + phi[i-1][j ] 84 phi[i ][j+1] + phi[i ][j-1] – h*h*f[i][j] ); 85 86 MPI_Waitall( 8, req, status );

jacobi2d5poverlap.c

2. 領域内部の計算と通信の完了

内部点

Y軸境界点

X軸境界点

計算領域の分類

0 1 2 ... nx nx+1 0

1

2

ny

ny+1

内部点のループ

187

Page 189: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

88 // Jacobi iteration, fringe 89 const int jn = ny, js = 1; 90 for( int i=1; i<=nx; ++i ) 91 { 92 w[i][jn] = 0.25*( phi[i ][jn+1] + phi[i ][jn-1] 93 phi[i+1][jn ] + phi[i-1][jn ] – h*h*f[i][jn] ); 94 w[i][js] = 0.25*( phi[i ][js+1] + phi[i ][js-1] 95 phi[i+1][js ] + phi[i-1][js ] – h*h*f[i][js] ); 96 } 97 const int ie = nx, iw = 1; 98 for( int j=2; j<=ny-1; ++j ) 99 { 100 w[ie][j] = 0.25*( phi[ie ][j+1] + phi[ie ][j-1] 101 phi[ie+1][j ] + phi[ie-1][j ] – h*h*f[ie][j] ); 102 w[iw][j] = 0.25*( phi[iw ][j+1] + phi[iw ][j-1] 103 phi[iw+1][j ] + phi[iw-1][j ] – h*h*f[iw][j] ); 104 }

jacobi2d5poverlap.c

3. 領域境界の計算

X軸境界点

Y軸境界点

188

Page 190: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

62 // initialize persistent sends 63 MPI_Request req[8]; 64 MPI_Ssend_init( sbuf_n, 1, yghost, north, 0, cart2d, &(req[0]) ); 65 MPI_Ssend_init( sbuf_s, 1, yghost, south, 0, cart2d, &(req[1]) ); 66 MPI_Ssend_init( sbuf_e, 1, xghost, east, 0, cart2d, &(req[2]) ); 67 MPI_Ssend_init( sbuf_w, 1, xghost, west, 0, cart2d, &(req[3]) ); 68 MPI_Recv_init( rbuf_n, 1, yghost, south, 0, cart2d, &(req[4]) ); 69 MPI_Recv_init( rbuf_s, 1, yghost, north, 0, cart2d, &(req[5]) ); 70 MPI_Recv_init( rbuf_e, 1, xghost, west, 0, cart2d, &(req[6]) ); 71 MPI_Recv_init( rbuf_w, 1, xghost, east, 0, cart2d, &(req[7]) );

jacobi2d5ppersistent.c

5点差分(持続通信)

• 前例とほとんど同じ

• 最初に送受信リクエストを作成しておく

• 通信は Startall で開始し Wailall で完了させる

1. 送受信リクエストの作成

• メモリコピーを回避するためここでは Synchronous send を使う

2. Y-X軸方向の通信

77 // start persistent sends 78 MPI_Startall( 8, req );

189

Page 191: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

9点差分(通信隠蔽無し)

1. コミュニケータの定義は5点差分と同じ 2. 派生データ型は xghost を y 軸の全領域とする 3. この派生データ型の場合はY-Xの順で逐次的に通信する

190

49 // define derived datatypes 50 MPI_Datatype xghost, yghost; 51 MPI_Type_vector( 1, ny+2, ny+2, MPI_FLOAT, &xghost ); 52 MPI_Type_vector( nx, 1, ny+2, MPI_FLOAT, &yghost ); 53 MPI_Type_commit( &xghost ); 54 MPI_Type_commit( &yghost );

jacobi2d9p.c

nx

yghost xghost

ny+2 ny+2 ny+2

1

1

strid

e

strid

e

count count

blo

ck

len

gth

blo

ck

len

gth

Page 192: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

56 // send buffers // recv buffers 57 void *sbuf_n = &(phi[1][ny]); void *rbuf_n = &(phi[1][ 0]); 58 void *sbuf_s = &(phi[1][ 1]); void *rbuf_s = &(phi[1][ny+1]); 66 // shift northward 67 MPI_Sendrecv( sbuf_n, 1, yghost, north, 0 68 rbuf_n, 1, yghost, south, 0, cart2d, status ); 69 // shift southward 70 MPI_Sendrecv( sbuf_s, 1, yghost, south, 0, 71 rbuf_s, 1, yghost, north, 0, cart2d, status );

jacobi2d9p.c

3. Y軸方向の通信

191

southward Self

yghost

yghost

rbuf_s

sbuf_s

buffers

recv

south

north

send

northward Self

yghost

yghost

sbuf_n

rbuf_n

buffers

send

recv

south

north

Page 193: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

59 void *sbuf_e = &(phi[nx][0]); void *rbuf_e = &(phi[ 0][0]); 60 void *sbuf_w = &(phi[ 1][0]); void *rbuf_w = &(phi[nx+1][0]); 72 // shift eastward 73 MPI_Sendrecv( sbuf_e, 1, xghost, east, 0 74 rbuf_e, 1, xghost, west, 0, cart2d, status ); 75 // shift westward 76 MPI_Sendrecv( sbuf_w, 1, xghost, west, 0, 77 rbuf_w, 1, xghost, east, 0, cart2d, status );

jacobi2d9p.c

4. X軸方向の通信

192

eastward

xg

ho

st

xg

ho

st

sbuf_e rbuf_e buffers

send

west

recv

Self east

westward

xg

ho

st

xg

ho

st

rbuf_w sbuf_w buffers

recv

west

send

Self east

Page 194: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

具体的な問題への応用

1. 構造格子系(差分法)

2. 非構造格子系(有限要素法,有限体積法)

3. フーリエ変換

4. MPI Tips

193

Page 195: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

具体的な問題への応用

1. 構造格子系(差分法)

2. 非構造格子系(有限要素法,有限体積法)

3. フーリエ変換

4. MPI Tips

194

Page 196: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

2次元フーリエ変換

195

• 2次元転置(2D transpose) 16 プロセスの場合

Transpose

Y to X

16 by 16

all-to-all

・配列全体をX軸で分割 ・配列全体をY軸で分割

・添字を巡回置換 (i-j⇒j-i)

x

y

Y FFT

A[i][j]

x

y

X FFT

B[j][i]

Page 197: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Transpose

ZY to YX

• 2次元転置(2D transpose)

Z-Y FFT X FFT

16 by 16

all-to-all

3次元フーリエ変換

196

x

z y

x

z y

A[i][j][k] B[j][k][i]

・配列全体をX軸で分割 ・配列全体をZ軸で分割

・添字を左巡回置換 (i-j-k⇒j-k-i)

16 プロセスの場合

Page 198: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Z FFT

Y FFT

X FFT

Transpose Z to Y

• 3次元転置(3D transpose)

部分コミュニケータ Cyz0 Cyz1 Cyz2 Cyz3

Cxy3

Cxy2

Cxy1

Cxy0

4 by 4 all-to-all を同時に4つ

部分コミュニケータ

197

x

z y

x

z y

x

z y

x

z y

A[i][j][k]

B[k][i][j]

C[j][k][i]

・配列全体をX軸で分割 ・添字を右巡回置換 (i-j-k⇒k-i-j)

・添字を右巡回置換 (k-i-j⇒j-k-i)

コミュニケータ切換え

Transpose Y to X

4 by 4 all-to-all を同時に4つ

・配列全体をY軸で分割

16 プロセスの場合

Page 199: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

具体的な問題への応用

1. 構造格子系(差分法)

2. 非構造格子系(有限要素法,有限体積法)

3. フーリエ変換

4. MPI Tips

198

Page 200: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

MPI通信の心得

1. 集団通信を使う ⇒ 通信手順の最適化

2. トポロジを使う ⇒ コミュニケータの最適化

3. 派生データ型を使う ⇒ メモリコピー削減 (システムによって悪くなる場合もある)

4. データはまとめて通信する ⇒ 回数削減, 長サイズ化

5. データ量の均一化 (BSP*の場合) ⇒ 無駄な待ち時間回避

*The MPE Multiprocessing Environment, Appendix C, Using MPI, 2nd ed., MIT Press, 1999 *http://www.mcs.anl.gov/research/projects/perfvis/download/

199 *Bulk Synchronous Parallel: barrierで計算と通信を分離する並列化手法

Page 201: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

Appendix A

MPE(Multi-Processing Environment) Library

MPICHの開発グループが提供するユーティリティー群

(他のMPIライブラリからも利用可能)

以下の機能が提供されている

• Logging routines

• X window graphics

• Sequential section

• Shared counter

• Tag management

• Miscellaneous

Logging routines は性能プロファイリングに利用される

それ以外の機能はほとんど使われない

*The MPE Multiprocessing Environment, Appendix C, Using MPI, 2nd ed., MIT Press, 1999 *http://www.mcs.anl.gov/research/projects/perfvis/download/

200

Page 202: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

#include “mpi.h” #include “mpe.h” MPI_Init( &argc, &argv); MPE_Init_log(); const int bgnID = 1; const int endID = 2; MPE_Describe_state(bgnID, endID, “Bcast”, “red:vlines3”); MPE_Log_event(bgnID, 0, “start”); // target section MPI_Bcast etc. MPE_Log_event(endID, 0, “stop”); MPE_Finish_log(“test.log”); MPI_Finalize();

Logging routinesの基本的な使い方

ヘッダファイルをインクルード

ログ取得開始

ログ取得終了, ファイル書出し

計時開始

計時終了

MPE_Describe_stateで計測領域の開始ID:bgnID,終了ID:endID, 領域名:“Bcast”,表示パターン:“red:vlines3” を定義する

ID番号は重複してはならない

201

Page 203: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

SLOG-2形式のファイルを可視化するプログラム

下図のようにプロセス毎のタイムライン等を表示できる

Jumpshot-3 Visualization Program

202

実際には100プロセス・100秒程度まで それ以上は画面スクロール等の操作が困難

Page 204: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

• Ubuntuのsynaptic(apt)は未だv1.6.5なので手動でインストール (注:既にMPIライブラリがインストールされている場合は完全にアンインストールしておく)

• 圧縮ファイル(openmpi-2.0.1.tar.gz)を

https://www.open-mpi.org/software/ompi/v2.0/ からダウンロード

• configureの質問はPCなら基本的にデフォルト設定

並列機の場合は色々設定する必要あり

• 作業には数時間~半日程度必要なこともある

• 最後の ldconfig はパスを通すため (注: ldconfigの前に/etc/ld.so.conf.d/libc.confの存在を確認しておく)

> tar xvf openmpi-2.0.1.tar.gz > cd openmpi-2.0.1 > sudo ./configure --prefix=/usr/local > sudo make all install > sudo ldconfig

Appendix B

Open MPI version 2.0.1のインストール方法

203

Page 205: 並列プログラミング入門( 編) · Magna Carta 1215 (The British Library, UK) ... 1.2 Jul ‘97 1.3 May ‘08 2.0 Jul ‘97 2.1 Jun ‘08 2.2 Sep ‘09 3.0 Sep ‘12 3.1

204

並列プログラミング入門(MPI編) はこれで終了です

お疲れ様でした