OpenMP* によるプログラミング

インテル® Fortran コンパイラは、OpenMP* ディレクティブを含む Fortran プログラムを入力ファイルとして処理し、マルチスレッド・バージョンのコードを生成します。並列プログラムが実行を開始する際に存在する単一スレッドは、 マスタスレッドと呼ばれます。並列領域に到達するまで、マスタスレッドはシーケンシャルに処理を続行します。

並列領域

並列領域とは、1 つのスレッドチームによって並列に実行されなければならない 1 ブロックのコードです。OpenMP Fortran API では、並列構造は OpenMP ディレクティブ PARALLEL をコード・セグメントの最初に、そして END PARALLEL を最後に配置することによって定義されます。このように境界のあるコード・セグメントは、並列実行が可能です。

コードの構造ブロックとは、最初と最後に単一の入口/出口ポイントを持つ、1 つまたは複数の実行文の集まりです。

インテル Fortran コンパイラはワークシェアリング構造および同期化構造をサポートします。これらの各構造は、特定の 1 つまたは 2 つの OpenMP ディレクティブと、囲まれた、または後続するコードの構造ブロックから構成されます。構造の詳細な定義については、「OpenMP Fortran version 2.0 仕様」を参照してください。

並列領域の最後で、スレッドはすべてのチームメンバが到達するまで待機します。そして、チームは論理的になくなり (次の並列領域で再利用されることもあります)、マスタスレッドは次の並列領域が検出されるまでシーケンシャルに処理を続行します。

ワークシェアリング構造

ワークシェアリング構造は、それを囲む並列領域に入る時点で作成されたチームメンバ間で、囲まれたコード領域の実行を分割します。マスタスレッドが並列領域に入ると、スレッドチームが形成されます。並列領域の最初から開始して、ワークシェアリング構造が検出されるまで、コードは複製されます (すべてのチームメンバによって実行されます)。ワークシェアリング構造は、チームのメンバ間で、囲まれたコード領域の実行を分割します。

OpenMP の SECTIONS または DO 構造は、その囲まれた作業を現在のチームのスレッド間に分配するため、ワークシェアリング構造として定義されます。ワークシェアリング構造は、並列領域の動的実行中である場合にのみ分配されます。ワークシェアリング構造が並列領域の記述範囲内にあれば、チームのメンバ間で処理を分配することにより、そのワークシェアリング構造は常に実行されます。ワークシェアリング構造が並列領域に字句的 (明示的) に囲まれていない場合 (つまり、構造が孤立 (orphan) している場合)、そのワークシェアリング構造は、最も近い動的範囲の並列領域のチームメンバ間に分配されます(これが存在する場合)。動的範囲の並列領域が存在しない場合、構造はシーケンシャルに実行されます。

1 つのスレッドがワークシェアリング構造の最後に到達すると、構造内のすべてのチームメンバが処理を終了するまで待機する場合があります。ワークシェアリング構造によって定義されたすべての処理が終了すると、チームは ワークシェアリング構造を出て、後に続くコードの実行を続行します。

並列/ワークシェアリング複合構造とは、ワークシェアリング構造を 1 つだけ含む並列領域を示します。

並列処理ディレクティブ・グループ

並列処理ディレクティブには次のグループが含まれます:

並列領域

ワークシェアリング構造

並列/ワークシェアリング複合構造

並列/ワークシェアリング複合構造は、単一のワークシェアリング構造が含まれる並列領域を指定するための短縮形を提供します。並列/ワークシェアリング複合構造は次のとおりです:

同期化構造および MASTER

同期化とは、共有データの一貫性を保証し、スレッド間の並列実行を調整するスレッド間通信です。データがアクセスされる際にすべてのスレッドが同じ値を取得する場合、スレッドのチームの共有データは一貫しています。同期化構造は、 共有データの一貫性を保証するために使用されます。

詳細は、「OpenMP ディレクティブと節」のリストを参照してください。

データの共有

データの共有は、SHARED および PRIVATE 節を使用して、並列領域または ワークシェアリング構造の最初で指定されます。SHARED 節に含まれているすべての変数は、チームメンバ間で共有されます。以下の項目は、アプリケーション側で行う必要があります:

また、SHARED および PRIVATE 変数に加えて、THREADPRIVATE ディレクティブを使用することで、個々の変数および 共通ブロック全体をプライベート化することができます。

孤立ディレクティブ

OpenMP には、並列ディレクティブの表現力を大幅に向上する孤立化と呼ばれる機能が含まれています。孤立化では、並列領域に付けられているディレクティブが 1 つのプログラム・ユニットの記述範囲内にある必要がありません。CRITICAL、BARRIER、SECTIONS、SINGLE、MASTER および DO などのディレクティブは、ラインタイム時に、囲まれた並列領域に動的に “バインド” し、プログラム・ユニット内に出現することができます。

孤立ディレクティブは、コードに最小限の変更を行うだけで、既存のコードを並列処理することができます。また、孤立化は 1 つの並列領域を、呼び出されたサブルーチン内にある複数の DO ディレクティブとバインドすることでパフォーマンスの向上を可能にします。次のコード・セグメントを参照してください。

...
!$omp parallel
call phase1
call phase2
!$omp end parallel
...

subroutine phase1
!$omp do private(i) shared(n)
do i = 1, n
call some_work(i)
end do
!$omp end do
end


subroutine phase2
!$omp do private(j) shared(n)
do j = 1, n
call more_work(j)
end do
!$omp end do
end

次に示す孤立ディレクティブの使用規則が適用されます。

OpenMP 処理を行うコードの準備

OpenMP を使用するためにコードを準備するには、次の段階と手順に従ってください。一般的に、最初の 2 つの段階は単一プロセッサ・システムまたはマルチプロセッサ・システムのいずれでも行うことができますが、その後の段階は通常、マルチプロセッサ・システムで行います。

OpenMP ディレクティブを挿入する前に

OpenMP 並列ディレクティブを挿入する前に、次の方法でコードが安全に並列実行されることを確認してください:

解析

解析の主な手順は次のとおりです:

再編成

OpenMP を正しく実装するためにプログラムを再編成するには、次のいくつか、またはすべてを実行します。

      1. 選択したループが繰返しを並列に実行できる場合、このループに PARALLEL DO 構造を取り入れます。

      2. アルゴリズムを書き直して、繰返し間の依存関係を取り除くようにします。

      3. 依存関係にかかわる変数の使用と割り当ての周囲に CRITICAL 構造を配置し、残りの繰返し間の依存関係を同期化します。

      4. ループに存在する変数を適切な SHARED、PRIVATE、LASTPRIVATE、FIRSTPRIVATE、またはREDUCTION 内にリストします。

チューニング

チューニング・プロセスでは、SCHEDULE 節または omp_schedule 環境変数を使用して、クリティカル・セクションのシーケンシャル・コードを最小化し、負荷のバランスをはかります。


通常、この手順はマルチプロセッサ・システムで実行されます。