openmp でマルチコア 並列 プログラミングtau/lecture/computer_software/... ·...

28
OpenMP でマルチコア (並列) プログラミング 田浦健次朗 1 / 28

Upload: others

Post on 18-Oct-2019

1 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

OpenMP でマルチコア (並列)プログラミング

田浦健次朗

1 / 28

Page 2: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

並列プログラミングの必要性

▶ いまどきの計算機にはことごとく, 複数の CPU (コア) が搭載れている

▶ 普通にプログラムを書いただけでは, その内の一つのCPU しか使われない

▶ 複数の CPU を使うプログラム (並列プログラム) を書いてみよう

2 / 28

Page 3: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

CPU の数の確かめ方 (Linux)▶ 方法 1: /proc/cpuinfo を見る�1 $ cat /proc/cpuinfo

▶ 方法 2 (GUI): パネル上の system load indicator → 右クリック → 「システムモニタを開く」

▶ 方法 3: hwloc-ls コマンド (おそらくインストールが必要)�1 $ hwloc-ls

インストール:�1 $ sudo apt-get install hwloc

▶ 方法 4: htop コマンド (おそらくインストールが必要)�1 $ htop

3 / 28

Page 4: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

CPU を「数える」時の (ややこしい) 用語▶ 仮想コア, ハードウェアスレッド ⊂ (物理) コア ⊂ チップ

▶ チップ: 物理的なチップの数. ラップトップは普通 1 個▶ (物理) コア: 一チップ内に複数 (今は 2-8 程度) 搭載.命令デコーダ, 演算器などを一揃い揃えたもの.

▶ 仮想コア: 一つの物理コア内に複数 (今は 1-2 程度) 搭載. 命令デコーダを独立に持っている.

▶ ソフトウェア (/proc/cpuinfo, hwlos, etc.) から見える“CPU” ≈ 仮想コア

▶ 物理的に「CPU」というとチップを指すことが多い (ややこしい…)

memory

controller L3 cache

hardware thread

(virtual core, CPU)

(physical) core

L2 cacheL1 cache

chip (socket, node, CPU)

4 / 28

Page 5: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

並列プログラミング

やり方は色々▶ OS が直接提供するインタフェース

▶ プロセス (プログラムを複数立ち上げる)▶ スレッド (Pthread)

▶ 言語▶ OpenMP (← 今回はこれ)▶ Cilk

▶ ライブラリ▶ Intel Threading Building Block

5 / 28

Page 6: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

OpenMP の使い方

1. C/C++ プログラムに並列化の 「並列化指示 (ディレクティブ, API 呼び出し)」を挿入

2. gcc でコンパイルするときに -fopenmp オプションを与える�

1 $ gcc -fopenmp program.c

3. 基本はこれだけ!4. 以降「並列化指示」の構文, 使い方を説明する

6 / 28

Page 7: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

先に例を見せておく▶ クイックソートの再帰呼び出しを並列に行う例▶ 変更は赤字部分を追加するだけ�

1 /* a[l:r]を整列 */2 void qs(K * a, long l, long r) {3 if (r - l <= 1) return;4 else {5 /* 「ある値」以下を左へ, より大きいのを右へ */6 long c = partition(a, l, r);7

8 qs(a, l, c-1); /* 左を整列 */9 qs(a, c, r); /* 右を整列 */

10

11 }12 }

7 / 28

Page 8: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

先に例を見せておく▶ クイックソートの再帰呼び出しを並列に行う例▶ 変更は赤字部分を追加するだけ�

