real x / 1.0 /, y / 0.0 / print *, x/y end character string*5, out*20 double precision value external exception_handler i = ieee_handler('set', 'all', exception_handler) string = '1e310' print *, '入力文字列', string, ' は: ', value print *, '1e300 * 1e10 の値は:', 1e300 * 1e10 i = ieee_flags('clear', 'exception', 'all', out) end integer function exception_handler(sig, code, sigcontext) integer sig, code, sigcontext(5) print *, '*** IEEE 例外が発生しました!' return end |
実行時出力:
並列化されたプログラムをデバッグするには、新たな作業が必要になります。次に、その方法をいくつか示します。
エラーの原因を特定するためにすぐに試してみることができる手順がいくつかあります。
並列化をオフにする。
次の 2 つの方法があります。
並列化オプションをオフにする。 並列化を行わず、-O3 か -O4 を付けてコンパイルし、プログラムが正しく動作するかを確認します。
スレッド数を 1 に設定し、並列化オプションをオンにしてコンパイルします。 つまり、環境変数 PARALLEL に 1 を設定してプログラムを実行します。
問題が解決された場合は、問題の原因が複数のスレッドを使用していることにあることがわかります。
また、-C を付けてコンパイルし、添字の上下限を超えた配列の参照がないかを調べます。
-autopar を使用している場合、コンパイラが並列化すべきでないものを並列化していることもあります。
-reduction をオフにする。
-reduction オプションを使用している場合、合計縮約が発生し、わずかに異なる答えを出している可能性があります。このオプションをはずして実行してみてください。
fsplit または f90split を使用する。
ユーザーのプログラムに多数のサブルーチンがある場合は、fsplit(1) を使用してサブルーチンを別個のファイルに分割します。次に、一部のファイルに -autopar を付けて、一部には付けずにコンパイルします。
バイナリを実行し、結果を検証します。
この手順を繰り返して、問題を 1 つのサブルーチンにしぼり込みます。
-loopinfo を使用する。
並列化されているループと、並列化されていないループを調べます。
ダミーのサブルーチンを使用する。
何もしないダミーのサブルーチンや関数を作成します。並列化されているいくつかのループにこのサブルーチンへの呼び出しを挿入します。そして、コンパイルし直して、実行します。-loopinfo を使用して、どのループが並列化されているかを調べます。
正しい結果が得られるようになるまで、この処理を続けます。
ループを逆方向に逐次実行する。
DO I=1,N を DO I=N,1,-1 で置き換えます。結果が異なるときは、データ依存性があることを示しています。
ループインデックスを使用しない。
これを
DO I=1,N ... CALL SNUBBER(I) ... ENDDO |
これに置き換える
DO I1=1,N I=I1 ... CALL SNUBBER(I) ... ENDDO |