KOBE HPC サマースクール 2022

2022/8/31

KOBE HPC サマースクール 2022（初級）8. 分散メモリ型並列計算機とは何か？
－ SPMDプログラミングによる Hello World!

2022/8/31

1

KOBE HPC サマースクール 2022

並列計算機のアーキテクチャ
並列計算機
複数のプロセッサ（ノイマン・アーキテクチャ）が，何らかの方法で接続されていて，協調して動作する計算機システム

タイプ
SIMD と MIMD（Flynn の分類, 1966年）
命令実行の流れとデータの流れに着目した分類方法

プロセッサ（P），プロセッサエレメント（PE），プロセッサユ
ニット（PU），ノード（Node），コア（core）

共有メモリ型と分散メモリ型
メモリ空間に着目した分類方法
ホモジニアス型とヘテロジニアス型
ハードウェアの均質性に着目した分類方法

2022/8/31

KOBE HPC サマースクール 2022

2

1

KOBE HPC サマースクール 2022

2022/8/31

共有メモリ型並列計算機
複数のプロセッサ（PE）が，単一のメモリ空間を共有
どの PE も同じメモリ領域にアクセス可能

PE0PE1PEn

バス，またはネットワーク

特徴
メモリ空間が単一なので，プログラミングが容易
PE の数が多いと，同一メモリアドレスへのアクセス競合が生じ，性能が低下

メモリ

プログラミング方法
OpenMP，または自動並列化
ただし，MPIプログラムを実行することも可能

2022/8/31

3

KOBE HPC サマースクール 2022

分散メモリ型並列計算機
複数のプロセッサがネットワークで接続されており，それぞれのプロセッサ（PE）が，メモリを持っている．
各PE が自分のメモリ領域のみアクセス可能
特徴
数千から数万PE規模の並列システムが可能
PE の間のデータ分散を意識したプログラミングが必要．

PE0

PE1

PEn

メモリ

メモリ

メモリ

インターコネクト・ネットワーク

プログラミング方法
メッセージ・パシング・インターフェイス（MPI）によるプログラ
ミング

2022/8/31

KOBE HPC サマースクール 2022

4

2

KOBE HPC サマースクール 2022

2022/8/31

メッセージ・パッシング・インターフェイス（MPI）
Message Passing Interface (MPI) とは．．．
複数の独立したプロセス間で，並列処理を行うためのプロセス間メッセージ通信の標準規格1992年頃より米国の計算機メーカ，大学などを中心に標準化
MPI規格化の歴史
1994 MPI-1.0
1997 MPI-2.0（一方向通信など）
2012 MPI-3.0
http://www.mpi-forum.org/docs/mpi-3.0/mpi30-report.pdf

2022/8/31

5

KOBE HPC サマースクール 2022

MPIプログラミング（SPMD）のイメージ
それぞれの人が，本棚に一連のノートを持っている．
それぞれの人には，名前が付いている（人を区別できる）．
ノートには同じ名前が付けられているが，中身は違っている．

本棚のノートに対し，それぞれの人が，読んだり書いたり…

【必要な情報】
ノートの名前何冊
誰に荷物のタグなど

大体は同じ作業をするが，最初のノートの中身が違うので，中身はそれぞれ違う．
ある人に，他の人とは違う作業をさせたい場合には，名前で作業と指示してあげる．

時々，他の人のノートを見たい．
相手にノートの中身を送ってあげる．
送られた人は，それを違う名前のノートに中身を書き写す．
2022/8/31

KOBE HPC サマースクール 2022

63

KOBE HPC サマースクール 2022

2022/8/31

MPIの実行モデル：SPMD（Single Program, Multiple Data)
複数のプロセスにより並列実行
実行開始から終了まで，全プロセスが同じプログラムを実行
各MPIプロセスは固有の番号（ランク番号）を持つ
P個のプロセスで実行する場合，プロセス番号は 0 から (P-1) までの整数
各プロセスで処理を変えたいときは，ランク番号を使った分岐により，各プロセスの処理を記述する．
実行開始

rank=0プロセス

a.out

rank=1プロセス

rank=2プロセス

a.out

