Parallel Lint による OpenMP* の確認

OpenMP を使用してシーケンシャル・アプリケーションから並列アプリケーションへの移行を迅速に行う場合、parallel lint を使用するとアプリケーションの開発時間とデバッグ時間を短縮することができるため、非常に便利です。ここでは、parallel lint を使用して並列アプリケーションを最適化する方法について説明します。parallel lint は、プログラムをスタティックかつグローバルに解析して、並列化における既存の問題と潜在的な問題を診断します。parallel lint の利点の 1 つは、ほかのルーチンに配置されているものを含め、すべての並列領域とワークシェアリング構造を考慮してチェックを行うことです。

1        parameter (N = 100)

2        real, dimension(N) :: x,y

3

4  !$OMP PARALLEL DEFAULT(SHARED)

5  !$OMP SECTIONS

6  !$OMP SECTION

7        do i = 1, N

8        call work(x, N, i)

9        call output(x, N)

10        end do

11  !$OMP SECTION

12        call work(y, N, N)

13        call output(y, N)

14  !$OMP END SECTIONS

15  !$OMP END PARALLEL

16        print *, x, y

17        end

18

19

20        subroutine work(x, N, i)

21          real, dimension(N) :: x

22          x(i) = i*10.0

23        end subroutine work

24

25        subroutine output(x, N)

26        real, dimension(N) :: x

27  !$OMP SINGLE

28          print *, x

29  !$OMP END SINGLE

tst.f(27): エラー #12200: SINGLE 宣言子は SECTIONS 宣言子の

ダイナミック・エクステントでは許可されていません (ファイル:tst.f 行:5)。

parallel lint は、プログラム・コンテキスト全体の OpenMP 宣言子 を診断する強力なツールです。また、データ依存と競合状態に関するデバッグエラーもチェックします。

1        parameter (N = 10)

2        integer i

3        integer, dimension(N) :: factorial

4

5        factorial(1) = 1

6  !$OMP PARALLEL DO

7        do i = 2, N

8            factorial(i) = i * factorial(i-1)

9        end do

10        print *, factorial

11        end

tst.f(8): 警告 #12246:

(ファイル:tst.f 行:8) から (ファイル:tst.f 行:8) までデータフロー依存関係があります。

"FACTORIAL" により、並列モードでプログラムが正しく実行されないことがあります。

コンパイルの基本

parallel lint 解析を有効にするには、/Qdiag-enable:sc-parallel[n] オプション (Windows*) または -diag-enable sc-parallel[n] オプション (Linux* および Mac OS*) 指定します。

parallel lint は IA-32 アーキテクチャーおよびインテル® 64 アーキテクチャーのみでサポートされています。

parallel lint には OpenMP オプション /Qopenmp (Windows) または -openmp (Linux および Mac OS) が必要です。このオプションを指定すると、OpenMP 宣言子 が処理され、parallel lint で並列化の解析が可能になります。OpenMP を指定しないで parallel lint を使用すると、コンパイラーは次のエラーメッセージを発行します。

コマンドライン・エラー: OpenMP* の並列化オプションが指定されていないため、parallel lint は呼び出されませんでした。

parallel lint を使用する場合、/Qopenmp オプションを追加してください。

Microsoft* Visual Studio* を使用している場合、parallel lint によって作成されるオブジェクト・ファイルとライブラリー・ファイルは製品のビルドには使用できないため、parallel lint 専用のビルド構成を作成してください。

基本チェック

parallel lint は、OpenMP を使用する並列プログラミングの初心者だけでなく、上級開発者にも便利なさまざまな OpenMP チェックを提供します。詳細は、「概要」を参照してください。

次の例では、parallel lint の最も便利な機能について紹介します。

ケース 1: 入れ子された領域

OpenMP プラグマに入れ子された並列領域がある場合、デバッグが困難です。入れ子された並列構造には、さまざまな制限が適用されます。parallel lint は、入れ子された parallel 文 (ほかのファイルに含まれているものも含む) をチェックできます。

次の例では、ワークシェアリング構造は WORKSHARINGCRITICALORDERED、または MASTER 構造の内部に入れ子できません。

1        parameter (N = 10)

2        real, dimension(N,N) :: x, y, z

3        x = 1.0

4        y = 2.0

5  !$OMP PARALLEL DEFAULT(SHARED)

6  !$OMP MASTER

7        call work(x, y, z, N)

8  !$OMP END MASTER

9  !$OMP END PARALLEL

10        print *, z

11        end

12

13        subroutine work(x, y, z, N)

14        real, dimension(N,N) :: x, y, z

15  !$OMP DO

16        do i = 1, N

17          do j = 1, N

18            z(i,j) = x(i,j) + y(j,i)

19          end do

20        end do

21        end subroutine work

tst.f(15): エラー #12200: LOOP 宣言子は MASTER 宣言子の

ダイナミック・エクステントでは許可されていません (ファイル:tst.f 行:6)。

ケース 2: データ共有属性節

