目次


IBM XL コンパイラーにおける OpenMP サポート

Comments

はじめに

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 仕様に準拠するアプリケーションは、異なるプラットフォーム間で移植することができます。また、この仕様は、並列プログラムとしても、逐次プログラムとしても実行できるようアプリケーションをサポートします (並列プログラムの場合は、複数の実行スレッドおよび完全な 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);
    }
}

例 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 つのスレッドによって実行されます。

さらに、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 環境変数だけを使用してスレッドのバインドを制御してください。

その他の機能強化

さまざまなシナリオで、並列処理をより柔軟に表現できるように、いくつかの機能強化が行われています。

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 の設定を表示させることができます。ランタイム設定を調べることができれば、プログラマーがコードをデバッグする際に役立ちます。また、プログラマーはこの機能を使用することで、リンク時に使用されるランタイム・ライブラリーのバージョン (ランタイム・ライブラリーが静的にリンクされている場合)、または実行時に使用されるバージョン (動的にリンクされる場合) を確認することもできます。別のシナリオとして、コードを移植した後、新しいプラットフォームでのデフォルト設定の違いから、予期せぬ動作が生じるようになったとします。この場合も、プログラマーは 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'
    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 プログラムにプラグマまたはディレクティブでアノテーションを付けることによって、逐次アプリケーションを並列化する手段を提供します。XL コンパイラーを使用してアプリケーションを並列化すると、例えば IBM POWER8 などのマルチコア・ハードウェアを利用することが可能になります。Linux on Power リトルエンディアン対応の XL C/C++ V13.1.2 および XL Fortran V15.1.2 には、OpenMP V4.0 の選り抜きの機能が追加されているため、ユーザーはさまざまな方法でアトミック操作を表現することができるだけでなく、デバッグを行う際や、さまざまなプラットフォームにコードを移植する際に、ランタイム設定に関する情報を入手することもできます。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=1014651
ArticleTitle=IBM XL コンパイラーにおける OpenMP サポート
publish-date=09102015