PDF

IBM XL コンパイラーにおける OpenMP サポート
Kelvin Li
Compiler Software Developer
IBM
2015年 9月 10日
Fortran および C/C++ 用の Linux on Power リトルエンディアン対応 IBM XL コンパイラー
は、OpenMP API V3.1 の機能に加え、V4.0 から選り抜いた一部の機能をサポートしています。
これにより、コンパイラーでマルチコア・ハードウェアを利用してパフォーマンスを高める
ことが可能になっています。この記事では、最新の XL コンパイラーでサポートされている
OpenMP の機能について説明します。さらに、これらの新しい機能を使用する利点を明らかに
する例も記載します。
はじめに
IBM XL コンパイラーは、アプリケーションがハードウェア・プラットフォームの特性を利用して
最大限のパフォーマンスを発揮するのを促進するとともに、パフォーマンス固有の機能をサポー
トし、プログラマーがアプリケーションを最適化およびチューニングできるよう支援します。最
近のほとんどのコンピューターはマルチコア・ハードウェアで構成されているため、並列化がア
プリケーションのパフォーマンスを向上させる一般的な手法の 1 つとなっています。
ユーザーが並列処理を用いるために、逐次コードにプラグマとディレクティブでアノテーショ
ンを付けられるようにする業界標準が、OpenMP アプリケーション・プログラミング・インター
フェース (API) です。OpenMP 仕様の基本言語は Fortran、C、および C++ です。OpenMP 仕様の
策定には、ベンダー、ユーザー、研究者などで構成される OpenMP 言語委員会が取り組んでいま
す。詳細については、OpenMP の Web サイトを参照してください。
Linux on Power リトルエンディアン対応の XL C/C++ コンパイラーおよび
XL Fortran コンパイラーでの OpenMP サポート
Linux on Power リトルエンディアン対応の IBM XL C/C++ V13.1.2 および XL Fortran V15.1.2 は、
並列プログラミングに関する OpenMP API V3.1 仕様と、(この記事を公開する時点で) 最新の
OpenMP API V4.0 から選り抜いた機能をサポートします。OpenMP は、並列アプリケーションを
開発するための単純かつ柔軟なインターフェースとなります。OpenMP 仕様は、ディレクティブ/
プラグマ、ランタイム・ライブラリー関数、環境変数という 3 つのコンポーネントからなりま
す。OpenMP 仕様に準拠するアプリケーションは、異なるプラットフォーム間で移植することが
できます。また、この仕様は、並列プログラムとしても、逐次プログラムとしても実行できるよ
うアプリケーションをサポートします (並列プログラムの場合は、複数の実行スレッドおよび完全
© Copyright IBM Corporation 2015
IBM XL コンパイラーにおける OpenMP サポート
商標
ページ 1 / 10
developerWorks®
ibm.com/developerWorks/jp/
な OpenMP サポート・ライブラリーを使用します。逐次プログラムの場合は、ディレクティブ/プ
ラグマが無視され、スタブ・ライブラリーがリンクされます)。
OpenMP による並列化を有効にするには、–qsmp コンパイラー・オプションを使用します。–
qsmp=omp を指定すると、コンパイル・プログラムに対して OpenMP への厳格な準拠が適用されま
す。詳細については、XL コンパイラーのコンパイラー・リファレンスを参照してください (「参
考文献」セクションにリンクが記載されています)。
OpenMP V3.1 の新機能
OpenMP API V3.1 では、ユーザーがアプリケーションを微調整するために使用できる既存の機能
が拡張されています。この改訂により、いくつかの制約も緩和されて、並列プログラミングでの
さまざまなシナリオをより柔軟に表現できるようになっています。
タスク並列処理の拡張
OpenMP 仕様の初期のバージョンでは、並列処理の対象はほとんど決まりきっており、例えば、
繰り返し処理の回数を決められるループ並列処理や、独立したセクションの数が固定されてい
る並列セクション構成体などがあります。決まりきった対象以外の並列処理をサポートするため
に、V3.0 ではタスク並列処理が導入されています。task 構成体は、ポインター追跡や再帰アルゴ
リズムなどの不規則なアルゴリズムの並列化を可能にします。ただし、問題の規模が小さくなれ
ばなるほど、計算処理をするためのタスクを作成するコストが、タスク自体の計算処理に比べて
かなり大きくなってきます。そのために導入されているのが、final 節と mergeable 節です。final
節は、タスクを即時に実行する必要があるのかどうか、mergeable 節は、タスクのデータ環境を
作成する必要があるのかどうかを制御できるようになっています。
例 1: final タスクを生成する
#pragma omp parallel
{
#pragma omp single
{
while (list) {
#pragma omp task final(list->size < THRESHOLD)
{
compute(list->next);
}
}
}
}
例 1 は、タスクを並列領域で生成して実行する例です。生成されたタスクの規模が THRESHOLD よ
り小さければ、そのタスクは final タスクとなります。この final タスクは即時に実行され、スケ
ジューリングのコストはかかりません。
例 2: mergeable タスクを生成する
void compute(struct S *p)
{
#pragma omp task final(level < DEPTH) mergeable
{
compute(p->next);
}
}
IBM XL コンパイラーにおける OpenMP サポート
ページ 2 / 10
ibm.com/developerWorks/jp/
developerWorks®
例 2 では、再帰関数がリストをトラバースして計算処理を行います。再帰関数がトラバース
する対象がある特定のレベルまでであれば、計算処理の規模が小さいことから、新しいタス
クを作成する価値はないかもしれません。mergeable 節を指定することで、コンパイラーに対
し、mergeable タスクには新しいデータ環境を作成しないように指示すると、タスクの生成コス
トが削減されます。この 2 つの新しい拡張により、計算処理の規模が小さくなる場合にタスク並
列処理のパフォーマンスを微調整してコストを削減できるようになりました。
ネストされた並列処理
OMP_NUM_THREADS 環境変数は、並列領域で使用するスレッドの数を指定します。しかし、ネス
トされた並列領域がある場合、この環境変数には、内側の並列領域で使用するスレッドの数を
直接制御する手段がありませんでした。プログラマーが気を抜くと、スレッドのオーバーサブ
スクリプションが発生しかねません。そうなると、パフォーマンスに影響が及ぶことになりま
す。OpenMP V3.1 では、OMP_NUM_THREADS 環境変数が拡張され、ネストされた並列領域で使用
するスレッドの数を指定できるようになりました。その値はカンマ区切りリストで指定する
ことができます (例えば、OMP_NUM_THREAD=8,4 など)。さらに、一連の照会ルーチンも追加さ
れています。例えば、ネストされた並列領域のレベル (omp_get_level)、先祖のスレッド番号
(omp_get_ancestor_thread_num)、指定されたレベルのチーム・サイズ (omp_get_team_size)、ネス
トされたアクティブ並列領域のレベル (omp_get_active_level) などです。さらに、アクティブな
レベルの最大数を取得および設定するランタイム・ルーチン (omp_set_max_active_levels および
omp_get_max_active_levels) もあります。
例 3: ネストされた並列構成体
#include <omp.h>
int main() {
#pragma omp parallel
{
if (omp_get_thread_num()==0) printf("outer parallel: %d\n", omp_get_num_threads());
#pragma omp parallel
{
if (omp_get_thread_num()==0)
printf("inner parallel: %d\n", omp_get_num_threads());
}
}
}
例 3 を XL C/C++ コンパイラーでコンパイルすると、例 4 に示す出力が表示されます。
例 4: ネストされた並列プログラムのコンパイルと出力
$ xlc –qsmp nested_par.c –o nested_par
$ export OMP_NESTED=true
$ export OMP_NUM_THREADS=4,2
$ ./nested_par
outer parallel: 4
inner parallel: 2
inner parallel: 2
inner parallel: 2
inner parallel: 2
OMP_NUM_THREADS 環境変数で「4,2」が指定されているため、外側の並列領域は 4 つのスレッドに
よって実行され、内側の並列領域は 2 つのスレッドによって実行されます。
IBM XL コンパイラーにおける OpenMP サポート
ページ 3 / 10
developerWorks®
ibm.com/developerWorks/jp/
さらに、Linux on Power リトルエンディアン対応の XL C/C++ V13.1.2 コンパイラーおよび XL
Fortran V15.1.2 コンパイラーでは、OpenMP スタイルのネストされた並列処理をサポートするよ
うになっています。ネストされた並列処理を有効にするには、OMP_NESTED 環境変数を true に設
定します。ネストされた並列処理は、デフォルトでは無効にされています。この設定は、プログ
ラム全体に適用されます。プログラマーは、omp_set_nested ランタイム・ルーチンを呼び出すこ
とで、コードの特定の並列領域に対して選択的にネストされた並列処理を有効にすることができ
ます。
この機能によって、実行中の環境に応じて簡単にアプリケーションを調整することができるた
め、必要とされる以上の数のスレッドを作成してパフォーマンスに影響が及ぶのを回避すること
ができます。
atomic 構成体の拡張
atomic 構成体には、現在さらに多くのアトミック操作が含まれるようになっており、read
節、write 節、capture 節が追加されています。これらの節はそれぞれ、読み取り操作、書き込み
操作、そして (値を取り込んでおいてから、その値を更新する)「キャプチャー」操作をサポート
します。既存のアトミック更新フォームは、update 節で表現することもできます。
例 5 に、atomic 構成体をいくつか記載します。
例 5: OpenMP のアトミック操作
! atomic read of variable x
!$omp atomic read
v = x
!$omp end atomic
! atomic write of variable x
!$omp atomic write
x = y
!$omp end atomic
! atomic capture: pre-update value of x is captured and then updated
!$omp atomic capture
v = x
x = x + 1
!$omp end atomic
スレッド・バインド・ポリシー
アプリケーションによっては、必要なパフォーマンスを実現するために専用リソースが必要にな
ります。スレッドをあるプロセッサーから別のプロセッサーに移植した場合、パフォーマンス
に予期せぬ影響が及ぶ可能性があります。稼働状態の環境で、ユーザーがプロセッサー間での
OpenMP スレッドの移植を有効または無効にできるように、OMP_PROC_BIND 環境変数が導入され
ています。
IBM XL コンパイラーでは XLSMPOPTS 環境変数の startproc/stride または procs サブオプションを
使用して、OpenMP スレッドをプロセッサーにバインドする方法をさらにきめ細かく制御するこ
とができます。ただし、この機能は IBM による拡張であるため、アプリケーションの移植性が重
要な場合は、OMP_PROC_BIND 環境変数だけを使用してスレッドのバインドを制御してください。
IBM XL コンパイラーにおける OpenMP サポート
ページ 4 / 10
ibm.com/developerWorks/jp/
developerWorks®
その他の機能強化
さまざまなシナリオで、並列処理をより柔軟に表現できるように、いくつかの機能強化が行われ
ています。
Fortran では、firstprivate 節に intent(in) ダミー引数を設定することができます。これによ
り、並列構成体に渡す前に、プロシージャー内で一時変数を作成する必要がなくなります。現在
は、firstprivate 節および lastprivate 節には、Fortran のポインターを指定できるようになって
います。
C/C++ では、簡約演算子 min および max が追加され、それぞれに対応する操作を実行できるよう
になっています。
OpenMP V4.0 の選り抜きの機能とその他の機能強化
Linux on Power リトルエンディアン対応の XL C/C++ V13.1.2 および XL Fortran V15.1.2 に
は、OpenMP V4.0 の機能がいくつか追加されています。具体的には、atomic 構成体の拡張と
OMP_DISPLAY_ENV 環境変数です。
atomic 構成体の拡張
アトミックな値交換は、atomic 構成体で capture 節を使用して表すことができます。以下の例に
示すアトミックな値交換を行う atomic 構成体では、元の値 x を取り込んでおいてから x を更新し
ます。
例 6: アトミックな値交換操作
#pragma omp atomic capture
{
v = x;
x = y;
}
上記の例に加え、atomic capture 構成体では他の表現形式も使用できるため、ユーザーはコードで
柔軟に表現することができます。
Linux on Power リトルエンディアン対応の XL C/C++ V13.1.2 および XL Fortran V15.1.2 では、パ
フォーマンスの向上を目的に、OpenMP アトミックを再実装しています。前の実装では、メモ
リー・ロケーションへの排他的アクセスを確実にするためにロックを使用していましたが、新し
い実装では IBM PowerPC アーキテクチャーで有効な、ロック・メカニズムを使用しないハード
ウェア命令を使用します。これによってアトミックな操作が効率化されるため、アトミックな操
作を使用するアプリケーションではパフォーマンス全体が向上することになります。
OpenMP ランタイム設定の表示
実装ではデフォルトで OpenMP 内部制御変数 (ICV) が設定されますが、ソース・コードの中で
環境変数を設定するか、ランタイム・ルーチンを呼び出すことで、これらの ICV を変更するこ
とができます。ICV の設定を照会するには、対応するランタイム・ルーチンを呼び出すという方
法もありますが、そのプロセスにはソースにルーチン呼び出しを挿入し、アプリケーションを
再コンパイルする作業が伴うため、時間がかかる場合があります。OpenMP V4.0 で追加してい
る OMP_DISPLAY_ENV 環境変数を使用すれば、OpenMP ラインタイムに ICV の設定を表示させる
IBM XL コンパイラーにおける OpenMP サポート
ページ 5 / 10
developerWorks®
ibm.com/developerWorks/jp/
ことができます。ランタイム設定を調べることができれば、プログラマーがコードをデバッグ
する際に役立ちます。また、プログラマーはこの機能を使用することで、リンク時に使用され
るランタイム・ライブラリーのバージョン (ランタイム・ライブラリーが静的にリンクされてい
る場合)、または実行時に使用されるバージョン (動的にリンクされる場合) を確認することもで
きます。別のシナリオとして、コードを移植した後、新しいプラットフォームでのデフォルト
設定の違いから、予期せぬ動作が生じるようになったとします。この場合も、プログラマーは
OMP_DISPLAY_ENV 環境変数を使用すれば、簡単に設定を比較して違いを特定し、必要に応じて
調整することができます。
例 7: OMP_DISPLAY_ENV 環境変数を使用したランタイム設定の表示
$ export OMP_DISPLAY_ENV=true
$ ./a.out
OPENMP DISPLAY ENVIRONMENT BEGIN
OMP_DISPLAY_ENV='TRUE'
_OPENMP='201107'
OMP_DYNAMIC='FALSE'
OMP_MAX_ACTIVE_LEVELS='5'
OMP_NESTED='FALSE'
OMP_NUM_THREADS='96'
OMP_PROC_BIND='FALSE'
OMP_SCHEDULE='STATIC,0'
OMP_STACKSIZE='4194304'
OMP_THREAD_LIMIT='96'
OMP_WAIT_POLICY='PASSIVE'
OPENMP DISPLAY ENVIRONMENT END
例 7 では、OMP_DISPLAY_ENV 環境変数が true に設定されていることから、OpenMP ラインタイム
は、環境変数に関連付けられた ICV のデフォルト設定をすべて表示しています。この環境変数が
verbose に設定されていると、もっと多くのベンダー固有の設定が表示されるようになります。
例 8: OMP_DISPLAY_ENV 環境変数を使用した、ベンダー固有の情報を含むランタイ
ム設定の表示
$ export OMP_DISPLAY_ENV=verbose
$ ./a.out
OPENMP DISPLAY SWITCHES BEGIN
LOMP_AUTO_PASSIVE_HALF_THREAD='1'
LOMP_CACHE_LINE_SIZE='256'
LOMP_CHECK_STACKS='1'
LOMP_CLEANUP_ON_PROCESS_EXIT='0'
LOMP_CLEANUP_TO_FORCE_RESCAN='0'
LOMP_COUNTER_BARRIER='0'
LOMP_DEBUG='0'
LOMP_DEFAULT_DELAY='1000'
LOMP_DEFAULT_SPIN='64'
LOMP_DEFAULT_YIELD='64'
LOMP_ENABLE_INLINING='1'
LOMP_ENABLE_WAIT_PASSIVE_BARRIER='0'
LOMP_ENABLE_WAIT_PASSIVE_WORKER='1'
LOMP_FUSSY_INIT='0'
LOMP_GUIDED_SHARED='1'
LOMP_ILDE_THREAD_EXIT='0'
LOMP_XL_LEGACY='0'
LOMP_G_LEGACY='0'
LOMP_AUTOPAR_LEGACY='1'
IBM XL コンパイラーにおける OpenMP サポート
ページ 6 / 10
ibm.com/developerWorks/jp/
developerWorks®
LOMP_LOOP_CACHE='0'
LOMP_MASTER_BARRIER_MSYNC='0'
LOMP_MAX_THREAD='65535'
LOMP_PARALEL_DISABLE_FAST_PATH='0'
LOMP_PROC_BIND_40='1'
LOMP_PROC_BIND_WHEN_OFF='0'
LOMP_PROC_BIND_WHEN_ON='1'
LOMP_SEQENTIAL_FAST='1'
LOMP_TASK_DISABLE_STEAL='0'
LOMP_TEST='1'
LOMP_WAIT_LOW_PRIO='1'
LOMP_WAIT_WITH_YIELD='1'
OMPT_TIER='0'
LOMP_TARGET_PPC='0'
LOMP_TARGET_CUDA='0'
LOMP_ARCH_POWER='8'
LOMP_BARRIER_SWMR_DEGREE='2'
LOMP_BARRIER_WITH_IO_SYNC='1'
OPENMP DISPLAY SWITCHES END
OPENMP DISPLAY RUNTIME BEGIN
LOMP_VERSION='0.35 for OpenMP 3.1'
BUILD_LEVEL='OpenMP Runtime Version: 13.1.2(C/C++) and
15.1.2(Fortran) Level: 150417 ID: _v1mpguSSEeSbzZ-i2Itj4A'
TARGET='Linux, 64 bit LE'
OPENMP DISPLAY RUNTIME END
OPENMP DISPLAY ENVIRONMENT BEGIN
OMP_DISPLAY_ENV='VERBOSE'
_OPENMP='201107'
OMP_DYNAMIC='FALSE'
OMP_MAX_ACTIVE_LEVELS='5'
OMP_NESTED='FALSE'
OMP_NUM_THREADS='96'
OMP_PROC_BIND='FALSE'
OMP_SCHEDULE='STATIC,0'
OMP_STACKSIZE='4194304'
OMP_THREAD_LIMIT='96'
OMP_WAIT_POLICY='PASSIVE'
XLSMPOPTS=' DELAYS=1000'
XLSMPOPTS=' NOSTACKCHECK'
XLSMPOPTS=' PARTHDS=96'
XLSMPOPTS=' PARTHRESHOLD=
inf'
XLSMPOPTS=' PROFILEFREQ=16'
XLSMPOPTS=' SCHEDULE=STATIC=0'
XLSMPOPTS=' SEQTHRESHOLD=
inf'
XLSMPOPTS=' SPINS=64'
XLSMPOPTS=' STACK=4194304'
XLSMPOPTS=' USRTHDS=0'
XLSMPOPTS=' YIELDS=64'
OPENMP DISPLAY ENVIRONMENT END
例 8 は、XL コンパイラー・ランタイムからの出力の一例です。最初のセクションには、OpenMP
ランタイムの内部設定が表示されます。2 番目のセクションには、ビルド固有の情報が表示され
ます。システムに OpenMP ランタイムの複数のバージョンがある場合、このビルド固有の情報
は、アプリケーションが関連付けられているランタイムのバージョンを特定する上で役立ちま
す。3 番目のセクションに表示されるのは、ICV 設定と IBM による拡張設定です。
まとめ
XL コンパイラーの OpenMP API サポートは、プログラマーに、C、C++、または Fortran プロ
グラムにプラグマまたはディレクティブでアノテーションを付けることによって、逐次アプリ
IBM XL コンパイラーにおける OpenMP サポート
ページ 7 / 10
developerWorks®
ibm.com/developerWorks/jp/
ケーションを並列化する手段を提供します。XL コンパイラーを使用してアプリケーションを並
列化すると、例えば IBM POWER8 などのマルチコア・ハードウェアを利用することが可能にな
ります。Linux on Power リトルエンディアン対応の XL C/C++ V13.1.2 および XL Fortran V15.1.2
には、OpenMP V4.0 の選り抜きの機能が追加されているため、ユーザーはさまざまな方法でア
トミック操作を表現することができるだけでなく、デバッグを行う際や、さまざまなプラット
フォームにコードを移植する際に、ランタイム設定に関する情報を入手することもできます。
IBM XL コンパイラーにおける OpenMP サポート
ページ 8 / 10
ibm.com/developerWorks/jp/
developerWorks®
参考文献
• OpenMP Architecture Review Board: 「OpenMP Application Program Interface Version 3.1」
(2011年7月)
• OpenMP Architecture Review Board: 「OpenMP Application Program Interface Version 4.0」
(2013年7月)
• コンパイラー・リファレンス ― XL C/C++ for Linux 13.1.2 (リトル・エンディアン・ディスト
リビューション用)
• コンパイラー・リファレンス ― XL Fortran for Linux 15.1.2 (リトル・エンディアン・ディスト
リビューション用)
IBM XL コンパイラーにおける OpenMP サポート
ページ 9 / 10
developerWorks®
ibm.com/developerWorks/jp/
著者について
Kelvin Li
Kelvin Li は IBM XL コンパイラー・チームで働いており、XL Fortran コンパイラーと
XL C/C++ コンパイラーに 15 年以上携わっています。彼は現在、OpenMP 言語委員会
および OpenMP Architecture Review Board for IBM の代表をしています。
© Copyright IBM Corporation 2015
(www.ibm.com/legal/copytrade.shtml)
商標
(www.ibm.com/developerworks/jp/ibm/trademarks/)
IBM XL コンパイラーにおける OpenMP サポート
ページ 10 / 10