3

OpenMP 経由で fortran ループを並列化しようとしています。ループは本質的に 2 つのコマンドのみで構成されます。

do i=1,LSample
  calcSslice(Vpot(:,:,i), Sslice)
  rpold = rp
  combine_rp_matrices (rpold, Sslice, rp)
end do

calcSslice サブルーチンは Vpot(:,:,i) を読み取り、いくつかの計算を実行し、結果を行列 Sslice に格納します。Combine_rp_matrices は rpold と Sslice を使用して rp を更新します。rp は実行変数として機能し、プログラムの目的の出力です。異なる反復からの Sslice 行列が rp と結合される順序は関係ありません。このループを並列化する最初の試みは次のようになりました。

!$OMP PARALLEL DO DEFAULT(SHARED), PRIVATE(Sslice), SCHEDULE(DYNAMIC)
do i=1,LSample
  calcSslice(Vpot(:,:,i), Sslice)
!$OMP CRITICAL
  rpold = rp
  combine_rp_matrices (rpold, Sslice, rp)
!$OMP END CRITICAL
end do
!$OMP END PARALLEL DO

これはコンパイルおよび実行されますが、間違った結果が生成されます。次のコードを使用すると、正しい結果が得られますが、実行がはるかに遅くなります (シリアル化されたコードよりも高速ですが)。

!$OMP PARALLEL DO DEFAULT(SHARED), PRIVATE(Sslice), SCHEDULE(DYNAMIC)
do i=1,LSample
!$OMP CRITICAL(Crit2)
  calcSslice(Vpot(:,:,i), Sslice)
!$OMP END CRITICAL(Crit2)
!$OMP CRITICAL
  rpold = rp
  combine_rp_matrices (rpold, Sslice, rp)
!$OMP END CRITICAL
end do
!$OMP END PARALLEL DO

そのため、calcSslice との同期に問題があるようです。ただし、これがどこで発生するかはよくわかりません。Vpot は calcSslice から読み取られるだけで書き込まれず、Sslice は threadprivate 変数です。calcSslice で使用されるグローバル変数も読み取り専用です。変数 rpold と rp は、DO ループが含まれるサブルーチンのスコープ内で宣言されているため、calcSslice からアクセスすることはできません。calcSslice で宣言された変数は、intent(in)、intent(out)、target、pointer の属性を使用します。

これはどこが間違っていますか?

編集:問題は解決されました。原因は、属性calcSsliceを意味する宣言中の変数の初期化でした。save

4

1 に答える 1

2

私の推測では、それcalcSsliceはスレッドセーフではありません。このサブルーチンが読み取り専用以外のグローバル変数にアクセスせず、save属性を使用しないことを確認してください (宣言中に変数を初期化する場合は、暗黙の保存に注意してください!)。Intel が提供するようなスレッドチェッカーを使用して、コード内の競合状態を見つけることができます。そのようなソフトウェアにアクセスできない場合は、ダミーの手順から始めて、ルーチンを段階的に入力して、失敗した場所を確認します。

もう 1 つ困惑するのは、ループ本体の最後の 2 行です。すべてのスレッドがマトリックス全体をバックアップしてから、スライスを追加します。reductionすべてのスライスを (節などで)集めてから、その大きなスライスを 1 回結合する方がよいのではないでしょうか?

于 2013-09-08T05:53:16.427 に答える