インテル® コンパイラーを使用した
OpenMP* による並列プログラミング
セッション 2: OpenMP* のタスク機能
IA Software User Society (iSUS)
編集長 すがわら きよふみ

このセッションの目的
明示的な並列プログラミング手法として注目されてきた OpenMP* による並列プロ
グラミングに加え、インテル® コンパイラーがサポートする OpenMP* 4.0 と 4.5 の機能を使用したベクトル・プログラミングとオフロード・プログラミングの概要をリフレッシュし、インテル® コンパイラー V19.1 でサポートされる OpenMP* 5.0 の機能と実装を紹介します。さらに新たなアクセラレーター・デバイスへのオフロードについて考えますセッションの対象者
すでに OpenMP* でマルチスレッド・プログラミングを開発し、4.0 以降でサポートされる新たなベクトル化とオフロードを導入し、アプリケーションのパフォーマンス
向上を計画する開発者| 2© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

セッションリスト
セッション

説明

はじめに
(13:35 – 14:20)

異なるバージョンのインテル® コンパイラーや異なるコンパイラー間で OpenMP* を使用する
注意点や制限について説明します

OpenMP* のタスク機能(14:30 – 15:30)

OpenMP* 3.1 で追加されたタスク機能が 4.0 から 4.5 でどのように進化したかを例を使用して説明し、最新の OpenMP* 5.0 で強化された新機能を紹介します

OpenMP* の SIMD 機能(13:30 – 14:30)

OpenMP* のスレッド化機能を使用してプログラマーがマルチスレッドの動作をプログラミン
グしたように、OpenMP* 4.0 からは omp simd を使用してプログラマーが明示的にベクトル化もできるようになりました。OpenMP* simd に関連する機能を 4.0 から 5.0 までの進化を追って紹介します

OpenMP* のオフロード機能(14:30 – 15:30)

OpenMP* 4.0 で追加されたオフロード機能を利用することで、これまで共有メモリー型並列処理に加え分散メモリー型の並列処理を表現できるようになりました。このセッションでは、注目されるヘテロジニアス・プログラミング環境での OpenMP* オフロード機能について説明
します

OpenMP* 5.0 の注目する機能 セッション2、3、4でカバーされなかった OpenMP* 5.0 のそのほかの機能について紹介します
インテル® C++/Fortran コン
パイラーのバージョン 19.1 を使用して GPU オフロードに備えましょう

oneAPI 向けのデータ並列 C++ (DPC++) へ移行する前に、現行のインテル® C++/Fortran コ
ンパイラー V19.1 やインテル® oneAPI HPC ツールキットに含まれるベータ版インテル®
C++/Fortran コンパイラー 2021 を使用して簡単にインテル® グラフィックスへのオフロードを行うソフトウェアを開発および検証方法を紹介します| 3© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

内容
はじめに (OpenMP* が必要とされる背景) と概要(OpenMP* とは、歴史、各バージョンの機能概要)◼ OpenMP* の各バージョンの機能(4.0、4.5 および 5.0 の注目される新機能)◼ 次世代インテル® コンパイラー (nextgen) の機能◼

| 4© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

内容◼

OpenMP* の各バージョンの機能◼ OpenMP* 3.1 の機能を確認◼ OpenMP* 4.0 以降のタスク拡張| 5© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* のバージョン
プログラマーの負担を軽減するオフ
ロード機能の拡張、ヘテロジニアス・プ
ログラミングの機能向上、メモリー管理と同期機能の改善春に 7 つのベンダーと DOE
は並列ループの開発に同意しOpenMP* ARB を組織。10 月にFortran 向けのOpenMP* 仕様
1.0 がリリース

Fortran と C/C++の統合: 統合した
ものは両方の個別の仕様よりも拡大している。
最初の OpenMP*
国際ワークショップが開催される。これにより、ユーザー
がベンダーと対話できる主要な
フォーラムが生まれた

cOMPunity
OpenMP*
ユーザーグループ
が設立され、北米、
欧州、アジアでワークショップを開催

マイナーな修正
1.1

5.0
タスク並列処理導入。OpenMP*
における問題は、タスクの動的特性に対応しつつスレッドベースの特性を維持するのに苦労することだった

C/C++ でmin/max
リダクションをサ
ポート

1.0
2.0

MPI と OpenMP*を使用した最初のハイブリッド・アプリケーションの登場

