この章では、OpenMP 2.5 仕様の、実装に依存する特定の動作について説明します。最新のコンパイラリリースに関する最新情報については、Sun Developer Network のポータルサイト (http://developers.sun.com/sunstudio) でコンパイラに関するマニュアルを参照してください。
メモリーモデル
複数スレッドから同じ変数への非同期のメモリーアクセスが、互いのそれぞれのアクセスに対して不可分なものになる保証はありません。
アクセスが不可分にものなるかどうかは、実装依存、およびアプリケーション依存の要因による影響を受けます。変数によっては、対象プラットフォームでの最大の不可分なメモリー動作よりも大きい場合があります。変数によっては、不正な境界整列が行われていたり境界が不明である場合があります。その場合、コンパイラまたは実行時システムがその変数にアクセスするためには、複数回の読み込みおよび格納が必要になることがあります。より多くの読み込みと格納を使用する、高速なコードシーケンスもあります。
内部制御変数
OpenMP 実行時ライブラリでは、次の内部制御変数が保持されています。
nthreads-var - 将来の並列領域に対して要求されたスレッド数が格納されます。
dyn-var - 将来の並列領域で、スレッド数の動的調整を有効にするかどうかを制御します。
nest-var - 将来の並列領域で、入れ子並列を有効にするかどうかを制御します。
run-sched-var - RUNTIME スケジュール句を使用したループ領域で使用する、スケジューリング情報が格納されます。
def-sched-var - 実装で定義された、ループ領域のデフォルトスケジュール情報が格納されます。
実行時ライブラリでは、スレッドごとに nthreads-var、dyn-var、nest-var のそれぞれの独立したコピーが保持されます。一方、実行時ライブラリではすべてのスレッドに適用される run-sched-var および def-sched-var の、それぞれのコピーが 1 つ保持されます。
nthreads-var のデフォルト値は 1 です。そのため、明示的な num_threads() 句、omp_set_num_threads() ルーチンの呼び出し、または OMP_NUM_THREADS 環境変数の明示的な定義がない場合、1 つのチーム内のスレッドのデフォルト数は 1 になります。
omp_set_num_threads() の呼び出しでは、呼び出し側のスレッドのみの nthreads-var の値が変更され、呼び出し側スレッドで認識された同じレベルまたは内部入れ子レベルの並列領域に適用されます。
要求されたスレッドの数が実装でサポートできるスレッド数よりも多い場合、または値が正の整数でない場合は、SUNW_MP_WARN が TRUE に設定されているか、sunw_mp_register_warn() の呼び出しによってコールバック関数が登録されていると、警告メッセージが出力されます。
入れ子並列処理がサポートされています。入れ子になった並列領域は複数のスレッドで実行できます。
nest-var のデフォルト値は false です。そのため、入れ子並列処理はデフォルトで無効になっています。有効にするには、OMP_NESTED 環境変数を設定するか、omp_set_nested() ルーチンを呼び出します。
omp_set_nested() の呼び出しでは、呼び出し側のスレッドのみの nest-var の値が変更され、呼び出し側スレッドで認識された同じレベルまたは内部入れ子レベルの並列領域に適用されます。
デフォルトでは、サポートされる有効な入れ子レベルの最大数は 4 です。SUNW_MP_MAX_NESTED_LEVELS 環境変数を設定することで、この最大数は変更できます。
dyn-var のデフォルト値は true です。そのため、デフォルトでは動的調整が有効に設定されます。OMP_DYNAMIC 環境変数を設定するか、omp_set_dynamic() ルーチンを呼び出すことで、動的調整を無効にできます。
omp_set_dynamic() の呼び出しでは、呼び出し側のスレッドのみの dyn-var の値が変更され、呼び出し側スレッドで認識された同じレベルまたは内部入れ子レベルの並列領域に適用されます。
動的調整が有効になっていると、チームに含まれるスレッドの数は次の中で最小の値に調整されます。
ユーザーが要求したスレッドの数
プール内で利用できるスレッドの数に 1 を足した数
使用できる仮想プロセッサの数
一方、動的調整が無効になっている場合は、チームに含まれるスレッドの数が次の中での最小の値に調整されます。
ユーザーが要求したスレッドの数
プール内で利用できるスレッドの数に 1 を足した数
システム資源の不足など、特別な状況では、提供されるスレッドの数は前に説明した数より少なくなることがあります。このような状況で、SUNW_MP_WARN が TRUE に設定されているか、sunw_mp_register_warn() を呼び出すことでコールバック関数が登録されている場合は、警告メッセージが出力されます。
スレッドのプールと入れ子並列処理の実行モデルの詳細については、第 2 章を参照してください。
ループスケジュール
def-sched-var のデフォルト値は STATIC スケジューリングです。ループ領域に別のスケジュールを指定するには、SCHEDULE 句を使用します。
run-sched-var のデフォルト値も STATIC スケジューリングです。OMP_SCHEDULE 環境変数を設定することで、デフォルトを変更できます。
chunksize が指定されていない場合の SCHEDULE(GUIDED) のデフォルトのチャンクサイズは 1 です。OpenMP 実行時ライブラリは、GUIDED スケジューリングされたループのチャンクサイズを次の式を使って計算します。 チャンクサイズ = unassigned_iterations / (weight * num_threads) unassigned_iterations とは、どのスレッドにも割り当てられていないループの反復回数を表します。weight (「重み係数」) は、ユーザーが SUNW_MP_GUIDED_WEIGHT 環境変数を使って実行時に設定できる浮動小数点定数です (「2.3 OpenMP 環境変数」 を参照してください)。現在のデフォルトでは、ユーザーの指定がない場合には weight として 2.0 が、num_threads (「スレッド数」) としてループの実行に使用されるスレッド数が指定されます。weight に指定された値は、ループ内のスレッドに割り当てられる反復の初期のチャンクとそのあとのチャンクのサイズに影響し、また、負荷分散に直接影響します。これまでの実験では、デフォルトである 2.0 でほとんどの場合問題なく動作することが確認されています。ただし、アプリケーションによっては異なる値にした方が良いこともあります。
POSIX または Solaris のスレッドを使用して明示的にスレッド化されたプログラムでは、OpenMP 指令を含めたり、Open MP の指令が含まれるルーチンを呼び出したりできます。
SUNW_MP_WARN 環境変数 (「2.3 OpenMP 環境変数」を参照) を設定すると、OpenMP 実行時ライブラリによる実行時の有効性の確認機能が有効になります。
たとえば、次に挙げるコードでは、スレッドが異なるバリアで待ち状態に入り、ループが終了しません。終了させるには、端末で Control キーを押しながら C キーを押します。
% cat bad1.c #include <omp.h> #include <stdio.h> int main(void) { omp_set_dynamic(0); omp_set_num_threads(4); #pragma omp parallel { int i = omp_get_thread_num(); if (i % 2) { printf("At barrier 1.\n"); #pragma omp barrier } } return 0; } % cc -xopenmp -xO3 bad1.c % ./a.out run the program At barrier 1. At barrier 1. program hung in endless loop Control-C to terminate execution |
しかし、実行前に SUNW_MP_WARN を設定しておけば、実行時ライブラリによってこの問題を事前に検出することができます。
% setenv SUNW_MP_WARN TRUE % ./a.out WARNING (libmtsk): Environment variable SUNW_MP_WARN is set to TRUE. Runtime error checking will be enabled. At barrier 1. At barrier 1. WARNING (libmtsk): Threads at barrier from different directives. Thread at barrier from bad1.c:8. Thread at barrier from bad1.c:13. Possible Reasons: Worksharing constructs not encountered by all threads in the team in the same order. Incorrect placement of barrier directives. WARNING (libmtsk): Runtime shutting down while some parallel region is still active. |
C および C++ コンパイラでも、エラーが検出されたときのコールバック関数を登録するための関数が提供されています。エラーが検出されると、登録されたコールバック関数が呼び出され、エラーメッセージ文字列へのポインタが引数として渡されます。
int sunw_mp_register_warn(void (*func) (void *) )
この関数のプロトタイプを使用する場合は、次の行を追加します。 #include <sunw_mp_misc.h>
次に例を示します。
% cat bad2.c #include <omp.h> #include <sunw_mp_misc.h> #include <stdio.h> void handle_warn(void *msg) { printf("handle_warn: %s\n", (char *)msg); } void set(int i) { static int k; #pragma omp critical { k++; } #pragma omp barrier } int main(void) { int i, rc; omp_set_dynamic(0); omp_set_num_threads(4); if (sunw_mp_register_warn(handle_warn) != 0) { printf ("Installing callback failed\n"); } #pragma omp parallel for for (i = 0; i < 20; i++) { set(i); } return 0; } % cc -xopenmp -xO3 bad2.c % a.out WARNING (libmtsk): Environment variable SUNW_MP_WARN is set to TRUE. Runtime error checking will be enabled. handle_warn: WARNING (libmtsk): at bad2.c:15. BARRIER is not permitted in the dynamic extent of FOR / DO. |
handle_warn() は、OpenMP 実行時ライブラリによってエラーが検出された場合に、コールバック関数としてインストールされます。この例のコールバック関数はライブラリから渡されたエラーメッセージを表示するだけですが、特定のエラーを検出するためにも使用できます。
特定の構文について
sections 構文
sections 構文内の構文ブロックは sections 領域を実行するチームのメンバーごとに分割され、実行されるスレッド数が sections の数とほぼ等しくなります。
single 構文
single 構文の構造ブロックは、先に single 領域を検出したスレッドによって実行されます。
atomic 構文
実装上は、すべての ATOMIC 指令およびプラグマは、CRITICAL 構文内に文を含める形に置き換えられます。
OpenMP ライブラリルーチンの結合スレッドセット
omp_set_num_threads ルーチン
明示的な並列領域の中から呼び出された場合、omp_set_num_threads 領域の結合スレッドセットは呼び出し側スレッドです。
omp_get_max_threads ルーチン
明示的な並列領域の中から呼び出された場合、omp_get_max_threads 領域の結合スレッドセットは呼び出し側スレッドです。
omp_set_dynamic ルーチン
明示的な並列領域の中から呼び出された場合、omp_set_dynamic 領域の結合スレッドセットは呼び出し側スレッドのみです。
omp_get_dynamic ルーチン
明示的な並列領域の中から呼び出された場合、omp_get_dynamic 領域の結合スレッドセットは呼び出し側スレッドのみです。
omp_set_nested ルーチン
明示的な並列領域の中から呼び出された場合、omp_get_nested 領域の結合スレッドセットは呼び出し側スレッドのみです。
omp_get_nested ルーチン
明示的な並列領域の中から呼び出された場合、omp_get_nested 領域の結合スレッドセットは呼び出し側スレッドのみです。
Fortran 95 固有の問題:
threadprivate 指令
2 つの連続した有効な並列領域間で維持される、スレッド (最初のスレッド以外) の threadprivate オブジェクト内のデータの値の条件がすべては保持されない場合、2 番目の領域の割り当て可能な配列の割り当て状態が「not currently allocated」になることがあります。
shared 句
共有変数を組み込み以外の手続きに渡すと、手続きで参照する前に共有変数の値が一時ストレージにコピーされ、手続きでの参照後に一時ストレージが実際の引数ストレージに戻されるることがあります。この一時ストレージへのコピーと読み出しが行われるのは、OpenMP 2.5 仕様のセクション 2.8.3.2 の条件 a、b、および c が保持される場合のみです。
インクルードファイルとモジュールファイル
この実装では、インクルードファイル omp_lib.h とモジュールファイル omp_lib の両方が提供されます。
Solaris では、引数をとる OpenMP 実行時ライブラリルーチンが generic インタフェースで拡張されたため、異なる Fortran の KIND 型の引数に対応できます。