このトピックは、自動ルーフライン・グラフを使用して、優先度の高い最適化を決定する方法を紹介するチュートリアルの一部です。
以下のステップを実行します。
このトピックでは、以下について説明します。
演算強度 ([Roofline (ルーフライン)] グラフの x 軸) = アクセスされるバイトあたりの浮動小数点操作数。すべてのアルゴリズムに演算強度があります。理論的には、このメトリックはアルゴリズム自体の特性であるため、最適化により変化することはありません。つまり、[Roofline (ルーフライン)] グラフ上のドットは、パフォーマンスの変化に応じて上下には移動しますが、左右に移動することはめったにありません。
ループを最適化しただけでは、対応するドットを次のルーフラインに移動できません。ループが最適化を上手く利用している必要があります。非効率なベクトル化や孤立した FMA (Fused Multiply Add) を最適化しただけでは十分ではありません。
適切な状況下では、データレイアウトとメモリーアクセスを最適化することで、計算能力とメモリー帯域幅の両方の制限を解決できます。
[Recommendations (推奨事項)] タブで how-can-I-fix-this-issue? (解決方法) にあるコード固有の推奨事項を利用できます。
時間とハードウェア依存性を考慮して、ここでは事前に収集された解析結果を使用します。
次のいずれかの操作を行います。
スタンドアロン GUI: [File (ファイル)] > [Open (開く)] > [Result (結果)] から Result2.advixeexpz 結果を選択します。
Visual Studio* IDE: [ファイル] > [開く] から Result2.advixeexpz 結果を選択します。
表示の切り替えを使用して、[Roofline (ルーフライン)] グラフと [Survey Report (サーベイレポート)] を並べて表示します。
インテル® Advisor ツールバーの [Loops And Functions (ループと関数)] フィルター・ドロップダウンから [Loops (ループ)] を選択します。

[Roofline (ルーフライン)] グラフで次の操作を行います。
[Use Single-Threaded Loops (シングルスレッドのループを使用)] チェックボックスをオンにします。
コントロールをクリックして、すべての SP... ループの [Visibility (可視化)] チェックボックスをオンにします(このサンプルコードの変数はすべて倍精度であるため、単精度のルーフラインを非表示にします)。

[Point Colorization (ポイントの色分け)] セクションで [Vectiorized/Scalar (ベクトル化/スカラー)] を選択して、ランタイム (赤、黄、緑) の代わりに、スカラー (青)/ベクトル (オレンジ) で色分けします。
をクリックして変更を保存します。
コントロールをクリックします。x 軸のフィールドで既存の値を Backspace キーで消去し、0.1 と 0.8 を入力します。y 軸のフィールドで既存の値を Backspace キーで消去し、3.1 と 45.5 を入力します。
ボタンをクリックして変更を保存します。

[Roofline (ルーフライン)] グラフの roofline.cpp:221 の main のループを表すドットの位置に注目してください。これは、[Vector Add Peak(ベクトル加算ピーク)] と [Scalar Add Peak (スカラー加算ピーク)] の両方のルーフラインの下に配置されます。これは、次のことが考えられます。
ドットの色が示すように、ループがベクトル化されていません。これは、[Survey Report (サーベイレポート)] の最初のカラムにあるスカラーの状態でも確認できます (青いアイコン = スカラー、オレンジのアイコン = ベクトル)。このチュートリアルでは、ディレクティブを使用してループがベクトル化されないようにしています。インテル® Advisor には、ループがベクトル化されなかった理由を診断するさまざまなツールがあり、実際に問題があった場合はこれらのツールを使用できます。
roofline.cpp:247 の main にあるループは、roofline.cpp:221 の main にあるループのベクトル化されたバージョンです。
[Roofline (ルーフライン)] グラフでは、このループを表す一番下のオレンジのドットの位置が、[Arithmetic Intensity (演算強度)] 軸上で左へ移動しています。これは、理論的にはありえないことです。演算強度は転送されたバイトあたりの浮動小数点操作数を示すもので、すべてのアルゴリズムには演算強度があり、このメトリックはアルゴリズム自体の特性であるため、最適化により変化しません。つまり、[Roofline (ルーフライン)] グラフ上のドットは、パフォーマンスが向上すると上方向に移動しますが、通常は左右に移動することはありません。
コンパイラーの最適化により、roofline.cpp:247 の main にあるループの演算強度が変わっています。
どのように実現したのでしょうか?
[Code Analytics (コード解析)] タブで、青いドットとオレンジのドットの両方のループの [GFLOPS] ドロップダウンをチェックします。