taskloop、task の優先順位、
doacross ループ、およびロックのヒントをサポート。
非同期オフロードとホスト実行の依存関係をサポート

4.0
4.5

Fortran と C/C++
仕様の統合が開始
される

1.0

1997

3.1

3.0

2.5

アクセラレーター
やコプロセッサー・
デバイスへのオフロード、SIMD
並列処理などをサポート。
OpenMP* の従来の機能を拡張

2.0

1998

1999

2000

2001

2002

2003

2004

2005

2006

2007

2008

2009

2010

2011

2012

2013

2014

2015

…

| 6
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

2018

OpenMP* のコンポーネント (3.1 までとそれ以降)
ディレクティブ

環境変数

ランタイム

◆ ワークシェア◆ スレッドの設定◆ スレッド管理◆ タスク処理◆ スレッドの制御◆ ワークシェア◆ アフィニティー◆ ワークシェア◆ オフロード◆ アフィニティー◆ キャンセル◆ アクセラレーター◆ 同期◆ キャンセル◆ SIMD◆ 操作可能◆ タスク処理◆ アフィニティー◆ アクセラレーター◆ デバイスメモリー◆ キャンセル◆ ロック| 7© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* の実行モデル
◼

◼

◼

◼

OpenMP* プログラムはシングルスレッドで処理を開始: マスタースレッド
ワーカースレッドは並列領域でスポーンされ、マスターとともにスレッドのチームを形成

マスター
スレッド
スレーブ
スレーブ
スレッド
ワーカー
スレッド

シリアル領域
並列領域

スレッド

並列領域の間ではワーカースレッドはスリー
プ状態になる。 OpenMP* ランタイムがすべてのスレッドの動作を管理

シリアル領域

コンセプト: フォークジョイン (fork & join)◼ インクリメンタルな並列処理を許可

並列領域

| 8
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 並列領域: for ワークシェアの例// N=12 を想定#pragma omp parallel#pragma omp for
for(i = 1, i < N+1, i++)c[i] = a[i] + b[i];#pragma omp parallel#pragma omp for

i=1

i=5

i=9

i=2

i=6

i = 10i=3

i=7i = 11i=4

i=8i = 12

暗黙のバリア

スレッドには独立したループ反復が割り当てられる◼ スレッドはワークシェア構文の最後で待機◼

| 9© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 並列領域: sections ワークシェアの例
独立したセクションのコードを同時に実行
実行時間を短縮“非同期実行” で利用される (I/O、オフロードなど)−#pragma omp parallel sections{#pragma omp section
phase1();#pragma omp section
phase2();#pragma omp section
phase3();}

シリアル実行並列実行| 10© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* のリダクション#pragma omp parallel for reduction(+:sum)for(i=0; i<N; i++) {sum += a[i] * b[i];}各スレッドに sum のローカルコピーを作成
sum のすべてのローカルコピーはマージされ、 “グローバル” 変数にストアされるOpenMP* 4.0 と 4.5 でリダクションの概念を拡張: !$OMP SIMD reduction(+:A)- ユーザー定義リダクション- リダクション変数は、もやはスカラーの制限がない

do I=1,25,4
do J=1,8
A(J) = A(J) + B(I,J)*B(I,J)
end doend do| 11© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 並列領域: single ワークシェアとタスク処理#pragma omp parallel
ここで 8 スレッドのプールを作成// 8 スレッドを想定{#pragma omp single private(p){…
1 つのスレッドが while ループを実行
while (p) {#pragma omp task{
processwork(p);“while ループ” を実行するスレッドは、processwork() の}各インスタンス向けにタスクを生成
p = p->next;
}
}
}
| 12
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* の同期
データのアクセス同期◼

◼

atomic 構文、critical 構文、ロックルーチン

実行制御

◼

◼

barrier 句、master 句、single 句、flush 句、暗黙の同期、nowait 節#pragma omp atomic
x += tmp;#pragma omp critical{
x += func(B);}#pragma omp parallel{
int id=omp_get_thread_num();#pragma omp masterA[id] = big_calc1(id);#pragma omp barrier
B[id] = big_calc2(id, A);}| 13© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* のデータ属性◼

データ環境のデフォルト属性を変更:
default(private | none | shared)◼

// private は Fortran のみ

構造内のストレージの属性を変更:
shared, firstprivate, private◼

