0

これはF90にありますが、OpenMPをサポートするすべての言語に問題が当てはまります。時間積分のために複数のストレージアレイを必要とするシミュレーションコードのデータを構造化する一般的な方法は、次のとおりです(現時点では2次元)。

REAL, DIMENSION(imax,jmax,n_sub_timesteps) :: vars

その後、次のように更新されます。

DO J = 1, jmax
  DO I = 1, imax
    vars(I,J,2) = func(vars(:,:,1))
  END DO
END DO

vars私の経験では、OpenMPはスレッドセーフではないと考えているため、実際にはこれらのループを並列化することはありません。しかし、プログラマーにとっては、明らかにそうです。

varsさらに実際の状況では、スレッドローカルにするのはコストがかかりすぎてデータをそこにコピーできないと仮定しましょう。

varsそれで、スレッドの依存関係の問題がないことを理解できないかもしれないが、実際にはないので、OpenMPをロックしないように穏やかに示唆する(別名強制する)方法はありますか?何かがスレッドセーフではなく、ロックが必要であることを伝える方法があることは知っていますが、スレッドごとにコピーを作成せずに逆を指定する方法はありますか?

4

1 に答える 1

3

OpenMPを自動並列化と間違えたようです。セクションまたはステートメントの導入(または句のある並列領域の終わり)によって明示的に指示されない限り、データロックを実行するOpenMP実装を認識していません。OpenMPコンパイラーは、データの依存関係の可能性についてコードを検査せず、並列実行を妨げます。これは完全にユーザーに任されています。保護されていない同時アクセスを実行したい場合は、それを実行できます。OpenMP対応のコンパイラーが実行を停止することはありません。次のコードは常に並列領域を生成し、チーム内のスレッド間で外部ループを分散します。CRITICALATOMICREDUCTION

!$OMP PARALLEL DO PRIVATE(I)
DO J = 1, jmax
  DO I = 1, imax
    vars(I,J,2) = func(vars(:,:,1))
  END DO
END DO
!$OMP END PARALLEL DO

一方、ほとんどのコンパイラに組み込まれている自動並列化機能は非常に保守的で慎重であり、通常、プログラマーからの明示的なヒントがなければ、あなたのようなケースを並列化することはできません。これらのヒントは通常、コンパイラー固有のディレクティブの形式です(Fortranではコメントとして、C / C ++ではプラグマとしてフォーマットされます)。たとえば、Intel Fortranは、!DEC$ PARALLELディレクティブに続くループ内の想定されるデータ依存関係を無視するようにヒントを与えるディレクティブをサポートしています。

!DEC$ PARALLEL
DO J = 1, jmax
  DO I = 1, imax
    vars(I,J,2) = func(vars(:,:,1))
  END DO
END DO

多くのコンパイラーは、自動並列化機能を実装するためにOpenMP実装とランタイム・ライブラリーを再利用します。したがって、結果の実行可能ファイルの動作は通常、のようなOpenMP環境変数で制御されますOMP_NUM_THREADS

並列OpenMPプログラムの実行速度が予想よりも遅い場合は、他にも多くの原因があります。主に、偽共有、キャッシュトラッシング、TLBトラッシング、メモリ帯域幅の制限、NUMAシステムでの非ローカルメモリアクセス、非一時的なロード/ストアの使用に関連しています。共有変数など。OpenMPは自動データロックを実行しているように見えるかもしれませんが、そうではありません。

于 2012-11-30T10:56:41.937 に答える