Sun Studio 12 Update 1: OpenMP API ユーザーズガイド

第 6 章 変数の自動スコープ宣言

OpenMP の並列領域で変数のスコープ属性を指定することを、スコープ宣言といいます。一般に、変数が SHARED とスコープ宣言された場合、すべてのスレッドは同じ変数を使用します。変数が PRIVATE スコープ宣言された場合は、各スレッドはそれぞれ専用の変数のコピーを使用します。OpenMP には、豊富なデータ環境があります。SHAREDPRIVATE に加えて、変数のスコープは、FIRSTPRIVATELASTPRIVATEREDUCTION、あるいは THREADPRIVATE とも宣言できます。

OpenMP では、並列領域で使用する変数の 1 つ 1 つについて、そのスコープを宣言する必要があります。これは単調でエラーを起こしやすい工程で、多くの人が、OpenMP を使ってプログラムを並列化する作業でもっとも手間のかかる部分と認識しています。

Sun Studio C、C++、および Fortran 95 コンパイラには自動スコープ宣言機能があります。コンパイラが並列領域の実行および同期パターンを解析して、一群のスコープ宣言規則に基づいて、変数のスコープを自動的に決定します。

6.1 自動スコープ宣言用データスコープ節

自動スコープ宣言用データスコープ節は、OpenMP 仕様に対する Sun の拡張です。このあとの 2 つある句のいずれかを利用することによって、変数のスコープを自動的に宣言するように指定できます。

6.1.1 __auto

構文は次のようになります。

__auto(list-of-variables)

並列構文上の __auto 節は、コンパイラが構文中で指定された変数のスコープを自動的に決定するように指示します。auto の前の下線は 2 つであることに注意してください。

__auto 節は、PARALLELPARALLEL DO/forPARALLEL SECTIONS、または Fortran 95 PARALLEL WORKSHARE 指令で使用できます。

__auto 節で変数を指定した場合、ほかのデータスコープ節でその変数を指定できません。

6.1.2 default(__auto)

並列構文上の default(__auto) 節は、どのデータスコープ節でも明示的にスコープ宣言されていない、構文内で参照される変数すべてのスコープを、コンパイラが自動的に特定するように指示します。

default(__auto) 節は、PARALLELPARALLEL DO/forPARALLEL SECTIONS、または Fortran 95 PARALLEL WORKSHARE 指令で使用できます。

6.2 スコープ宣言規則

自動スコープ宣言では、コンパイラは、並列領域内の変数のスコープを決定する際に次の規則を適用します。

これらの規則は、OpenMP 仕様で暗黙にスコープ宣言される、ワークシェアリング DO または FOR ループのループインデックス変数などの変数には適用されません。

6.2.1 スカラー変数に関するスコープ宣言規則

6.2.2 配列に関するスコープ宣言規則

6.3 自動スコープ宣言に関する一般的な注意事項

暗黙のスコープを持たない変数を自動スコープ宣言するときに、コンパイラは、スカラーの場合は指定された順序で前述の S1 ~ S3 の規則に対して、および配列の場合は前述の A1 の規則に対して、変数の使われ方を比較検査します。規則に一致する場合、コンパイラはその規則に従って変数のスコープを決定します。規則に一致しない場合、コンパイラは次の規則を試します。コンパイラは、一致するものが見つからなかった場合は、その変数のスコープ判定を中止します。その変数のスコープは SHARED と宣言され、あたかも IF (.FALSE.) または if(0) 節が指定されているかのように結合並列領域が直列化されます。

自動スコープ宣言が失敗する理由は 2 つあります。1 つは、変数の使われ方が前述のどれにも一致しないため、もう 1 つは、ソースコードが複雑すぎて、コンパイラが十分な解析を行えないためです。こうした原因としてよくあるのは、たとえば、関数呼び出しや複雑な配列添え字、メモリー別名、ユーザー実装の同期などです。「6.5 現在の実装の既知の制限事項」を参照してください。

6.3.1 Fortran 95 の自動スコープ宣言規則

Fortran では、変数が __auto または default(__auto) 節を使用して自動スコープ宣言され、その変数に OpenMP 仕様に従って事前定義されたスコープがある場合、コンパイラはその事前定義されたスコープに従って変数のスコープを宣言します。

Fortran では、次の変数に事前定義されるスコープがあります。

6.3.2 C/C++ の自動スコープ宣言規則

C/C++ では、変数が __auto または default(__auto) 節を使用して自動スコープ宣言され、その変数に OpenMP 仕様に従って事前定義されたスコープがある場合、コンパイラはその事前定義されたスコープに従って変数のスコープを宣言します。

C/C++ では、次の変数に事前定義されるスコープがあります。

C および C++ の自動スコープ宣言が適用されるのは、基本データ型の 整数、浮動小数点、ポインタのみです。ユーザーが構造変数またはクラス変数の自動スコープ宣言を指定する場合、コンパイラは変数を shared としてスコープ宣言し、それを包含する並列領域は 1 つのスレッドとして実行されます。