ループ内のプライベート変数の最後の値をループ外の共有変数に転送:
lastprivate| 14© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

まとめ: ループとリダクションによる pi プログラム#include <omp.h>
static long num_steps = 100000; double x,step;
void main ()スレッドのチームを生成 ... parallel 構文が{int i;
double x, pi, sum = 0.0;
ないと 1 スレッド以上にはなりません
step = 1.0/(double) num_steps;
ループを分割してスレッドに割り当#pragma omp parallel for private(x) reduction(+:sum) てます ... sum へリダクション演算
for (i=0;i< num_steps; i++){を行うよう設定します。
x = (i+0.5)*step;
注意 ... ループ・インデックスはデ
sum = sum + 4.0/(1.0+x*x);
フォルトでスレッドローカルです}pi = step * sum;
並列領域内でテンポラリー値を保持}するため、各スレッドでプライベートのスカラー変数を使用します

OpenMP* 構造を有効にするには、
コンパイルオプションが必要 (/Qopenmp、-qopenmp)| 15© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

内容
OpenMP* の各バージョンの機能◼ OpenMP* 4.0 と 4.5、および 5.0 の新機能
• タスク
• SIMD• オフロード• OpenMP* 5.0 の注目する新機能◼

| 16© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

新しい機能を説明する前に◼

Combine Construct (結合構造)
シーケンス内の複数のプラグマのショートカットとして使用します。結合された構文は、別の構文内で入れ子になった、もう一方の構文を指定するショートカットとなります。結合された構文は、意味的には2番目の構文を含んでいますが、ほかのステートメントを含まない最初の構文を指定するのと同じです
例: #pragma omp parallel for◼

Composite Construct (複合構造)
複合構文は、2つの構文で構成されますが、入れ子になった構文のいずれかを指定す
る同一の意味を持ちません。複合構文では、指定した構文が別々の意味を持ちます
例: #pragma omp parallel for simd

| 17
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* タスクに関する拡張
task、taskwait、taskyield| 18© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

タスクを使用しない OpenMP* ワークシェアの問題
OpenMP* ワークシェア構文が上手く構成されていない問題の例: 並列化された領域からインテル® MKL の dgemm を呼び出す
void example(){#pragma omp parallel{
compute_in_parallel(A);compute_in_parallel_too(B);// dgemm はパラレルもしくはシリアル
cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
m, n, k, alpha, A, k, B, n, beta, C, n);}}

次のいずれかの状態となる:▪ オーバーサブスクライブ (dgemm が内部で並列化されている場合)▪ OpenMP* のオーバーヘッドによるパフォーマンスの低下、または▪ 部分行列に dgemm を適用するため、周辺コードが必要になる| 19© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* の task 構文

4.0

ここまでは
OpenMP* 3.1 の機能

4.5

| 20
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* のタスク処理: 簡単な例

OpenMP* 3.1 の機能#pragma omp parallel
ここで 8 スレッドのプールを作成// 8 スレッドを想定{#pragma omp single private(p){…
1 つのスレッドが while ループを実行
while (p) {#pragma omp task{
processwork(p);“while ループ” を実行するスレッドは、processwork() の}各インスタンス向けにタスクを生成
p = p->next;
}
}
}
| 21
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

タスクによるフィボナッチ数列

OpenMP* 3.1 の機能

int fib ( int n ){int x,y;if ( n < 2 ) return n;#pragma omp task shared(x)x = fib(n-1);#pragma omp task shared(y)y = fib(n-2);#pragma omp taskwait
return x+y;}n は両方のタスクで firstprivate

x と y は共有
最良の解決策sum を計算するため x と y 両方の
値が必要

| 22
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

タスク動作を制御する例

OpenMP* 3.1 の機能#pragma omp task{…

while( (status = omp_test_lock(lock)) != true){ //ロックが取得できるまでループ#pragma omp taskyield…
}

現在のタスクをこの地点で一時停止し、別のタスクの実行に切り替えられることを指示します。このプラグマを使用して、タスク内の特定のポイントで明示的なタスク・スケジュール・ポイントを提供することができます…
omp_unset_lock(lock);}while ループで OpenMP* ロックの取得を待機していますが、タスクは消
費されます
| 23
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 4.0 の機能

task 間の変数の依存関係生成されたタスクの実行順序は不定、参照
する変数に依存関係がある場合、意図する結果が得られないことがあります
タスクが使用する変数を depend 節で依存関係 in、out、inout を指定できるようになりました

