ここでは、OpenMP* の並列フレームワーク・コードを追加して、インテル® Advisor アノテーションで推奨された並列処理を実装する手順を説明します。
適切な共有リソースの同期を追加するため、LOCK アノテーションをガイドとして使用して OpenMP* コードを追加します。
OpenMP* のタスクを生成するコードを追加するため、サイト/タスクのアノテーションをガイドとして使用します。
アノテーションを OpenMP* コードに置き換える際に推奨される手順は以下のとおりです。
LOCK アノテーションをガイドとして、適切な共有リソースの同期を追加します。
並列タスクを使用して非決定論的な動作を追加する前に、問題がないか検証するためテストを行います。
サイト/タスクのアノテーションをガイドとして、OpenMP* の並列セクションを生成するコードを追加します。
プログラムが正しく動作することを確認するため、単一のスレッドでテストを行います。例えば、プログラムを実行する前に環境変数 OMP_NUM_THREADS を 1 に設定します。
マルチスレッドが期待どおりに動作することを確認するため、複数のスレッドでテストを行います。
OpenMP* はワーカースレッドを自動的に生成します。一般に、開発者はタスクについてのみ考え、ワーカースレッドの生成と破棄は並列フレームワークに任せるべきです。
ワーカースレッドの生成と破棄で何らかの制御が必要である場合、コンパイラーのドキュメントを参照してください。例えば、スレッド数を制限するには、OMP_THREAD_LIMIT または OMP_NUM_THREADS 環境変数を設定します。
次の表は、並列処理を適用可能な典型的な例を示します。左のカラムはアノテーションが追加されたシリアルコードで、右のカラムは等価な OpenMP* C/C++ と Fortran 並列コードです。
| インテル® Advisor のアノテーションを追加した C/C++ と Fortran シリアルコード | OpenMP* を使用した C/C++ と Fortran 並列コード |
|---|---|
// C/C++: 同期
ANNOTATE_LOCK_ACQUIRE(0);
Body();
ANNOTATE_LOCK_RELEASE(0);
|
// 同期には OpenMP* の critical セクション、 // atomic 操作、ロック、および reduction 操作 // (以降で説明) を使用できます |
! 同期、Fortran
call annotate_lock_acquire(0)
body
call annotate_lock_release(0) |
// 同期には OpenMP* の critical セクション、 // atomic 操作、ロック、および reduction 操作 // (以降で説明) を使用できます |
// データ並列 - カウント付き C/C++
// ループ内で 1 つのタスク
ANNOTATE_SITE_BEGIN(site);
for (i = 0; i < n; ++i) {
ANNOTATE_ITERATION_TASK(task);
ステートメント;
}
ANNOTATE_SITE_END();
|
// データの並列処理 - 1 つのタスクの
// カウント付き C/C++ ループ
#pragma omp parallel for
for (int i = 0; i < n; ++i) {
ステートメント;
}
|
! データ並列 - カウント付き Fortran! ループで 1 つのタスク
call annotate_site_begin("site1")
do i = 1, N
call annotate_iteration_task("task1")
ステートメント
end do
call annotate_site_end
|
! データ並列 - カウント付き Fortran! ループで 1 つのタスク
! $omp parallel do
do i = 1, N
ステートメント
end do
! $omp end parallel do
|
// 並列 C/C++ 関数
ANNOTATE_SITE_BEGIN(site);
ANNOTATE_TASK_BEGIN(task1);
function_1();
ANNOTATE_TASK_END();
ANNOTATE_TASK_BEGIN(task2);
function_2();
ANNOTATE_TASK_END();
ANNOTATE_SITE_END();
|
// C/C++ 関数の並列化
#pragma omp parallel // 並列領域の開始
{
#pragma omp sections
{
#pragma omp section
function_1();
#pragma omp section
function_2();
}
} // 並列領域の終了
|
! 並列 Fortran 関数
call annotate_site_begin("site1")
call annotate_task_begin("task1")
call subroutine_1
call annotate_task_end
call annotate_task_begin("task2")
call subroutine_2
call annotate_task_end
call annotate_site_end
|
! 並列 Fortran 関数
!$omp parallel ! 並列領域開始
!$omp sections
!$omp section
call subroutine_1
!$omp section
call subroutine_2
!$omp end sections
!$omp end parallel ! 並列領域終了
|