1 /* a[l:r]を整列 */2 void qs(K * a, long l, long r) {3 if (r - l <= 1) return;4 else {5 /* 「ある値」以下を左へ, より大きいのを右へ */6 long c = partition(a, l, r);7 #pragma omp task if (r - l > 100)8 qs(a, l, c-1); /* 左を整列 */9 qs(a, c, r); /* 右を整列 */

10 #pragma omp taskwait11 }12 }

8 / 28

Page 9: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

覚えるべき構文

▶ #pragma omp parallel▶ #pragma omp master▶ #pragma omp task▶ #pragma omp taskwait▶ #pragma omp for

正式な情報源:▶ http://openmp.org/ → OpenMP Specifications▶ OpenMP Specifications ページに日本語訳もあり▶ 書籍: 日本語も含め多数

9 / 28

Page 10: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

指示文の構文: 共通事項

▶ C/C++ 構文を拡張するのではなく, C/C++ の文を修飾する指示文 (directive, pragma)

▶ 指示文は #pragma omp …という文法. 例:�1 #pragma omp parallel2 文

▶ 一部, 関数もある

10 / 28

Page 11: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

parallel (仕様書 2.4)

▶ これがなくては何も始まらない▶ 構文:�1 #pragma omp parallel2 S

▶ 意味: S (parallel の直下に書かれた文) を, 参加する全てのCPU が実行

S S S S

...

...

11 / 28

Page 12: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

parallel : 例 1�1 #include <stdio.h>2 int main() {3 printf("main\n");4 #pragma omp parallel5 printf("worker\n");6 }�1 $ gcc -fopenmp hellopmp.c2 $ ./a.out3 main4 worker5 worker6 worker7 worker

12 / 28

Page 13: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

OpenMP の基本的な実行モデル▶ プログラム開始時は一 CPU だけで実行されている (「逐次」領域)

▶ pragma omp parallel に遭遇すると, 「並列領域 (「全 CPU が」実行するモード)」に移行; 全 CPUが「直下の一文」を実行する; 終わったらまた逐次領域に戻る

▶ 直下の一文と言っても複合文, 関数呼び出しを含むなど, 実際にはいくらでも「長い」部分を並列領域にできる

▶ ここで並列領域に参加しているCPU を「チーム」と呼ぶ

S S S S

...

...

13 / 28

Page 14: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

parallel : 例 2

�1 #include <stdio.h>2 int main() {3 printf("main\n");4 #pragma omp parallel5 parallel_main();6 }

▶ real_main の中身 (したがってプログラムのほぼ全て) を全 CPU が実行する

14 / 28

Page 15: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

OMP_NUM_THREADS

▶ プログラム実行時に環境変数 OMP_NUM_THREADS を指定すると, 並列領域で用いる CPU 数を指定できる

▶�1 $ gcc -fopenmp hellopmp.c2 $ OMP_NUM_THREADS=2 ./a.out3 main4 worker5 worker

15 / 28

Page 16: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

master (仕様書 2.8)

▶ 構文�1 #pragma omp master2 S

▶ 意味: S を, (並列領域内であっても) ただひとつの CPU (その並列領域を生んだ CPU) だけが実行する

▶ 何の役に立つ? 後でわかる

...

...

#pragma omp

S

16 / 28

Page 17: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

parallel, master : 例�

1 #include <stdio.h>2 int main() {3 printf("main\n");4 #pragma omp parallel5 {6 printf("para 1\n");7 #pragma omp parallel8 printf("master\n");9 printf("para 2\n");

10 }11 }

�1 $ OMP_NUM_THREADS=2 ./a.out2 main3 para 14 master5 para 26 para 17 para 2

17 / 28

Page 18: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

parallel だけではろくな事はできない

▶ parallelだけでは「全 CPU に同じ事をやらせる」のがせいぜい

▶ チーム内で「仕事を分け合」わなくては意味がない (高速化はしない)

▶ そのための二つの手段▶ pragma for (ループの分割)▶ pragma task, pragma taskwait (タスクの生成)

▶ OpenMP を使う場合, pragma parallel for を使うことが圧倒的に多い

▶ が, 今の我々に重要なのは後者 (task)

18 / 28

Page 19: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

task, taskwait

▶ タスク ≈ 他の CPU に分散させたい処理の単位▶ task 構文 ≈ タスクを作る▶ taskwait 構文 ≈ タスクの終了を待つ