6.4 自動スコープ宣言結果の確認

コンパイラのコメント」を利用して、詳細な自動スコープ宣言結果を調べたり、自動スコープ宣言が失敗したために直列化された並列領域がないか確認したりできます。

コンパイルで -g が付けられていると、コンパイラはインラインコメントを生成します。このコメントは、次に示すように er_src を使って表示できます(er_src コマンドは、Sun Studio ソフトウェアの一部として提供されています。詳細は、er_src(1) のマニュアルページまたは『Sun Studio プログラムのパフォーマンス解析』を参照してください)。

-xvpara コンパイルオプションを使用することからスタートすることを推奨します。自動スコープ宣言の失敗があると、次のような警告メッセージが出力されます。


例 6–1 -vpara を使ったコンパイル


%cat t.f
      INTEGER X(100), Y(100), I, T
C$OMP PARALLEL DO DEFAULT(__AUTO)
      DO I=1, 100
         T = Y(I)
         CALL FOO(X)
         X(I) = T*T
      END DO
C$OMP END PARALLEL DO
      END
%f95 -xopenmp -xO3 -vpara -c t.f
"t.f", line 2: Warning: parallel region will be executed 
   by a single thread because the autoscoping 
   of following variables failed - x

f95 では -vparacc では -xvpara 付きでコンパイルします (CC では、まだこのオプションが実装されていません)。


例 6–2 コンパイラのコメントの見方


%cat t.f
      INTEGER X(100), Y(100), I, T
C$OMP PARALLEL DO DEFAULT(__AUTO)
      DO I=1, 100
         T = Y(I)
         X(I) = T*T
      END DO
C$OMP END PARALLEL DO
      END

%f95 -xopenmp -xO3 -g -c t.f
%er_src t.o
Source file: ./t.f
Object file: ./ot.o
Load Object: ./t.o

     1. INTEGER X(100), Y(100), I, T

Source OpenMP region below has tag R1
Variables autoscoped as SHARED in R1: x, y
Variables autoscoped as PRIVATE in R1: t, i
Private variables in R1: i, t
Shared variables in R1: y, x
     2. C$OMP PARALLEL DO DEFAULT(__AUTO)
       <Function: _$d1A2.MAIN_>
Source loop below has tag L1
L1 parallelized by explicit user directive
L1 parallel loop-body code placed in function _$d1A2.MAIN_ along with 0
inner loops
Copy in M-function of loop below has tag L2
L2 scheduled with steady-state cycle count = 3
L2 unrolled 4 times
L2 has 0 loads, 0 stores, 2 prefetches, 0 FPadds, 0 FPmuls, and 0 FPdivs
per iteration
L2 has 1 int-loads, 1 int-stores, 4 alu-ops, 1 muls, 0 int-divs and 1
shifts per iteration
     3. DO I=1, 100
     4. T = Y(I)
     5. X(I) = T*T
     6. END DO
     7. C$OMP END PARALLEL DO
     8. END

次に、自動スコープ宣言の仕組みを示すより複雑な例を紹介します。


例 6–3 より複雑な例


 1.      REAL FUNCTION FOO (N, X, Y)
 2.      INTEGER       N, I
 3.      REAL          X(*), Y(*)
 4.      REAL          W, MM, M
 5.
 6.      W = 0.0
 7.
 8. C$OMP PARALLEL DEFAULT(__AUTO)
 9.
10. C$OMP SINGLE
11.       M = 0.0
12. C$OMP END SINGLE
13.
14.       MM = 0.0
15.
16. C$OMP DO
17.       DO I = 1, N
18.          T = X(I)
19.          Y(I) = T
20.          IF (MM .GT. T) THEN
21.             W = W + T
22.             MM = T
23.          END IF
24.       END DO
25. C$OMP END DO
26.
27. C$OMP CRITICAL
28.       IF ( MM .GT. M ) THEN
29.          M = MM
30.       END IF
31. C$OMP END CRITICAL
32.
33. C$OMP END PARALLEL
34.
35.      FOO = W - M
36.
37.      RETURN
38.      END

関数 FOO() には並列領域が 1 つあり、この並列領域には、SINGLE 構文とワークシェアリングの DO 構文、CRITICAL 構文がそれぞれ 1 つあります。こうした OpenMP 並列構文をすべて無視した場合、並列領域内のコードが行うのは、次のことです。

  1. 配列 X 内の値を配列 Y にコピーします。

  2. X 内の正の最大値を検出し、その値を M に格納します。

  3. X の一部要素の値を変数 W に蓄積します。

コンパイラが前述の規則に従って、この並列領域内の変数に適切なスコープを発見する仕組みをみてみましょう。

前述の並列領域では、INMMTWMX、および Y という変数が使用されています。コンパイラは次のことを決定します。

6.5 現在の実装の既知の制限事項

現在の Sun Studio Fortran 95 コンパイラの自動スコープ宣言に関する既知の制限事項は、次のとおりです。