インテル® Fortran コンパイラー 16.0 ユーザー・リファレンス・ガイド
OpenMP* API コンパイラー宣言子を持つプログラムは、単一のスレッドとして実行を開始します。これは、初期スレッドの実行と呼ばれます。最初の並列構造が検出されるまで、初期スレッドは、シーケンシャルに実行します。
OpenMP* API では、PARALLEL と END PARALLEL 宣言子は並列構造の範囲を定義します。初期スレッドが並列構造を検出すると、その初期スレッドがチームのマスターとなり、スレッドのチームを作成します。並列構造に囲まれたプログラム文はすべて (そこから呼び出されるすべてのルーチンを含む)、チーム内の各スレッドごとに並列で実行されます。
構造内で字句的に囲まれた文は、構造の静的範囲を定義します。動的範囲には、スレッドによる構造の実行中に実行されるすべての文 (呼び出される全ルーチンを含む) が含まれます。
1 つのスレッドが並列構造によって囲まれた構造化ブロックの終わりに到達すると、そのスレッドは、チーム内のすべてのスレッドが到着するまで待機します。すべてのスレッドが到着すると、チームは消滅し、マスタースレッドのみが次の並列構造のコードの実行を続けます。チーム内の他のスレッドは、別のチームの形成で必要になるまで待機状態になります。単一プログラム内で並列構造は何回でも指定できます。結果として、プログラム実行中に、スレッドのチームは何度も生成され消滅します。
次の例は、上位レベルから OpenMP* 構造の実行モデルを示します。コードのコメントは、各構造やセクションの説明です。
例 |
---|
PROGRAM MAIN ! シリアル実行の開始。 ... ! 初期スレッドのみ実行する。 !$OMP PARALLEL ! 並列構造を開始し、チームを形成する。 ... ! このコードは各チームメンバーにより実行される。 !$OMP SECTIONS ! ワークシェア構造の開始。 !$OMP SECTION ! 1 つの作業単位。 ... ! !$OMP SECTION ! 別の作業単位。 ... ! !$OMP END SECTIONS ! 両方の作業単位の完了を待機する。 ... ! 複製されたコード。 !$OMP DO ! ワークシェア構造を開始する。 DO ! 各反復が作業単位。 ... ! チーム内で作業を分配。 END DO ! !$OMP END DO NOWAIT ! ワークシェア構造の終了。 ! NOWAIT が指定されているので待機不要。 ! このコードは各チームメンバーにより実行される。 !$OMP CRITICAL ! クリティカル構造の開始。 ... ! 一度に 1 つのスレッドでのみ実行する。 !$OMP END CRITICAL ! クリティカル構造の終了。 ... ! このコードは各チームメンバーにより実行される。 !$OMP BARRIER ! すべてのチームメンバーが到着するまで待機する。 ... ! このコードは各チームメンバーにより実行される。 !$OMP END PARALLEL ! 並列構造の終了。! チームを解散し、シリアル実行を継続する。 ... ! 別のの並列構造。 END PROGRAM MAIN ! シリアル実行の終了。 |
並列構造内で呼び出されたルーチンで、宣言子を使用することができます。並列構造の静的範囲ではなく、動的範囲の宣言子は、親なし宣言子と呼ばれます。親なし宣言子は、プログラムのシーケンシャル・バージョンに最小限の変更を行うだけで、プログラム部分を並列に実行できます。この機能を使用すると、プログラム・コール・ツリーの最上位レベルで並列構造をコーディングでき、宣言子を使用して呼び出されるすべてのルーチンの実行を制御することができます。次に例を示します。
例 |
---|
subroutine F ... !$OMP PARALLEL... call G ... subroutine G !$OMP DO... ! 親なし宣言子 ... |
並列領域が subroutine G で字句的に指定されていないので、これが親なし DO ループ宣言子となります。
データ環境制御
並列およびワークシェア構造内でデータ環境を制御できます。宣言子と宣言子のデータ環境節を使用して、THREADPRIVATE 宣言子で名前付きグローバル・ライフタイム・オブジェクトをプライベート化したり、またはデータ環境節をサポートする宣言子のデータ環境節でデータスコープ属性を制御できます。
データスコープ属性節:
DEFAULT
PRIVATE
FIRSTPRIVATE
LASTPRIVATE
REDUCTION
SHARED
データコピー節:
COPYIN
COPYPRIVATE
複数の宣言子節を使用して、変数のデータスコープ属性を指定した構造の継続期間中にその属性を制御することができます。ただし、宣言子でデータスコープ属性節を指定しない場合、宣言子に影響を受ける変数の動作はデフォルトのスコープ規則によって決まります。これは、OpenMP* API 仕様で説明されています。
ワークロードがアプリケーションの (一定ではない) 入力に依存するアプリケーションでは、入力サイズが確認されるランタイム時まで、使用するスレッド数の決定を保留します。スレッド数に影響を与えるワークロードの入力パラメーターには、行列のサイズ、データベースのサイズ、イメージ/ビデオのサイズおよび解像度、ツリーベースの構造体の階層の深さ/幅/種類、およびリストベースの構造体のサイズなどが含まれます。同様に、プロセッサー数が一定ではないシステムで実行するように設計されたアプリケーションでも、マシンサイズが確認されるアプリケーション・ランタイム時まで、使用するスレッド数の決定を保留します。
入力データから処理の量を予測できないアプリケーションでは、適切なスレッド数を選択するために、測定ステップを取り入れて、ワークロードおよびシステムの特性を確認することを推奨します。測定結果は、ファイルシステムなど永久保管場所に格納することによって、(測定ステップのオーバーヘッドを抑え) 永続的に使用することができます。
システムの処理ユニット数を超えるスレッドを同時に使用しないでください。同時に使用すると、オペレーティング・システムによりプロセッサー上でスレッドが多重化され、パフォーマンスが最適化されません。
ライブラリーを開発する場合 (アプリケーション全体を開発する場合とは異なり)、ライブラリーによって使用されるスレッド数を簡単に選択できるメカニズムを使用してください。これは、より高度な並列化を使用している場合、ライブラリー内の並列化が必要ないためです。
並列領域で NUM_THREADS 節を使用して、使用するスレッド数を制御し、並列領域で if 節を使用してマルチスレッドを使用するかどうかを決定します。OMP_SET_NUM_THREADS ルーチンも使用することができますが、呼び出し側のスレッドにより作成される並列領域にも影響します。NUM_THREADS 節の効果はローカルであるため、ほかの並列領域には影響しません。明示的なスレッド数の設定には、次のような短所があります。
多数のプロセッサーを搭載したシステムで、アプリケーションはすべてのプロセッサーではなく、その一部を使用します。
少数のプロセッサーを搭載したシステムで、アプリケーションはパフォーマンスの低下につながるオーバーサブスクリプションを強制する可能性があります。
インテルの OpenMP* ランタイムは、OMP_SET_NUM_THREADS ルーチンを使用しない限り、利用可能な論理プロセッサー数と同じ数のスレッドを生成します。実際の制限を特定するには、OMP_GET_THREAD_LIMIT() と OMP_GET_MAX_ACTIVE_LEVELS() を使用します。システムがオーバーロードしないように、開発者はスレッドの使用と並列処理の入れ子構造に注意する必要があります。OMP_THREAD_LIMIT 環境変数は、OpenMP* プログラム全体に使用する OpenMP* スレッドの数を制限します。OMP_MAX_ACTIVE_LEVELS 環境変数は、アクティブな入れ子構造の並列領域の数を制限します。
どの OpenMP* 構文を別のどの OpenMP* 構文で入れ子にできるかとその動作については、さまざまなバインド設定によって説明されます。
OpenMP* 構文のバインド領域は、実行コンテキストと宣言子の有効範囲を決める領域です。
ORDERED 構文のバインド領域は、最内の DO ループ領域です。
TASKWAIT 構文のバインド領域は、最内の TASK 領域です。
現在のチームがバインドスレッドであるか、現在のチームタスクがバインドタスクであるその他すべての構文のバインド領域は、最内の PARALLEL 領域です。
バインドタスクが生成されるタスクである構文のバインド領域は、生成されるタスクの領域です。
PARALLEL 構文は、アクティブでなくても、明示的でなくても、バインド領域になります。
TASK 構文は、明示的でなくても、バインド領域になります。
領域は、最内の並列領域外のいかなる領域ともバインドしません。
OpenMP* 構文のバインドタスクは、領域の実行により影響を受ける、または領域の実行にコンテキストを与えるタスクのセットです。特定の構文のバインドタスクは、すべてのタスク、現在のチームタスク、または生成されるタスクです。
OpenMP* 構文のバインドスレッドは、領域の実行により影響を受ける、または領域の実行にコンテキストを与えるスレッドのセットです。特定の構文のバインドスレッドは、デバイス上のすべてのスレッド、グループのすべてのスレッド、現在のチーム、または到達スレッドです。