フロー依存(out,in)、アンチ依存(in,out)、
出力依存(out,out) を制御

int val=0;
int main(){#pragma omp parallel num_threads(3){#pragma omp single{#pragma omp task depend(out:val)
val = 100;
#pragma omp task depend(inout:val)
val += 1000;}}
printf("Value is %d¥n", val);}| 24© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 4.0 の機能

OpenMP* タスク処理の例: コレスキー分解
void cholesky(int ts, int nt, double* a[nt][nt]) {for (int k = 0; k < nt; k++) {tsnt// 対角ブロック分解
ts
potrf(a[k][k], ts, ts);nt// 三角システムfor (int i = k + 1; i < nt; i++) {#pragma omp task
trsm(a[k][k], a[k][i], ts, ts);}
#pragma omp taskwait
//

}
}

ts

void cholesky(int ts, int nt, double* a[nt][nt]) {for (int k = 0; k < nt; k++) {// 対角ブロック分解#pragma omp task depend(inout: a[k][k])potrf(a[k][k], ts, ts);ts末端の行列を更新
for (int i = k + 1; i < nt; i++) {for (int j = k + 1; j < i; j++) {#pragma omp task
dgemm(a[k][i], a[k][j], a[j][i], ts, ts);}
#pragma omp tasksyrk(a[k][i], a[i][i], ts, ts);}
#pragma omp taskwait// 三角システムfor (int i = k + 1; i < nt; i++) {#pragma omp task depend(in: a[k][k]) ¥depend(inout: a[k][i])trsm(a[k][k], a[k][i], ts, ts);}//末端の行列を更新
for (int i = k + 1; i < nt; i++) {for (int j = k + 1; j < i; j++) {#pragma omp task depend(inout: a[j][i]) ¥depend(in: a[k][i], a[k][j])dgemm(a[k][i], a[k][j], a[j][i], ts, ts);}
#pragma omp task depend(inout: a[i][i]) ¥depend(in: a[k][i])syrk(a[k][i], a[i][i], ts, ts);} } }バルセロナ・スーパーコンピューティング・センターによるスライド提供© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

| 25

OpenMP* 4.0 の機能

Do-across ループ並列

依存関係はループ反復間で生じますが、以下のコードにはループ伝搬後方依存がありますvoid lcd_ex(float* a, float* b, size_t n, int m, float c1, float c2) {size_t K;◼ ループを並列化するとき、ループ伝搬依存がない#pragma omp parallel for ordered(1)ときは、Doallループとして並列化し、ループ伝搬依存があるときは、同期操作がある Doacrossfor (K = 17; K < n; K++) {ループとして並列化します#pragma omp ordered depend(sink: K–17) ◼ そのため、ordered 句を伴う入れ子になった Do
Across ループをサポートする depend 節のa[K] = c1 * a[K - 17] + c2 * b[K];source と sink 依存性タイプがサポートされまし#pragma omp ordered depend(source)
た。これにより、構造化された依存性を持つルー}プを並列化できるようになりました
}

0

1

2

3

17 18

19

20
| 26

© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 4.5 の機能

taskloop 句
OpenMP* task を使用してループを並列化できます:#pragma omp taskloop [simd] [節]for/do ループ

ループをチャンクへ分割◼ オプションの grainsize と num_tasks 節
でタスクの生成を制御◼ インテル® Cilk™ Plus の “cilk_for” に類似◼ それぞれのループチャンクにタスクを生成◼

void CG_mat(Matrix *A, double *x, double *y){// ...
#pragma omp taskloop ¥private(j,is,ie,j0,y0) grainsize(500)for (i = 0; i < A->n; i++) {y0 = 0;is = A->ptr[i];ie = A->ptr[i + 1];
for (j = is; j < ie; j++) {j0 = index[j];y0 += value[j] * x[j0];}y[i] = y0;// ...
}// ...
}

4.5 ではまだ気軽に taskloop は使えない…
| 27© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* のタスク処理: さらに...

OpenMP* 4.0 の機能

cancel (キャンセル)OpenMP* 4.0 以前では、タスクの並列実行はキャンセルできませんでした◼
–◼

コード領域は常に最後まで実行されました (もしくはすべて実行しないか)

OpenMP* 4.0 の cancel 句は OpenMP* 領域の中断を可能にしますtaskgroup (タスクグループ)◼

次のような処理のため、タスクを論理的にグループ化できます– 同期– キャンセル| 28© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

cancel 句

OpenMP* 4.0 の機能指定された構造タイプの最も内側の並列領域の要求をキャンセルします
if 文、while 文、do 文、switch 文とラベルの後には指定できません#pragma omp cancel [構造タイプ] [[,] if 節]構造タイプ: parallel、sections、for、taskgroupif 節: if(スカラー式)
注:構文に到達したとき、デッドロックを引き起こす可能性があるロックやその他のデータ構造を解放する必要があります。ブロックされたスレッドは取り消すことができません| 29© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

cancellation point 句

OpenMP* 4.0 の機能指定された構造タイプの最も内側の並列領域のキャンセルが要求された場合に、キャンセルをチェックする位置を指定:#pragma omp cancellation point [構造タイプ]
構造タイプ: parallel、sections、for、taskgroup
制約事項:• この構文は、実行文が許可されている場所にのみ追加できます• if 文のアクション文として使用したり、プログラムで参照されるラベルの実行文として使用することはできません| 30© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

#define N 10000

cancel 句の例

void example() {std::exception *ex = NULL;#pragma omp parallel shared(ex){#pragma omp forfor (int i = 0; i < N; i++) {// コンパイラーの最適化を妨げる‘if’文はありません
try {causes_an_exception();}catch (std::exception *e) {// 後で例外を処理するため ex にステータスをストア#pragma omp atomic write
ex = e;#pragma omp cancel for // for ワークシェアリングをキャンセル}}
if (ex) // 例外が発生したら parallel 構文をキャンセル#pragma omp cancel parallel
phase_1();#pragma omp barrier
phase_2();}// 例外がワークシェア・ループ内でスローされている場合は継続
if (ex)// ex の例外処理} // parallel のおわり

OpenMP* 4.0 の機能

例外をキャッチしたら for ワーク
シェア並列処理をキャンセル
例外をキャッチしたら parallel
並列処理をキャンセル| 31© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

cancellation point 句の例 (Fortran)
subroutine example(n, dim)
integer, intent(in) :: n, dim(n)integer :: i, s, err
real, allocatable :: B(:)
err = 0!$omp parallel shared(err)! ...
!$omp do private(s, B)
do i=1, n!$omp cancellation point doallocate(B(dim(i)), stat=s)
if (s .gt. 0) then!$omp atomic write
err = s!$omp cancel do
endif
!
...
! deallocate private array B
if (allocated(B)) thendeallocate(B)
endif
enddo
!$omp end parallel
end subroutine

OpenMP* 4.0 の機能

ほかのスレッドはこの位置でキャンセルをチェック

allocate 文からエラーが返されたときにcancel do をアクティブにします| 32© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 4.0 の機能

taskgroup 構文
taskgroup 構文は、現在のタスクの子タスク（孫タスク）の完了を待機することを可能にしますint main(){
int i; tree_type tree;
init_tree(tree);#pragma omp parallel#pragma omp single{#pragma omp task
start_background_work();for (i = 0; i < max_steps; i++) {#pragma omp taskgroup{#pragma omp task
compute_tree(tree);} // このステップの tree トラバースを待機check_step();}} // ここで start_background_work の完了を待機
print_results();
return 0;}

この 2 つのタスクは同時に実行され、start_background_work() はcompute_tree() の同期の影響を受けない
なぜ taskwait が使用できないのか?

| 33© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

task 句の priority 節

OpenMP* 4.5 の機能

priotity 節は生成されたタスクの優先度に関するヒントです。実行準備が整っているタスクの中で、優先度の高いタスク (数値が大きいもの) を先に実行します:#pragma omp task priority [優先順位]

優先順位: タスクの実行順序のヒントを提供する負でない数値のスカラー式です
この機能はバージョン 17 では未サポート、19.1 ではサポート| 34© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 5.0 の task 機能強化

OpenMP* 5.0 の機能

task、taskgroup、taskloop 句でのリダクション演算のサポート◼ taskloop 構文で collapse 節をサポート◼ taskwait 句に depend 節が指定できるようになりました◼ depend 節に排他的に inout セットを自動サポートする
mutexinoutset タイプが追加されました◼

https://www.isus.jp/products/c-compilers/openmp-50-support-in-180/https://www.isus.jp/products/c-compilers/openmp_tr6_new_features/https://www.isus.jp/hpc/pu27-01-present-and-future-of-openmp/| 35© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

taskloop でのリダクション演算

OpenMP* 5.0 の機能

OpenMP* 4.5 では次のようなリダクションを含むワークシェア構文を
taskloop に書き換えることは困難でした#pragma omp parallel#pgarma omp single#pragmaprivate(x)#pragma omp
omp taskloop
parallel reduction(+:sum)for reduction(+:sum)private(x)for (i=0;i< num_steps; i++){x = (i+0.5)*step;sum = sum + 4.0/(1.0+x*x);}
pi = step * sum;

OpenMP* 5.0 では、taskloop でリダクション演算が利用できます| 36© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 5.0 の機能

taskgroup を適用して次のように記述できます
task_reduction と in_reduction を使用#pragma omp parallel#pragma omp single#pragma omp taskgroup task_reduction(+:sum)#pragma omp taskloop in_reduction (+:sum) private(x)for (i=0;i< num_steps; i++){x = (i+0.5)*step;sum = sum + 4.0/(1.0+x*x);}
pi = step * sum;| 37
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

task_reduction と in_reduction

OpenMP* 5.0 の機能

int find_minimum(list_t * list) {in_reduction が指定されないタスクの
int minimum = INT_MAX;
list_t * ptr = list;
変数はリダクションに参加しません#pragma omp parallel#pragma omp single#pragma omp taskgroup task_reduction(min:minimum){for (ptr = list; ptr ; ptr = ptr->next) {#pragma omp task firstprivate(ptr) in_reduction(min:minimum){
int element = ptr->element;
minimum = (element < minimum) ? element : minimum;}}}
return minimum;}| 38© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

taskloop 構文中での collapse 節

OpenMP* 5.0 の機能

void taskloop_example() {#pragma omp taskgroup{#pragma omp task
long_running_task() // 以下と同時に実行可能#pragma omp taskloop collapse(2) grainsize(500) nogroupfor (int i = 0; i < N; i++)for (int j = 0; j < M; j++)loop_body();}}

この構文は、ループの反復空間をチャンクに分割し、それぞれのチャンクに対して 1 つのタスクを生成します| 39© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

taskwait 句での depend 節
main ( ){int x = 2;#pragma omp task // shared(x) mergeable{x++;}#pragma omp taskwait // depend(in:x)
printf("%d¥n",x); // print 3}

OpenMP* 5.0 の機能

V19.1 では未実装

2 つのタスクのデータ
スコープは異なります

taskwait 構文に depend 節が指定される場合、マージ可能なインク
ルード・タスクを生成する空の構造化ブロックを持つ task 構文であるかのように動作します| 40© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* 5.0 の機能

相互排他を必要とするタスクセット
V19.1 Classic では未実装
mutexinoutset 依存関係タイプ
int x = 0, y = 0, res = 0;
#pragma omp parallel#pragma omp single{#pragma omp task depend(out: res)
res = 0;//T0

#pragma omp task depend(out: x)
long_computation(x);//T1#pragma omp task depend(out: y)
short_computation(y);

//T2

T1

T0

T3

T3

T2

T4

T4

#pragma omp task depend(in: x) depend(inout:
depend(mutexinoutset:res) //T3res) //T3
res += x;#pragma omp task depend(in: y) depend(mutexinoutset:
depend(inout: res) //T4res) //T4
res += y;#pragma omp task depend(in: res)std::cout << res << std::endl;

T5

//T5

}
| 41
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

OpenMP* におけるタスク依存関係のまとめ
OpenMP* API バージョン 4.5

OpenMP* API バージョン 4.0◼

task 構造に depend 節を追加◼

◼

target 構造に depend 節を追加
doacross ループをサポート

OpenMP* API バージョン 5.0
◼
◼
◼
◼
◼

depend 節の lvalue 式
新しい依存関係タイプ: mutexinoutset
depend 節にイテレーターを追加
taskwaiｔ 構造に depend 節を追加
依存関係をストアするオブジェクト

Intel、インテル、Intel ロゴ、Cilk は、アメリカ合衆国および / またはその他の国における Intel Corporation またはその子会社の商標です。
© 2020 iSUS *その他の社名、製品名などは、一般に各社の表示、商標または登録商標です。

| 42

ソフトウェア・セミナー