すべてまたは一部の元のループ反復が、ループ本体を実行していません。ピール/リマインダーループをループ本体へ移動することでパフォーマンスが改善されます。
データをアライメント
元のループ内のメモリーアクセスの一つが、 適切にアライメントされた境界から開始されていません。解決方法: データをアライメントし、コンパイラーにデータがアライメントされていることを知らせます。データをアライメントするには、__declspec(align()) を使用します。元のループの前で use __assume_aligned() を使用して、コンパイラーにデータがアライメントされていることを知らせます。
関連情報:
スレッド化と SIMD 命令の両方を使用してループを並列化
ループはスレッド化と自動ベクトル化されていますが、トリップカウントがベクトル長の倍数ではありません。解決方法: 次のすべてを行います。
オリジナルのコードサンプル:
!$omp parallel do schedule(static) do i = 1,1000 c(i) = a(i)*b(i) end do !$omp end parallel do
修正されたのコードサンプル:
!$omp parallel do simd schedule(simd: static) do i = 1,1000 c(i) = a(i)*b(i) end do !$omp end parallel do simd
関連情報:
スカラーのリマインダー生成を強制します
コンパイラーが生成したマスク付きのベクトル化されたリマインダーループは、効率良いベクトル化には反復数が少なすぎます。スカラーループがより適しています。解決方法: ディレクティブを使用してスカラー・リマインダーの生成を強制します。!DIR$ VECTOR NOVECREMAINDER。
subroutine add(A, N, X) integer N, X real A(N) ! リマインダー・ループをベクトル化しないことをコンパイラーに強制します !DIR$ VECTOR NOVECREMAINDER do i=x+1, n a(i) = a(i) + a(i-x) enddo end
関連情報:
ベクトルリマインダーの生成を強制します
コンパイラーはリマインダー・ループをベクトル化しませんでしたが、パフォーマンスは向上します。解決方法: ディレクティブを使用してベクトル化を強制します。!DIR$ VECTOR VECREMAINDER。
subroutine add(A, N, X) integer N, X real A(N) ! リマインダー・ループのベクトル化をコンパイラーに強制します !DIR$ VECTOR VECREMAINDER do i=x+1, n a(i) = a(i) + a(i-x) enddo end
関連情報:
推測されるループの反復数を指定
コンパイラーは静的にトリップカウントを認識できません。解決方法: ディレクティブ!DIR$ LOOP COUNT。
推測されるループの反復を最小 3、最大 10、平均 5 に設定:
!DIR$ LOOP COUNT MAX(10), MIN(3), AVG(5) do i =1, m b(i) = a(i) + 1 d(i) = c(i) + 1 enddo
関連情報:
チャンクサイズを変更します
ループは、!$omp parallel for simdディレクティブを使用してスレッド化とベクトル化されています。特に、このディレクティブはループ反復をチャンク (サブセット) に分割して、チャンクをスレッドに分配することで、チャンクの反復は SIMD 命令を使用して同時に実行されます。この場合、チャンクサイズ (チャンクごとの反復数) がベクトル長の倍数ではありません。解決方法: ベクトル宣言にschedule (simd: [kind])修飾子を!$omp parallel for simdディレクティブに追加します。
最大ベクトル長を保証します。
!$omp parallel do simd schedule(simd: static) do i = 1,1000 c(i) = a(i)*b(i) end do !$omp end parallel do simd
関連情報:
データのパディングを行います
トリップカウントがベクトル長の倍数ではありません。解決方法: 次のいずれかを行います。
関連情報:
トリップ・カウント・データを収集
サーベイレポートで、正確な推奨を作成するにはトリップ・カウント・データが不足しています。
アンロールを無効にします
ループアンロール後のトリップカウントは、ベクトル長と比べると小さすぎです。解決方法: ループのアンロールを行わないか、ディレクティブを使用してアンロール係数を減らします。!DIR$ NOUNROLL または !DIR$ UNROLL。
!DIR$ NOUNROLL でループの自動アンロールを無効化します。
!DIR$ NOUNROLL do i = 1, m b(i) = a(i) + 1 d(i) = c(i) + 1 enddo
関連情報:
小さなベクトル長を使用します
コンパイラーはベクトル長を選択しましたが、トリップカウントはベクトル長よりも小さめです。解決方法: ディレクティブを使用して小さなベクトル長を指定します。!$OMP SIMD SIMDLEN。
!$OMP SIMD SIMDLEN(4) do i = 1, m b(i) = a(i) + 1 d(i) = c(i) + 1 enddo
インテル® Fortran コンパイラーのバージョン 19.0 以降には、コンパイラーがコストに基づいて最適なベクトル長を選択できるように指示する新しい vectorlength 句があります。!DIR$ VECTOR VECTORLENGTH (vl1, vl2, ..., vln)説明:vl は、2 の整数乗です。
!DIR$ VECTOR VECTORLENGTH(2, 4, 16) do i = 1, m b(i) = a(i) + 1 d(i) = c(i) + 1 enddo
関連情報:
動的なアライメントを無効にします
コンパイラーは、ベクトルループをメモリー参照に合わせて、反復をベクトルループからスカラーループに自動的にピールします。ただし、この最適化が常に最適であるとは限りません。パフォーマンスを向上するには、次のディレクティブを使用して自動ピールを無効にします。!DIR$ VECTOR NODYNAMIC_ALIGN。
...!DIR$ VECTOR NODYNAMIC_ALIGN do i = 1, len a(i) = b(i) * c(i) enddo
関連情報:
ユーザー定義関数内のループ本体はベクトル化されません。
インライン展開を有効にします
ユーザー定義関数のインライン展開はコンパイラー・オプションで無効化されています。解決方法: インライン展開を制御するため、Obまたはinline-levelコンパイラー・オプションを使用している場合、引数0を引数1に置き換えて、inlineキーワードや属性で指定されるインライン展開を有効にするか、引数2で、すべての関数のインライン展開をコンパイラーの判断に任せます。
Windows* |
Linux* |
---|---|
/Ob1 または /Ob2 | -inline-level=1 または -inline-level=2 |
関連情報:
ループ内のシリアル化された関数をベクトル化します
Target | ディレクティブ |
---|---|
元のループ | !$OMP SIMD |
内部関数定義や宣言 | !$OMP DECLARE SIMD |
real function f (x) !DIR$ OMP DECLARE SIMD real, intent(in), value :: x f= x + 1 end function f !DIR$ OMP SIMD do k = 1, N a(k) = f(k) enddo
関連情報:
ループ本体内の数学関数呼び出しは、コンパイラーがループを効率良くベクトル化するのを妨げます。ベクトル数学関数を使用することでパフォーマンスを改善します。
インライン展開を有効にします
インライン展開はコンパイラーによって無効化されています。解決方法: インライン展開を制御するため、Obまたはinline-levelコンパイラー・オプションを使用している場合、引数0を引数1に置き換えて、inlineキーワードや属性で指定されるインライン展開を有効にするか、引数2で、すべての関数のインライン展開をコンパイラーの判断に任せます。
Windows* |
Linux* |
---|---|
/Ob1 または /Ob2 | -inline-level=1 または -inline-level=2 |
あるいは、#include <mathimf.h>ヘッダーを標準の#include <math.h>に置き替えて、浮動小数点計算を行うアプリケーションで一般的に使用される最適化された高精度の数学関数を呼び出します。
関連情報:
ループ内の数学関数呼び出しをベクトル化します
浮動小数点モデル precise を使用すると、アプリケーションはシリアル化された数学関数を呼び出します。解決方法: 次のいずれかを行います。
Windows* |
Linux* |
---|---|
/Qfast-transcendentals | -fast-transcendentals |
subroutine add(A, N, X) integer N, X real A(N) !DIR$ OMP SIMD do i=x+1, n a(i) = a(i) + a(i-x) enddo end
関連情報:
浮動小数点モデルを変更します
strict 浮動小数点モデルを使用すると、アプリケーションはシリアル化された数学関数を呼び出します。strict浮動小数点モデルを使用すると、アプリケーションはシリアル化された数学関数を呼び出します。解決方法: 次のいずれかを行います。
Windows* |
Linux* |
---|---|
/fast | -fp-model fast |
/fp:precise /Qfast-transcendentals | -fp-model precise -fast-transcendentals |
gfortran program.for -O2 -fopenmp -fp-model precise -fast-transcendentals !DIR$ OMP SIMD COLLAPSE(2) do i = 1, N a(i) = b(i) * c(i) do j = 1, N d(j) = e(j) * f(j) enddo enddo
関連情報:
Glibc ライブラリーとベクトル化された SVML 関数を使用します
アプリケーションは、ベクトル化されたバージョンの数学関数ではなく、スカラー関数を呼び出しています。解決方法: 次のすべてを行います。
gfortran PROGRAM.FOR -O2 -fopenmp -ffast-math -lrt -lm -mavx2 program main parameter (N=100000000) real*8 angles(N), results(N) integer i call srand(86456) do i=1,N angles(i) = rand() enddo !$OMP SIMD do i=1,N results(i) = cos(angles(i)) enddo end
関連情報:
ベクトル組込み関数にインテルの SVML を使用
アプリケーションは、ベクトル化されたバージョンの数学関数ではなく、スカラー関数を呼び出しています。解決方法: 次のすべてを行います。
gfortran PROGRAM.FOR -O2 -ftree-vectorize -funsafe-math-optimizations -mveclibabi=svml -L/opt/intel/lib/intel64 -lm -lsvml -Wl,-rpath=/opt/intel/lib/intel64 program main parameter (N=100000000) real*8 angles(N), results(N) integer i call srand(86456) do i=1,N angles(i) = rand() enddo ! the loop will be auto-vectorized do i=1,N results(i) = cos(angles(i)) enddo end
関連情報:
コンパイラーがベクトル操作で使用するデータの間接、または不規則なストライドアクセスを想定しました。次のような通常のストライド・アクセス・パターンを検出するため、コンパイラーに通知することでメモリーアクセスを改善します。
パターン |
説明 |
---|---|
不変 | 命令はループ全体で同じメモリーの値にアクセスします。 |
均一 (水平方向は不変) | 命令はベクトル反復で同じメモリーの値にアクセスします。 |
垂直方向は不変 | 命令はすべてのベクトル反復間で同じオフセットを使用してメモリー位置にアクセスします。 |
ユニット | 命令はループ全体でベクトル反復 = ベクトル長のストライドで連続したメモリーの値をアクセスします。 |
一定 (非ユニット) | 命令は反復間で同じストライドを使用してメモリー位置にアクセスします。 |
検出された通常のストライド・アクセス・パターンでコードをリファクタリングします
メモリー・アクセス・パターン・レポートは次の通常ストライドアクセスを示します。
変数 |
パターン |
---|---|
block 0x2b05c877040 allocated at main.cpp:14 | ユニット |
block 0x2b05c877040 allocated at main.cpp:14 | 一定 (非ユニット) |
メモリー・アクセス・パターン・レポートのソース詳細表示を参照します。
メモリーアクセスを改善するには、次の操作を行います。コードをリファクタリングして、コンパイラーに通常のストライドアクセスであることを通知します。時に、複数ファイルにわたるプロシージャー間の最適化 (IPO) を有効にする、ipo/Qipo コンパイラー・オプションから利点が得られることがあります。
関連情報:
レジスターのスピルが検出されました。すべてのベクトルレジスターが使用中です。これは、スピルされた変数はメインメモリーに退避/復帰されるため、パフォーマンス上悪影響があります。ベクトルレジスターへの圧力を緩和してパフォーマンスを改善します。
アンロール係数を減らします
現在のディレクティブのアンロールの係数は、レジスターへの圧力を高めます。解決方法: ディレクティブを使用してアンロール係数を減らします。!DIR$ NOUNROLL または !DIR$ UNROLL。
!DIR$ UNROLL do i = 1, m b(i) = a(i) + 1 d(i) = c(i) + 1 enddo
関連情報:
ループを小さなループに分割します
高いレジスターへの圧力は、レジスタースピルの可能性を高め、効率良いベクトル化を妨げます。解決方法: !DIR$ DISTRIBUTE POINT ディレクティブを使用するか、コードを書き換えてループを分割します。これは、レジスターへの圧力を低くしてソフトウェア・パイプライン処理を有効にすることで、命令とデータキャッシュ両方の使用を改善できます。
!DIR$ DISTRIBUTE POINT do i = 1, m b(i) = a(i) + 1 ... c(i) = a(i) + b(i) ! コンパイラーがここで分割することを決定 ! ! データの依存関係があります ... d(i) = c(i) + 1 enddo do i =1, m b(i) = a(i) + 1 ...!DIR$ DISTRIBUTE POINT call sub(a, n) ! ここから分散を開始。 ! すべてのループ伝搬依存を無視 c(i) = a(i) + b(i) ... d(i) = c(i) + 1 enddo
関連情報:
コンパイラーが、ループ内でアンチ依存関係 (読み取り後の書き込み - WAR) または真の依存関係 (書込み後の読み取り - RAW) を想定しました。想定を調査して適切に処理することでパフォーマンスを改善します。
実際に依存関係があるか確認します
実際に依存関係がループ中にあるか確認できません。確認方法: 依存関係解析を実行します。
ベクトル化を有効にします
依存関係解析は与えられたワークロードでループの依存関係を検出しませんでした。キーワードrestrict または、ディレクティブを使用してベクトル化が安全であることをコンパイラーに通知します。
Target |
ディレクティブ |
---|---|
!$OMP SIMD | ループのすべての依存関係を無視。 |
!DIR$ IVDEP | ベクトルの依存関係のみを無視 (最も安全)。 |
!DIR$ IVDEP do i = 1, N-4, 4 a(i+4) = b(i) * c enddo
関連情報:
コンパイラーが、ループ内でアンチ依存関係 (読み取り後の書き込み - WAR) または真の依存関係 (書込み後の読み取り - RAW) を想定しました。想定を調査して適切に処理することでパフォーマンスを改善します。
依存関係の解決
依存性解析は、ループ内に実際の依存関係があることを示しています。解決方法: 次のいずれかを行います。
!$OMP SIMD SAFELEN(4) do i = 1, N-4, 4 a(i+4) = b(i) * c enddo
!$OMP SIMD REDUCTION(+:SUMX) do k = 1, size2 sumx = sumx + x(k) * b(k) enddo
関連情報:
ループ内に複数のデータ型が混在しています。データ型の変換を防ぐことでハードウェアのベクトル化サポートの効率を高めます。
最も小さなデータ型を使用します
ループは異なる幅のデータ型を含んでいます。解決方法: ベクトルレジスター幅全体を使用するため、必要な精度を提供する最小のデータ型を使用します。
例: 16 ビットのみ必要な場合、int より short を使用すると、4 ウェイと 8 ウェイの SIMD 並列処理のそれぞれ違いが実感できます。
ループ本体内のユーザー関数呼び出しは、コンパイラーがループをベクトル化するのを妨げます。
インライン展開を有効にします
ユーザー定義関数のインライン展開はコンパイラー・オプションで無効化されています。解決方法: インライン展開を制御するため、Ob または inline-level コンパイラー・オプションを使用している場合、引数 0 を引数 1 に置き換えて、inline キーワードや属性で指定されるインライン展開を有効にするか、引数2で、すべての関数のインライン展開をコンパイラーの判断に任せます。
Windows* |
Linux* |
---|---|
/Ob1 または /Ob2 | -inline-level=1または-inline-level=2 |
関連情報:
ループ内のユーザー関数をベクトル化します
コンパイラーはこれらのユーザー定義関数をベクトル化またはインライン展開できません:my_calc()解決方法: 次のいずれかを行います。
Target | ディレクティブ |
---|---|
元のループ | !$OMP SIMD |
内部関数定義や宣言 | !$OMP DECLARE SIMD |
real function f (x) !DIR$ OMP DECLARE SIMD real, intent(in), value :: x f= x + 1 end function f !DIR$ OMP SIMD do k = 1, N a(k) = f(k) enddo
関連情報:
Fortran SIMD 対応関数への書き換え
配列をELEMENTAL関数/サブルーチンに渡すと、ベクトル化を妨げる依存関係が生じます。解決方法:
Target | ディレクティブ |
---|---|
元のループ | !$OMP SIMD |
内部関数定義や宣言 | !$OMP DECLARE SIMD |
オリジナルコードの例:
elemental subroutine callee(t,q,r) real, intent(in) :: t, q real, intent(out) :: r r = t + q end subroutine callee ... do k = 1,nlev call callee(a(:,k), b(:,k), c(:,k)) end do ...
修正されたコードの例:
subroutine callee(t,q,r) !$OMP DECLARE SIMD(callee) real, intent(in) :: t, q real, intent(out) :: r r = t + q end subroutine callee ... do k = 1,nlev !$OMP SIMD do i = 1,n call callee(a(i,k), b(i,k), c(i,k)) end do end do ...
関連情報:
原因: インテル® コンパイラーを使用していないか、古いバージョンのインテル® コンパイラーを使用しています。それにもかかわらず、ベクトル化を妨げる問題はなく、ベクトル化が有益であるように示されることがあります。
ベクトル化の可能性を調査
自動ベクトル化を有効にしてコンパイルしても、コンパイラーはコードをベクトル化できないことがあります。ベクトル化の可能性を調査:
関連情報:
自動ベクトルを有効にします
自動ベクトル化を無効にしてコンパイルしています; 自動ベクトル化を有効にします。
関連情報:
ループ本体内のシステム関数呼び出しは、コンパイラーがループをベクトル化するのを妨げます。
システム関数呼び出しをループから排除します
一般にシステム関数やサブルーチン呼び出しはベクトル化されません; print 文はベクトル化を妨げる代表例です。解決方法: ループ内ではシステム関数の呼び出しを避けます。
ループ本体内の OpenMP* 関数呼び出しは、コンパイラーがループを効率良くベクトル化するのを妨げます。
OpenMP* API 呼び出しをループ本体の外へ移動します
不変でないなどの理由によって、コンパイラーが OpenMP* 呼び出しをループ本体の外へ移動できない場合、OpenMP* 呼び出しは自動ベクトル化を妨げます。解決方法:
Target |
ディレクティブ |
---|---|
その他 | !$OMP PARALLEL [節[[,] 節] ...] |
内部 | !$OMP SIMD [節[[,] 節]...] |
オリジナルコードの例:
!$OMP PARALLEL DO PRIVATE(tid, nthreads) do k = 1, N tid = omp_get_thread_num() ! ループ内のこの呼び出しはベクトル化を妨げます nthreads = omp_get_num_threads() ! ループ内のこの呼び出しはベクトル化を妨げます ... enddo
修正されたコードの例:
!$OMP PARALLEL PRIVATE(tid, nthreads) ! OpenMP* 呼び出しをここに移動 tid = omp_get_thread_num() nthreads = omp_get_num_threads() !$OMP DO NOWAIT do k = 1, N ... enddo !$OMP END PARALLEL
関連情報:
OpenMP* ロック関数を排除します
オブジェクトのロックはループの実行を低速にします。解決方法: OpenMP* ロック関数を使用しないようにコードを書き換えます。
それぞれのスレッドに個別の配列を割り当てて、並列処理の後にそれらをマージすることで、速度が向上する可能性があります (ただし、メモリー消費量が増加します)。
関連情報:
非効率なメモリー・アクセス・パターンは、重要なベクトルコードの実行速度を低下させたり、コンパイラーによる自動ベクトル化の妨げとなります。調査してパフォーマンスを改善します。
非効率なメモリー・アクセス・パターンを確認します
非効率なメモリー・アクセス・パターンをの存在を確認する方法がありません。解決方法: メモリー・アクセス・パターン解析を実行します。
不規則な (可変またはランダム) ストライドアクセスのメモリーアクセス命令の比率が高いことが観測されました。調査して適切に処理することでパフォーマンスを改善します。
ループの並べ替え
このループは近接する外部ループほどメモリーのアクセス効率は良くありません。解決方法: 可能であればループを並べ替えます。
オリジナルコードの例:
subroutine matrix_multiply(arrSize, aMatrix, bMatrix, cMatrix) implicit none real, intent(inout) :: cMatrix(:,:) real, intent(in) :: aMatrix(:,:), bMatrix(:,:) integer, intent(in) :: arrSize integer :: i,j,k; do j=1,arrSize do i=1,arrSize do k=1,arrSize cMatrix(i,j) = cMatrix(i,j) + aMatrix(i,k) * bMatrix(k,j) end do end do end do end subroutine matrix_multiply修正されたコードの例:
subroutine matrix_multiply(arrSize, aMatrix, bMatrix, cMatrix) implicit none real, intent(inout) :: cMatrix(:,:) real, intent(in) :: aMatrix(:,:), bMatrix(:,:) integer, intent(in) :: arrSize integer :: i,j,k; do j=1,arrSize do k=1,arrSize do i=1,arrSize cMatrix(i,j) = cMatrix(i,j) + aMatrix(i,k) * bMatrix(k,j) end do end do end do end subroutine matrix_multiply依存関係があるため、入れ替えが常に可能であるとは限らず、異なる結果を招く可能性があります。
Fortran 2008 の CONTIGUOUS 属性を使用します
形状引き継ぎ配列やポインターでループがユニットストライドと非ユニットストライド向けにマルチバージョン化されているが、マークされたループはユニットストライドなアクセスのみを行っている。CONTIGUOUS 属性は、形状引き継ぎ配列やポインターのターゲットが連続していることを示します。これにより、メモリーの連続したブロックを占有するオブジェクトのメモリーレイアウトに関連する最適化を容易にします。
real, pointer, contiguous :: ptr(:) real, contiguous :: arrayarg(:, :)
複数の呼び出しルーチンが関係する場合、形状引継ぎ配列およびポインターがメモリー内で常に連続していることをコンパイラーに知らせるには、インテル® Fortran コンパイラーのバージョン 18 以降で利用可能な次のオプションを使用します。
タイプ | Windows* | Linux* |
---|---|---|
形状引継ぎ配列 | /assume:contiguous_assumed_shape | -assume contiguous_assumed_shape |
ポインター | /assume:contiguous_pointer | -assume contiguous_pointer |
Windows* | Linux* |
---|---|
/check:contiguous | -check contiguous |
$ ifort -DCONTIG -check contiguous -traceback forrtl: severe (408): fort: (32): CONTIGUOUS 属性を持つポインターが、連続しないターゲットで作成されています。この例では、コンパイラーは連続しないターゲットへの連続ポインターの割り当てを検出します。-traceback(Linux*)、/traceback(Windows* ) オプションは、不正な割り当てが発生した関数とソースファイルの行番号を特定します。このトレースバックを取得するには、デバッグオプション-g(Linux* および macOS*)、/Zi(Windows*) を使用してコンパイルする必要はありません。
関連情報:
AoS の代わりに SoA を使用します
配列は、通常のインデックスでアクセス可能な、連続したデータ項目の集合を含む最も一般的なデータ構造です。構造体配列 (AoS)、または配列構造体 (SoA) として構成することができます。AoS はカプセル化には最適ですが、ベクトル化処理の妨げになることがあります。解決方法: AoS の代わりに SoA を使用するデータ構成にコードを変更します。
関連情報:
現在のハードウェアは、乗算加算融合 (FMA) 命令が利用できる AVX2 命令セットアーキテクチャー (ISA) をサポートします。FMA 命令を使用してパフォーマンスを改善します。
可能であればベクトル化を強制します
ループには FMA 命令 (ベクトル化の利点が考えられる) が含まれていますが、ベクトル化されていません。解決するには、以下を確認します。
関連情報:
strict 浮動小数点モデルを適用する場合、FMA 命令の生成を可能にします
静的解析は、ループが AVX2 ISA で使用可能な FMA 命令から利益が得られると推測しましたが、strict浮動小数点モデルは、デフォルトで FMA 命令の生成を無効にします。解決方法: この動作を fma コンパイラー・オプションを使用して変更します。
Windows* | Linux* |
---|---|
/Qfma | -fma または /Qfma |
関連情報:
インテル® AVX2 ISA ターゲット
静的解析は、ループがインテル® AVX2 以降で使用可能な FMA 命令から利点が得られると推測しましたが、このループでは FMA 命令が実行されていません。解決方法: インテル® AVX2 固有コードを生成するには、
Windows* | Linux* |
---|---|
/QxCORE-AVX2 または /QaxCORE-AVX2 | -xCORE-AVX2 または -axCORE-AVX2 |
/QxCOMMON-AVX512 または /QaxCOMMON-AVX512 | -xCOMMON-AVX512 または -axCOMMON-AVX512 |
関連情報:
xHost オプションの代わりに固有の ISA をターゲットにします
静的解析は、ループがインテル® AVX2 以降で使用可能な FMA 命令から利点が得られると推測しましたが、このループでは FMA 命令が実行されていません。解決方法: ホスト ISA による最適化の可能性を制限する xHost コンパイラー・オプションを使用する代わりに、次のコンパイラー・オプションを使用します。
Windows* | Linux* |
---|---|
/QxCORE-AVX2 または /QaxCORE-AVX2 | -xCORE-AVX2 または -axCORE-AVX2 |
/QxCOMMON-AVX512 または /QaxCOMMON-AVX512 | -xCOMMON-AVX512 または -axCOMMON-AVX512 |
関連情報:
ループ本体内の間接関数呼び出しは、コンパイラーがループをベクトル化するのを妨げます。間接呼び出しは、間接ジャンプとも呼ばれ、レジスターまたはメモリーから呼び出し先のアドレスを取得するのに対し、直接呼出しは引数から呼び出し先のアドレスを取得します。ループのベクトル化を強制しても間接呼び出しはシリアル化されます。
分岐予測の改善
64 ビット・アプリケーションでは、分岐ターゲットが分岐から 4 GB 以上離れている場合、分岐予測のパフォーマンスに悪影響を与えます。これは、アプリケーションが共有ライブラリーと分離されている場合に発生する可能性があります。解決方法: 次のことを行います。
関連情報:
ループ内の間接呼び出しを排除します
間接関数やサブルーチン呼び出しはベクトル化できません。解決方法: ループ内では間接呼び出しを避けます。
SIMD 対応関数のデフォルトのベクトル宣言では、余分な計算や非効率なメモリー・アクセス・パターンをもたらす可能性があります。適切な節を追加してパフォーマンスを改善します。
参照値を linear として指定します
Fortran アプリケーションでは、デフォルトでスカラー引数は参照渡しです。そのため、SIMD 対応関数では、引数は単一アドレスではなく、アドレスのショートベクトルとして渡されます。そして、ショートベクトルからデータをギャザーして、後続のベクトル演算で使用するショートベクトル値を作成します。このギャザーはパフォーマンスを低下します。解決方法: ベクトル宣言に REF 修飾子を持つ LINEAR 節を指定します (OpenMP* 4.5 でサポート)。指示節 LINEAR (REF(linear-list[: linear-step])) を !$OMP DECLARE SIMD ディレクティブに追加します。
関連情報:
固有のプロセッサー・タイプをターゲットとします
SIMD 対応関数のデフォルト命令セット・アーキテクチャー (ISA) は、レジスター間との余分なメモリーアクセスが生じる可能性があるため、ホスト・プロセッサーでは非効率です。解決方法: 次のいずれかを追加してコンパイラーにベクトル関数の拡張セットを生成することを通知します。
Windows* | Linux* |
---|---|
!$OMP DECLARE SIMD の PROCESSOR(cpuid) | !$OMP DECLARE SIMD の PROCESSOR(cpuid) |
/Qvecabi:cmdtarget 注意: コンパイラー・オプション /Qx または /Qax によって指定されるターゲットに対応する複数のベクトル関数が生成されます。 | -vecabi=cmdtarget 注意: コンパイラー・オプション -x または -ax で指定されるターゲットに対応する複数のベクトル関数が生成されます |
関連情報:
ベクトル依存関係を無視するようにコンパイラーに指示します
実際の依存関係は検出されなかったため競合検出命令を使用する必要がありません。解決方法: !DIR$ IVDEP ディレクティブを使用して、ベクトル化が安全であることをコンパイラーに知らせます。
!DIR$ IVDEP do i = 1, N a(index(i)) = b(i) * c enddo
関連情報:
これは外部 (最も内側ではない) ループです。通常外部ループは自動ベクトル化の対象とはありません。外部ループのベクトル化は可能であり有益なこともありますが、OpenMP* API やインテル® Cilk™ Plus を使用した明示的なベクトル化が必要です。
トリップ・カウント・データを収集
サーベイレポートでは、外部ループのベクトル化の有益性を証明するトリップカウントデータが不足しています。解決方法: トリップカウント解析を実行します。
外部ループの依存関係を調査します
依存関係の有無を認識せずにベクトル化を強制するのは安全とは言えません。依存関係を調査する前に内部ループのベクトル化を無効にします。確認するには: 依存関係解析を実行します。
外部ループのメモリー・アクセス・パターンをチェックします
外部ループが適切なメモリー・アクセス・パターンを持っているか確認するには、メモリー・アクセス・パターン解析を実行します。
外部ループのベクトル化を検討してください
コンパイラーは最内ループ以外をベクトル化のターゲットとしないため、内部ループがベクトル化できれば外部ループはベクトル化されません。しかし、より適切なメモリー・アクセス・パターン、髙いトリップカウント、またはより良い依存関係構成により、外部ループのベクトル化が有益である可能性があります。
外部ループをベクトル化します。
ターゲット | ディレクティブ |
---|---|
外部ループ | !$OMP SIMD |
内部ループ | !$OMP NOVECTOR |
!$OMP SIMD DO I=1,N !$OMP NOVECTOR DO J=1,N SUM = SUM + A(i)*A(j) ENDDO ENDDO
関連情報:
外部ループのベクトル化を検討してください。
コードの複雑性がコンパイラーが判断できる基準を超えているため、コンパイラーはループをベクトル化することができませんでした。ループのベクトル化を実施できれば高いパフォーマンスを得られる可能性があります。ソースのループブロックの前で、適切なディレクティブを使用します。
ICL/ICC/ICPC ディレクティブ |
---|
!$OMP SIMD |
関連情報:
外部ループのベクトル化を検討してください
依存関係の可能性が検出されたため、コンパイラーは内部ループをベクトル化できませんでした。依存関係がなければ外部ループをベクトル化します。ソースのループブロックの前で、適切なディレクティブを使用します。
ICL/ICC/ICPC ディレクティブ |
---|
!$OMP SIMD |
関連情報:
現在のハードウェアは、単精度と倍精度の逆数および逆数平方根命令が使用できるインテル® アドバンスト・ベクトル・エクステンション 512 (インテル® AVX-512) 命令をサポートしています。これらの命令を使用してパフォーマンスを改善します。これらの命令を使用してパフォーマンスを改善します。
可能であればベクトル化を強制します
ループには SQRT/DIV 命令 (ベクトル化の利点が考えられる) が含まれていますが、ベクトル化されていません。解決するには、以下を確認します。
関連情報:
インテル® AVX-512 ISA ターゲット
静的解析は、インテル® AVX-512 の指数および逆数 (インテル® AVX-512ER) 命令からループが利点を得られると推測しましたが、これらの命令は使用されていません。解決方法: 以下のいずれかのコンパイラー・オプションを使用します。
Windows* | Linux* |
---|---|
/QxCOMMON-AVX512 または /QaxCOMMON-AVX512 | -xCOMMON-AVX512 または -axCOMMON-AVX512 |
関連情報:
インテル® AVX-512 指数および逆数命令 ISA をターゲットにします
静的解析は、インテル® AVX-512 指数および逆数 (インテル® AVX-512ER) 命令からループが利点を得られると推測しました。この命令は現在インテル® Xeon Phi™ プロセッサーでのみサポートされていますが、このループでは使用されていませんでした。解決方法: 以下のいずれかのコンパイラー・オプションを使用します。
Windows* | Linux* |
---|---|
/QxMIC-AVX512 または /QaxMIC-AVX512 | -xMIC-AVX512 または -axMIC-AVX512 |
関連情報:
精度と浮動小数点モデルのコンパイラー・オプションを調整することで、逆数近似命令の使用を可能にします
静的解析は、逆数近似命令からループが恩恵を得られることを推測しましたが、精度と浮動小数点モデルを設定するコンパイラー・オプションがこの命令の生成を妨げている可能性があります。解決方法: 次のコンパイラー・オプションで調整します。
Windows* | Linux* | コメント |
---|---|---|
/fp | -fp-model | -fp-model=preciseは、逆数近似命令の使用を抑制します。 |
/Qimf-precision | -fimf-precision | 代わりに-fimf-precision=mediumまたは-fimf-precision=lowの利用を検討してください。 |
/Qimf-accuracy-bits | -fimf-accuracy-bits | この設定を減らすことを考慮してください。 |
/Qimf-max-error | -fimf-max-error | この設定を減らすことを考慮してください。 同様のオプションもあります。-fimf-absolute-errorディレクティブを使用します。同時に両方のオプションの使用しないでください。 |
/Qimf-absolute-error | -fimf-absolute-error | 代わりに-fimf-max-errorを使用して、-fimf-absolute-error=0に設定するか (デフォルト)、この設定を-fimf-max-errorと同時に指定して設定を増やすことを考慮してください。 |
/Qimf-domain-exclusion | -fimf-domain-exclusion | この設定を減らすことを考慮してください。クラスを除外するとコードの最適化が可能となります。注意して使用してください。アプリケーションが使用する計算がドメインから除外されていると、このオプションにより不正確な動作となる可能性があります。 |
/Qimf-arch-consistency | -fimf-arch-consistency | -fimf-arch-consistency=trueは、逆数近似命令の使用を抑制します。 |
/Qprec-div | -prec-div | -prec-divは、逆数近似命令の使用を抑制します。 |
/Qprec-sqrt | -prec-sqrt | -prec-sqrtは、逆数近似命令の使用を抑制します。 |
関連情報:
間接アドレスによるストアで、コンパイラーは潜在的な依存関係を想定しました。
これは SIMD 処理において、AVX-512 vpconflict 命令などの競合検出命令が使用され、ベクトルと生成された競合無しのサブセット内で複製された値が検出された結果によるものです。競合検出命令を排除することでパフォーマンスを改善できます。
ベクトル依存関係を無視するようにコンパイラーに指示します
実際の依存関係は検出されなかったため競合検出命令を使用する必要がありません。解決方法: !DIR$ IVDEP ディレクティブを使用して、ベクトル化が安全であることをコンパイラーに知らせます。
!DIR$ IVDEP do i = 1, N a(index(i)) = b(i) * c enddo
関連情報:
近似操作命令を有効にしてパフォーマンスを改善します。
近似除算命令の使用を可能にします
静的解析は、ループで近似計算を使用することで利点が得られると推測しました。個々の除算は事前計算され乗算に置き換えられます。解決方法: 次のコンパイラー・オプションで調整します。
Windows* | Linux* | コメント |
---|---|---|
/Qprec-div | -no-prec-div | -no-prec-div近似除算を使用した最適化を有効にします。 |
関連情報:
近似平方根命令の使用を可能にします
静的解析は、近似平方根 (sqrt) 命令からループが恩恵を得られることを推測しましたが、精度と浮動小数点モデルを設定するコンパイラー・オプションがこの命令の生成を妨げている可能性があります。解決方法: 次のコンパイラー・オプションで調整します。
Windows* | Linux* | コメント |
---|---|---|
/Qprec-sqrt | -no-prec-sqrt | -no-prec-sqrt近似平方根最適化の使用を可能にします。 |
関連情報:
非テンポラルなストアを有効にします
!DIR$ vector nontemporal を使用して、非テンポラルなストアを有効にします。nontemporal 節は、特に明記されていない限り、サポートされているすべてのアーキテクチャー・ベースのシステムで、一時的ではない (ストリーミング) ストアを使用するようにコンパイラーに指示します。オプションでカンマ区切りの変数リストも指定できます。
ストリーミング・ストアは、特定のプロセッサーにおいて非ストリーミング・ストアよりも、大幅なパフォーマンスの向上をもたらす可能性があります。ただし、ストリーミング・ストアの使用を誤ると、パフォーマンスが大幅に低下します。
!DIR$ vector nontemporal do i=1,N arr1(i) = 0 end do
関連情報:
メモリー内にある現在のループ配置では、CPU フロントエンドの効率が低下する可能性があります。ループコードをアライメントすることでパフォーマンスを向上します。
コンパイラーにループコードのアライメントを強制します
静的解析は、ループのコード・アライメントから利点が得られると推測しました。解決方法: より細かな制御のためコンパイラー・ディレクティブを使用して、コンパイラーにループを 2 のべき乗バイトへのアライメントを強制します。!DIR$ CODE_ALIGN [:n]
内部ループを 32 バイト境界で配置します。
!DIR$ CODE_ALIGN :64 do i = 1, n, 1 do j = 1, m, 1 a(i) = a(i) * (b(i) + c(j)) enddo enddo
次のコンパイラー・オプションも指定する必要があります。
Windows* | Linux* と macOS* |
---|---|
/Qalign-loops[:n] | -falign-loops[=n] |
n は、1 から 4096 の範囲内の 2 の累乗の値でなければなりません (例: 1、2、4、8、16、32、64 など)。n = 1 はアライメントを行わないことを指示します。n が省略されると、16 バイトのアライメントが使用されます。推奨: 16 と 32 を最初に試します。
/Qalign-loops-と-fno-align-loops、デフォルトのコンパイルオプションでは、特殊なループのアライメントは無効になります。