既存のシリアル・アプリケーションをスレッド化する際には、データ共有節を正しい位置に記述する必要があります。parallel lint は、共有節の不適切な使用だけでなく、適切なデータ共有宣言子が不足していないかどうかを確認するのにも役立ちます。

次の例は、「NOWAIT も適用される構造で LASTPRIVATE 節が使用されている場合、オリジナルのリスト項目は、最後の反復または記述上において最後の SECTION 構造を実行するスレッドがそのリスト項目を確実に保存するために、バリア同期化が行われるまで未定義のままになる」[OpenMP 標準] という OpenMP 標準の制限を示します。

1        integer, parameter :: N=10

2        integer last, i

3        real, dimension(N) :: a, b, c

4        b = 10.0

5        c = 50.0

6  !$OMP PARALLEL SHARED(a, b, c, last)

7  !$OMP DO LASTPRIVATE(last)

8        do i = 1, N

9          a(i) = b(i) + c(i)

10          last = i

11        end do

12  !$OMP END DO NOWAIT

13  !$OMP SINGLE

14        call sub(last)

15  !$OMP END SINGLE

16  !$OMP END PARALLEL

17        end

18

19        subroutine sub(last)

20        integer last

21        print *, last

22        end subroutine sub

tst.f(14): エラー #12220: NOWAIT ワークシェアリング構文の LASTPRIVATE 変数 "LAST" が

バリアー同期の前に使用されています。

次の例は、「並列領域の実行中に割り当てられたプライベート・ポインターは、メモリーリークを回避するために、並列領域が終わる前にプログラムによって明示的に割り当てを解除する必要がある」という OpenMP 標準の制限を示します。

1        integer :: OMP_GET_THREAD_NUM

2        integer, pointer :: ptr

3        integer, pointer :: a(:)

4

5        call OMP_SET_NUM_THREADS(2)

6        allocate(ptr)

7        allocate(a(2))

8        ptr = 5

9        print *, ptr

10  !$OMP PARALLEL PRIVATE(ptr) SHARED(a)

11        allocate(ptr)

12        ptr = 3

13  !$OMP CRITICAL

14        a(OMP_GET_THREAD_NUM()+1) = ptr

15  !$OMP END CRITICAL

16  !$OMP END PARALLEL

17        print *, a

18        end

as_44_1.f(11): エラー #12359: メモリーリークを回避するために、private ポインター "PTR" は

並列領域 (ファイル:as_44_1.f 行:10) の前にプログラムで明示的に割り当て解除する必要があります。

ケース 3: データの依存性

並列プログラムでは動作が一定ではないため、データの依存性問題をデバッグすることは困難です。parallel lint は、プログラムを実行せずに、プログラム中のデータ依存性問題を特定することができます。

データの依存性を解析するには、診断で重要度 3 の parallel lint を指定します。

1        integer i, a(4)

2  !$OMP PARALLEL DO SHARED(i) NUM_THREADS(4)

3        do i=1,4

4           a(i) = loc(i)

5        end do

6  !$OMP END PARALLEL DO

7        print *,a

8        end

tst.f(3): 警告 #12246:

(ファイル:tst.f 行:3) から (ファイル:tst.f 行:3) までデータフロー依存関係があります。

"I" により、並列モードでプログラムが正しく実行されないことがあります。

ケース 4: スレッド・プライベート変数

1        integer a(1000)

2  !$OMP THREADPRIVATE(a)

3        integer i, sum

4

5  !$OMP PARALLEL DO

6        do i=1,1000

7           a(i) = i

8        end do

9  !$OMP END PARALLEL DO

10  !$OMP PARALLEL DO REDUCTION(+:sum)

11        do i=10,1000

12           sum = sum + a(i)

13        end do

14  !$OMP END PARALLEL DO

15        print *,sum

16        end

tst.f(12): エラー #12344: THREADPRIVATE 変数 "A" が

初期値の異なるループで使用されています。

(ファイル:tst.f 行:6) と (ファイル:tst.f 行:11) のループを確認してください。

ケース 5: リダクション

リダクションは並列プログラミングで広く使われていますが、さまざまな制限があります。parallel lint は、リダクションに関する潜在的な問題を回避するのに役立ちます。この例では、REDUCTION 節に記述する変数は、囲まれたコンテキスト内で SHARED でなければならないという OpenMP API の明示的な制限を示します。

1        integer i, j

2        real a

3

4  !$OMP PARALLEL PRIVATE(a)

5        do i = 1, 10

6        call sub(a,i)

7        end do

!$OMP SINGLE        !

9        print *, a

10  !$OMP END SINGLE

11  !$OMP END PARALLEL

12        end

13

14        subroutine sub(a,i)

15        integer i

16        real a

17  !$OMP DO REDUCTION(+: a)

18          do j = 1, 10

19              a = a + i + j

20          end do

21        end subroutine sub

as_35_1.f(17): エラー #12208: 変数 "A" は REDUCTION 句

(ファイル:as_35_1.f 行:4) で指定されているため、囲まれたコンテキストで SHARED でなければなりません。