rank=3
プロセス

a.out

並列実行部分a.out
実行終了

2022/8/31

7

KOBE HPC サマースクール 2022

MPIの実行モデル（続き）
複数のプロセスにより並列実行
実行開始から終了まで，全プロセスが同じプログラムを実行
各MPIプロセスは固有の番号（ランク番号）を持つ⇒ ある単一の MPIプログラムを実行するとき，各プロセスが処理する内容を頭の中でイメージ（頭の中で動作をシミュレート）することが重要
calc0();
if( rank == 0 ) {calc1();} else { /*if( rank == 1)*/
calc2();}
calc3();

実行開始

rank=0プロセス

rank=1
プロセス

calc0

calc0

calc1

calc2

calc3

calc3

KOBE HPC サマースクール 2022

calc0();
calc1();
calc3();
 プロセス1

実行終了
2022/8/31

 プロセス0

calc0();
calc2();
calc3();
84

KOBE HPC サマースクール 2022

2022/8/31

MPIの実行モデル（続き）
メモリ空間
プロセスごとに独立したメモリ空間を保持プログラム中で定義された変数や配列は，同じ名前で独立に各プロセスのメモリ上に割り当てられる．
同じ変数や配列に対して，プロセスごとに違う値を与えることが可能
他のプロセスの持つ変数や配列には，直接にアクセスできない．

実行開始

rank=0プロセス

a.out

rank=1
プロセス

int k;
double x[100];

int k;
double x[100];

直接にアクセス不可能

k = 138x[62] = 4.254

a.out

k = 5478
x[62] = 2847.45

実行終了
2022/8/31

9

KOBE HPC サマースクール 2022

MPIの実行モデル（続き）
プロセス間通信
他のプロセスの持つ変数や配列のデータにアクセスできない．
⇒ プロセス間通信によりデータを送ってもらう．
メッセージパッシング方式：メッセージ（データ）の送り手と受け手
この方式によるプロセス間通信関数の集合 ≒ MPI
実行開始

rank=0プロセス
データを送る（例：MPI_Send)a.out

rank=1
プロセス

int k;
double x[100];

MPI関数によるプロセス間通信
2022/8/31

KOBE HPC サマースクール 2022

a.out
int k;
double x[100];

データを受取る（例：MPI_Recv)
実行終了
105

KOBE HPC サマースクール 2022

2022/8/31

MPIプログラムのスケルトン#include <stdio.h>#include <mpi.h>

MPIモジュールの取り込み（おまじない1）