両方のループの統計を並べて確認すると、ベクトル化されたループの [Self FLOP Per Iteration (反復ごとのセルフ FLOP)] に違いが見られます。ループのベクトル長は 4 であるため、8*4=32 でこれは理にかなっています。合計と反復ごとの [Data Transfers (データ転送)] 値が変わっています。256 という値はベクトル化によって説明できません。ベクトル化により変わったのであれば、48*4=192 となり、256 にはなりません。
メトリック |
スカラーループ (青いドット) |
ベクトル化されたループ (一番下のオレンジのドット) |
|---|---|---|
反復ごとのセルフ FLOP |
8 |
32 |
データ転送: 合計ギガバイト: |
318.720 |
424.960 |
データ転送: ループ反復ごと (バイト) |
48 |
256 |
この統計から、コンパイラーによってメモリーアクセスが変更されたことが分かります。[Code Analytics (コード解析)] タブからも分かるように、新しいアンパック命令と挿入命令がメモリー計算に影響を与えている可能性があります。
roofline.cpp:247 の main のループには次の異常性があります。[Roofline (ルーフライン)] グラフの下部のオレンジ色のドットは、[Scalar Add Peak (スカラー加算ピーク)] ルーフラインのわずかに上に配置されています。
これは、次のことが考えられます: ループのベクトル化は非効率です。
これを検証するため、以下の操作を行います。
[Survey Report (サーベイレポート)] で、[Vectorized Loops/Efficiency (ベクトル化されたループ/効率)] の値を確認すると 31% です。ベクトル化が十分ではないため、ループは [Vector Add Peak (ベクトル加算ピーク)] ルーフラインに近づくことができません。ループを効率良くベクトル化する必要があります。
[Efficiency (効率)] 値が非常に低い原因として、
次のことが考えられます: 非効率なメモリーアクセスにより、VPU/SIMD リソースが最大限に活用されていません。これは、構造体配列 (AOS) データレイアウトでよくある問題です。[Memory Access Patterns Report (メモリー・アクセス・パターン・レポート)] を確認します。

メモリーアクセスの問題が確認されました: ほとんどのメモリーアクセスが均一ストライドではありません。([Code Analytics (コード解析)] タブの挿入操作からもこれを確認できます)。これは、ベクトル化の非効率性を助長します。
ベクトル化の効率を改善するため、次の操作を行います。
構造体配列 (AOS) の代わりに、配列構造体 (SOA) データレイアウトを使用するようにコードを再構成します。これは、最適化のアドバイスとして、[Recommendations (推奨事項)] タブにも記載されています。

これは、roofline.cpp:260 の main にあるループ (真ん中のオレンジのドット) で行ったことと同じです。
このトッドは、[Vector Add Peak (ベクトル加算ピーク)] ルーフラインのすぐ下にあります。[Survey Report (サーベイレポート)] で、[Vectorize Loops/Efficiency (ベクトル化されたループ/効率)] の値を確認すると 100% です。
このドットは L3 キャッシュによって制限されることがなく、L2 キャッシュによる制限もごくわずかであるため、メモリー帯域幅ルーフラインもスキップしています。
このため、SOA データレイアウトに変更することで、計算能力とメモリー帯域幅の両方のボトルネックが解決されました。
最後に、roofline.cpp:273 の main にあるループ (一番上のオレンジのドット) を見てみましょう。ドットが [Vector Add Peak (ベクトル加算ピーク)] ルーフラインの上にある理由を考えてみてください。ヒント: [Assembly (アセンブリー)] タブで、一番上と真ん中のオレンジのドットで表される 2 つのループの命令を比較してみてください。