19 / 28

Page 20: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

task (仕様書 2.7)▶ 構文:�1 #pragma omp task2 S

▶ 意味: S を実行する「タスク」を作る ≈ チーム内の暇な CPU を見つけて S を実行

▶ 結果的に�1 #pragma omp task2 S3 C

は, S と C を (並行に) 実行する(かも)

...

...

#pragma task

S #pragma task

TS

T

20 / 28

Page 21: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

taskwait (仕様書 2.8)

▶ 構文:�1 #pragma omp taskwait

▶ 意味: 現タスクから作られたタスクの完了を待つ

21 / 28

Page 22: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

再掲: クイックソートの再帰呼び出しを並列に�

1 /* a[l:r]を整列 */2 void qs(K * a, long l, long r) {3 if (r - l <= 1) return;4 else {5 /* 「ある値」以下を左へ, より大きいのを右へ */6 long c = partition(a, l, r);7 #pragma omp task8 qs(a, l, c-1); /* 左を整列 */9 qs(a, c, r); /* 右を整列 */

10 #pragma omp taskwait11 }12 }

22 / 28

Page 23: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

全体の構成

▶ parallel で, チームを作り▶ master で, そのうち一人だけが qs の実行を開始▶ その中でタスクが作られ, チーム内に負荷分散して行く�

1 int main() {2 #pragma omp parallel3 #pragma omp master4 {5 a = ...6 qs(a, 0, n);7 }8 }

23 / 28

Page 24: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

実行イメージ

▶ qs の再帰呼び出し内でタスクが作られている

▶ タスクも再帰的に (極めて多数) 作られる

▶ OpenMP がそれを「空いている CPU に割り当てて実行」してくれる

...

...

...

...

24 / 28

Page 25: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

実行イメージ

▶ タスクは多数作っても構わないが, あまりにも小さい (少ししか計算をしない) 処理にタスクを作っても利益はない

▶ 少なくとも, 「タスクを作るオーバーヘッド < 処理そのもの」でないと意味がない

▶ task 構文には, 実際にタスクを作るかどうかの条件を書ける�

1 #pragma omp task if (...)

25 / 28

Page 26: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

再再掲: クイックソートの再帰呼び出しを並列に�

1 /* a[l:r]を整列 */2 void qs(K * a, long l, long r) {3 if (r - l <= 1) return;4 else {5 /* 「ある値」以下を左へ, より大きいのを右へ */6 long c = partition(a, l, r);7 #pragma omp task if (r - l > 100)8 qs(a, l, c-1); /* 左を整列 */9 qs(a, c, r); /* 右を整列 */

10 #pragma omp taskwait11 }12 }

26 / 28

Page 27: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

注: そもそも何でも並列化して良いわけではない▶ 以下により, qs(a, l, c-1) と qs(a, c, r) が「並行に」実行され (得) る�

1 #pragma omp task if (r - l > 100)2 qs(a, l, c-1); /* 左を整列 */3 qs(a, c, r); /* 右を整列 */4 #pragma omp taskwait5 }6 }

▶ これが OK (そうやっても結果が変わらない) なのは, 両者の読み書きする領域が重なっていないため

▶ qs(a, l, c-1); → a[l:c-1]▶ qs(a, c, r); → a[c,r]

27 / 28

Page 28: OpenMP でマルチコア 並列 プログラミングtau/lecture/computer_software/... · 並列プログラミングの必要性 いまどきの計算機にはことごとく, 複数のcpu

並列化して良い (ひとつの十分) 条件�1 A;2 B;

を�1 #pragma omp task2 A;3 B;4 #pragma omp taskwait

と書き換えて良いか?

A

B

AB

A;

B;

#pragma omp task

A;

B;

#pragma omp taskwait

ひとつの十分条件は,1. A が書く領域 ∩ B が読むか書く領域 = ∅ かつ2. B が書く領域 ∩ A が読むか書く領域 = ∅

28 / 28