OpenMPTM アプリケーションプログラミングインタフェース (API) は、共用メモリーマルチプロセッサアーキテクチャー用に複数のコンピュータベンダーと共同で開発された並列プログラミングモデルです。Fortran、C++ および C の OpenMP プログラムを dbx を使用してデバッグするためのサポートは、dbx の汎用マルチスレッドデバッグ機能に基づいています。スレッドおよび LWP 上で動作するすべての dbx コマンドは OpenMP デバッグに使用できます。dbx は、OpenMP デバッグでの非同期スレッド制御はサポートしていません。
この章の内容は次のとおりです。
Sun Studio Fortran 95 および C コンパイラによって実装される指示、実行時ライブラリルーチン、および OpenMP Version 2.0 アプリケーションプログラムインタフェースの環境変数については、『OpenMP API ユーザーズガイド』を参照してく ださい。
OpenMP デバッグが行えるのは Solaris OS の動作しているプラットフォームのみです。Linux プラットフォームで行うことはできません。
OpenMP デバッグの詳細については、OpenMP コードがコンパイラによってどのように変換されるかを理解することが役立ちます。次に Fortran の例を示します。
1 プログラムの例 2 integer i, n 3 parameter (n = 1000000) 4 real sum, a(n) 5 6 do i = 1, n 7 a(i) = i*i 8 end do 9 10 sum = 0 11 12 !$OMP PARALLEL DO DEFAULT(PRIVATE), SHARED(a, sum) 13 14 do i = 1, n 15 sum = sum + a(i) 16 end do 17 18 !$OMP END PARALLEL DO 19 20 print*, sum 21 プログラムの例、終わり |
行 12 〜 18 のコードは並列領域です。f95 コンパイラは、コードのこのセクションを、 OpenMP 実行時ライブラリから呼び出されるアウトラインサブルーチンに変換します。このアウトラインサブルーチンには、内部で生成された名前が付きます。この場合は _$d1A12.MAIN_ です。次に f95 コンパイラは、 OpenMP 実行時ライブラリへの呼び出しによって並列領域用にコードを置換して、アウトラインサブルーチンを引数の 1 つとして渡します。OpenMP 実行時ライブラリはすべてのスレッド関連実行を処理し、アウトラインサブルーチンを並列で実行するスレーブスレッドをディスパッチします。C コンパイラも同様に動作します。
OpenMP プログラムをデバッグするときには、アウトラインサブルーチンは dbx によって別の関数として扱われますが、内部生成された名前を使用して関数内のブレークポイントを明示的に設定することはできません。
マルチスレッドプログラムのデバッグ用の機能に加えて、OpenMP プログラム内で dbx を使用して次のことが実行できます。
並列領域へのシングルステップ。並列領域は OpenMP 実行時ライブラリから呼び出されるため、実行のシングルステップは実際には、この目的のために作成されたスレーブスレッドによって実行される複数の実行ライブラリ呼び出しレイヤーがかかわってきます。並列領域にシングルステップ実行すると、最初にブレークポイントに到達したスレッドによってプログラムが停止します。このスレッドは、ステップを開始したマスターステップではなく、スレーブスレッドになります。
たとえば、「コンパイラによる OpenMP コードの変換」の Fortran を参照して、マスタースレッド t@1 が行 10 にあるとします。行 12 にシングルステップすると、実行時ライブラリ呼び出しを実行するためのスレーブスレッド t@2、t@3、および t@4 が作成されます。スレッド t@3 が最初にブレークポイントに到達し、プログラムの実行が停止します。したがって、スレッド t@1 によって開始されたシングルステップはスレッド t@3 で終了します。この動作は、シングルステップのあとに同じスレッドで行う通常のステップ実行とは異なります。
shared、private、および threadprivate 変数の出力。dbx は すべての shared、private、および threadprivate 変数を出力できます。並列領域外で threadprivate 変数を出力しようとすると、マスタースレッドのコピーが出力されます。whatis コマンドは変数が shared、private、または threadprivate のいずれであるかを通知しません。
並列領域で実行が停止されると、 where コマンドによってアウトラインサブルーチンを含むスタックトレースと複数の実行時ライブラリ呼び出しが表示されます。 「コンパイラによる OpenMP コードの変換」の Fortran の例を使用して実行を行 15 で停止すると、where コマンドによって次のスタックトレースが生成されます。
[t@4 l@4]: where 現スレッド: t@4 =>[1] _$d1A12.MAIN_(), 行番号 15 "example.f90" [2] __mt_run_my_job_(0x45720, 0xff82ee48, 0x0, 0xff82ee58, 0x0, 0x0), at 0x16860 [3] __mt_SlaveFunction_(0x45720, 0x0, 0xff82ee48, 0x0, 0x455e0, 0x1), at 0x1aaf0 |
スタックの上位フレームはアウトライン関数のフレームです。コードがアウトラインされていても、ソース行番号は 15 にマップされたままです。ほかの 2 つのフレームは実行時ライブラリルーチン用です。
並列領域で実行が停止されると、前述の例のようにスレーブスレッドの where コマンドはスタックトレースを親スレッドに戻しません。ただし、マスタースレッドの where コマンドは完全トレースバックを行います。
[t@4 l@4]: thread t@1 t@1 (l@1) で停止しました _$d1A12.MAIN_ 行番号 15 ファイル "example.f90" 15 sum = sum + a(i) [t@1 l@1]: where 現スレッド: t@1 =>[1] _$d1A12.MAIN_(), 行番号 15 "example.f90" [2] __mt_run_my_job_(0x41568, 0xff82ee48, 0x0, 0xff82ee58, 0x0, 0x0), at 0x16860 [3] __mt_MasterFunction_(0x1, 0x0, 0x6, 0x0, 0x0, 0x40d78), at 0x16150 [4] MAIN(), 行番号 12 "example.f90" |
いくつかのスレッドが大きくない場合、threads コマンド (「threads コマンド」参照) を使用してすべてのスレッドをリスト表示し、スレーブスレッド内で実行がどのようにブレークポイントに到達したかを判別し、各スレッドに切り替えてマスタースレッドを判別することができます。
並列領域で実行が停止すると、dump コマンドによって private 変数の複数のコピーが出力されます。次の例では、dump c コマンドが変数 i の 2 つのコピーを出力します。
[t@1 l@1]: dump i = 1 sum = 0.0 a = ARRAY i = 1000001 |
変数 i の 2 つのコピーが出力されるのは、アウトラインルーチンがホストルーチンのネストされた関数として実装され、private 変数がアウトラインルーチンの局所変数として実装されます。dump コマンドがスコープ内のすべての変数を出力する ため、ホストルーチン内の i およびアウトラインルーチン内の i の両方が表示されます。
OpenMP プログラム内の並列領域の内部にシングルステップするときの実行シーケンスは、ソースコードシーケンスとは同じではありません。シーケンスが異なるのは、並列領域内のコードが通常はコンパイラによって変換され再配置されるためです。OpenMP コード内でのシングルステップは、オプティマイザがコードを移動する最適化コード内でのシングルステップと似ています。