int main(int argc, char **argv){
int nprocs, myrank;

MPIで使う変数の宣言
MPIの初期化（おまじない2）
MPIで使うプロセス数を nprocs に取得
自分のプロセス番号を myrank に取得

MPI_Init( &argc, &argv );MPI_Comm_size( MPI_COMM_WORLD, &nprocs );MPI_Comm_rank( MPI_COMM_WORLD, &myrank );(この部分に並列実行するプログラムを書く）

MPIの終了処理（おまじない3）

MPI_Finalize() ;return 0 ;}

 それぞれのプロセスで異なった処理をする場合は，myrankの値で場合分けし，うまく仕事が振り分けられるようにする（後出）．
2022/8/31

KOBE HPC サマースクール 2022

11

MPIプログラムの基本構成
int MPI_Init( int *argc, char ***argv )MPIの初期化を行う．MPIプログラムの最初に必ず書く．
int MPI_Comm_size( MPI_Comm comm, int *nprocs )MPIの全プロセス数を取得し，2番目の引数 nprocs（整数型）に取得する．
MPI_COMM_WORLDはコミュニケータと呼ばれ，最初に割り当てられるすべてのプロセスの集合
int MPI_Comm_rank( MPI_Comm comm, int *myrank )自分のプロセス番号（0からnprocs-1のどれか）を，2番目の引数 myrank（整数型）に取得する．
int MPI_Finalize(void)

MPIの終了処理をする．MPIプログラムの最後に必ず書く．

2022/8/31

KOBE HPC サマースクール 2022

126

KOBE HPC サマースクール 2022

2022/8/31

MPIプログラム（hello_mpi.c）： Hello, world!
#include <stdio.h>#include <mpi.h>
int main( int argc, char **argv ){int nprocs, myrank ;MPI_Init( &argc, &argv );MPI_Comm_size( MPI_COMM_WORLD, &nprocs );MPI_Comm_rank( MPI_COMM_WORLD, &myrank );printf (“Hello, World! My rank number and nprocs are %d and %d.\n", myrank, nprocs);
MPI_Finalize();
return 0;}2022/8/31

KOBE HPC サマースクール 2022

13

県立大 Rokko システムの SGI版MPI を使う手順
環境設定:インテルコンパイラ，SGI版MPI を使えるようにする．
$$

module load intel
module load mpt$

icc prog.c -lmpi

コンパイル方法（アイ シー シー：prog.cはコンパイルしたいプログラムのファイル名

prog.c ハイフン(-) エル エム ピー アイ）

バッチジョブ・スクリプト:ファイル名は 「***.sh」（たとえば jobm.sh など）としておくと良い#!/bin/bash#PBS -q S#PBS -l select=1:ncpus=2:mpiprocs=2#PBS -N hello#PBS -j oesource /etc/profile.d/modules.shmodule load intel
module load mpt
cd ${PBS_O_WORKDIR}
mpiexec_mpt -np XX dplace –s1 ./a.out
2022/8/31

select:ノード数，ncpus:ノード内コア数
MPIだけの並列プログラム実行の場合はncpus と mpiprocs の値は同じにする．
helloは，出力ファイルヘッダ

XX: MPI並列数-np XX を指定しない場合は，スクリプトの値が使われる．

KOBE HPC サマースクール 2022

147

KOBE HPC サマースクール 2022

2022/8/31

演習8-1：Hello, world! を並列に出力する．
MPI版 “Hello, world!” を 2，4，及び8プロセスで実行し，結果を確認せよ！ 以下は実行例．
$$

mkdir␣MPI
cd␣MPI

今日の演習用のディレクトリを作成する．
※ ␣はスペースを表わす．

$$

mkdir␣M-1
cd␣M-1

演習M-1用のディレクトリを作成する．

$

cp␣/home/guest60/share/hello_mpi.c␣./

ソースプログラム hello_mpi.c をカレントディレクトリにコピーする．
※ 中身を見て，プログラムを確認すること．

$

icc␣hello_mpi.c␣-lmpi

ソースプログラムをコンパイル$

cp␣/home/guest60/share/jobm.sh␣./

ジョブスクリプト jobm.sh をコピーする．
（プロセス数の指定など，必要な部分をeditする）$ qsub␣jobm.sh
nnnnnn.rokko1

ジョブを投入し，実行結果を確認する．
※ nnnnnn はジョブ番号$※ hello は，jobm.sh内で指定した jobname のこと

cat␣hello.onnnnn

2022/8/31

KOBE HPC サマースクール 2022

15

プログラム M-1の実行結果の確認
２プロセスでの実行結果
Hello, world!
Hello, world!

My rank number and nprocs are 0, 2.
My rank number and nprocs are 1, 2.

４プロセスでの実行結果
Hello, world!
Hello, world!
Hello, world!
Hello, world!

My rank number and nprocs are 2, 4.
My rank number and nprocs are 0, 4.
My rank number and nprocs are 3, 4.
My rank number and nprocs are 1, 4.

（注意）出力はランク順に並ぶとは限らず，また，実行ごとに出力の順番が異なることがある．

ポイント•各プロセスが同じプログラムを実行している．
•各プロセスが持っているランク番号（myrankの値）が異なっている．
2022/8/31

KOBE HPC サマースクール 2022

168

KOBE HPC サマースクール 2022

2022/8/31

2プロセス時の変数の値（SPMD）
メモリ空間
プロセスごとに独立したメモリ空間を保持プログラム中で定義された変数や配列は，同じ名前で独立に各プロセスのメモリ上に割り当てられる．
同じ変数や配列に対して，プロセスごとに違う値を与えることが可能

実行開始

rank=0プロセス

rank=1
プロセスa.out
int myrank;
int nprocs;

myrank = 0nprocs = 2

a.out
int myrank;
int nprocs;

myrank = 1
nprocs = 2
実行終了

2022/8/31

KOBE HPC サマースクール 2022

17

参考：Fortran版

2022/8/31

KOBE HPC サマースクール 2022

189KOBE HPC サマースクール 2022

2022/8/31

MPIプログラムのスケルトン
program mainuse mpi
implicit none

MPIモジュールの取り込み（おまじない1）

integer :: nprocs, myrank, ierr

MPIで使う変数の宣言

call mpi_init( ierr )call mpi_comm_size( MPI_COMM_WORLD, nprocs, ierr )call mpi_comm_rank( MPI_COMM_WORLD, myrank, ierr )MPIの初期化（おまじない2）
MPIで使うプロセス数を nprocs に取得
自分のプロセス番号を myrank に取得(この部分に並列実行するプログラムを書く）
call mpi_finalize( ierr )MPIの終了処理（おまじない3）

end program main それぞれのプロセスが何の計算をするかは，myrank の値で場合分けし，うまく仕事が振り分けられるようにする．

2022/8/31

KOBE HPC サマースクール 2022

19

MPIプログラムの基本構成（説明）call mpi_init( ierr )MPI の初期化を行う．MPIプログラムの最初に必ず書く．
call mpi_comm_size( MPI_COMM_WORLD, nprocs, ierr )MPI の全プロセス数を取得し，2番目の引数 nprocs（整数型）に取得する．
MPI_COMM_WORLD はコミュニケータと呼ばれ，最初に割り当てられるすべてのプロセスの集合
call mpi_comm_rank( MPI_COMM_WORLD, myrank, ierr )自分のプロセス番号（0からnprocs-1のどれか）を，2番目の引数 myrank（整数型）に取得する．
call mpi_finalize( ierr )MPI の終了処理をする．MPIプログラムの最後に必ず書く．

2022/8/31

KOBE HPC サマースクール 2022

2010

KOBE HPC サマースクール 2022

2022/8/31

プログラム（hello_mpi.f90） の説明
program hello_by_mpi（おまじない）MPI用のモジュールをインクルード

use mpi
implicit none
integer :: nprocs, myrank, ierr

（おまじない）MPI の初期化
MPI で使うプロセス数を nprocs に取得
自分のプロセス番号を myrank に取得

call mpi_init( ierr )call mpi_comm_size( MPI_COMM_WORLD, nprocs, ierr )call mpi_comm_rank( MPI_COMM_WORLD, myrank, ierr )print *, 'Hello, world!

My rank number and nprocs are', myrank, ',',

nprocscall mpi_finalize( ierr )各プロセスで myrank と nprocs を出力する．
※ myrank はプロセスごとに異なる※ nprocs はすべてのプロセスで同じ（おまじない）
MPIの終了処理

end program hello_by_mpi

2022/8/31

KOBE HPC サマースクール 2022

21

演習8-1：Hello, world! を並列に出力する．
MPI版 “Hello, world!” を 2，4，及び8プロセスで実行し，結果を確認せよ！ 以下は実行例．
$$

mkdir␣MPI
cd␣MPI$$

mkdir␣M-1
cd␣M-1$cp␣/home/guest60/share/hello_mpi.f90␣./

ソースプログラム hello_mpi.c をカレントディレクトリにコピーする．
※ 中身を見て確認すること．

$

ifort␣hello_mpi.f90␣-lmpi

ソースプログラムをコンパイル$

cp␣/home/guest60/share/jobm.sh␣./

ジョブスクリプト jobm.sh をコピーする．
（プロセス数の指定など，必要な部分をeditする）

今日の演習用のディレクトリを作成する．
※ ␣はスペースを表わす．
スペース

演習M-1用のディレクトリを作成する．

$ qsub␣jobm.sh
nnnnnn.rokko1

ジョブを投入し，実行結果を確認する．
※ nnnnnn はジョブ番号$※ hello は，jobm.sh内で指定した jobname のこと

cat␣hello.onnnnn

2022/8/31

KOBE HPC サマースクール 2022

2211