高レベルな最適化 (HLO) レポート

高レベルな最適化 (HLO) は、各最適化の有用性および適用可能性に基づいて特定の最適化を行います。HLO レポートは、関連するすべての領域に加えて、構造体分割およびループ運搬のスカラー置換についての情報を提供します。また、次の理由から行われなかったループ交換についての情報も提供します。

例えば、レポートは、コンパイラーが最適化の候補と見なされたループの入れ子になぜループ交換を適用しなかったかを知る手がかりを提供します。レポートされた問題 (ボトルネック) がソースコードを変更することで排除できる場合は、レポートは可能性のあるループ交換を示唆します。

オペレーティング・システムに応じて、次のオプションを指定し、HLO を有効にしてレポートを作成します。

HLO の詳細については、「高レベルな最適化の概要」を参照してください。

次のコマンド例は、HLO レポートの作成に必要な一般的なコマンドです。

オペレーティング・システム

コマンド例

Linux* および Mac OS* X

icpc -c -xSSE3 -O3 -opt-report 3 -opt-report-phase=hlo sample.cpp

Windows

icl /c /QxSSE3 /O3 /Qopt-report:3 /Qopt-report-phase:hlo sample.cpp

-opt-report-file (Linux* および Mac OS* X) または /Qopt-report-file (Windows*) を使用して、レポート結果をキャプチャーする出力ファイルを指定します。結果をキャプチャーするファイルを指定することで、結果の解析に費やす時間を短縮でき、後に行うテスティングの基本ラインをつかむことができます。

レポート結果

レポートは、特定の形式で情報を提供します。Windows のレポート形式は、Linux や Mac OS X のレポート形式とは異なります。レポート出力には共通の要素が含まれますが、レポートが提供するアドバイスを理解する一番良い方法は、コード例とそのレポート出力を実際に確認することです。

例 1: この例では、関数呼び出しがループの内部にある場合を示しています。

例 1

void bar (int *A, int **B);
int foo (int *A, int **B, int N)
{
   int i, j;
   for (j=0; j<N; j++) {
      for (i=0; i<N; i++) {
         B[i][j] += A[j];
         bar(A,B);
      }
   }
   return 1;
}

オペレーティング・システムを問わず、レポートでは、特定の関数の最適化結果が 1 行で示され、その後にレポートされた処理が示されます。行の形式と説明は下にリストされます。

次の表は、一般的なレポート要素と結果の解釈に役立つ説明をまとめたものです。

レポート要素

説明

レポートされる関数についての情報です。次の形式で示されます。

<source name>;<start line>;<end line>;<optimization>; <function name>;<element type>

例えば、レポートには次の情報が含まれます。

Linux* および Mac OS* X:

<sample1.c;-1:-1;hlo;foo;0>

Windows*:

<sample1.c;-1:-1;hlo;_foo;0>

ここでは、次の情報が含まれます。

  • <source name>: 検証されるソースファイルの名前です。

  • <start line>: 検証される関数の開始行番号です。値が 1 の場合、関数全体がレポートされます。

  • <end line>: 検証される関数の終了行番号を示します。

  • <optimization>: 最適化フェーズを示します。このレポートの場合は、hlo 最適化フェーズです。

  • <function name>: 検証される関数名です。

  • <element type>: レポート要素の型を示します。0 は要素がコメントであることを示します。

いくつかのレポート要素はグループ化されます。

QLOOPS 2/2      ENODE ループ 2 
不明 0 multi_exit_do 0 do 2 
linear_do 2
線形 HLO 式:  17 / 18

Windows* のみ: レポートのこのセクションには、次の情報がリストされます。

  • QLOOPS: 発見されたループの中から適格なループの数を示します。

  • ENODE ループ: HLO によって生成された望ましいループ形式 (標準的な) の数を示します。これは、HLO によって生成されたループの数です。

  • 不明: カウントできなかったループの数を示します。

  • multi_exit_do: 複数の出口を含むカウント可能なループを示します。

  • do: カウント可能なトリップカウントを持つループの合計数を示します。

  • linear_do: 線形形式で表現できる限界を持つループ数を示します。

  • LINEAR HLO EXPRESSIONS: 線形形式で表現できる式 (2 番目の数字) のすべての中間形式 (ENODE) にある式の数 (最初の数字) を示します。

上記のコード例では次のような結果が出力されます。

オペレーティング・システム

例 1 のレポート出力

Linux* および Mac OS* X

<sample1.c;-1:-1;hlo;foo;0>
高レベル・オプティマイザー・レポート (foo)
ブロック、アンロール、ジャムレポート:
(ループ行の番号、アンロールファクターおよび変換の種類)
<sample1.c;7:7;hlo_unroll;foo;0>
ループ (行:7) 剰余ありでアンロール - 2

Windows

<sample1.c;-1:-1;hlo;_foo;0>
高レベル・オプティマイザー・レポート (_foo)
QLOOPS 2/2      ENODE ループ 2 不明 0 multi_exit_do 0 do 2 linear_do 2
線形 HLO 式:  17 / 18
------------------------------------------------------------------------------
<sample1.c;6:6;hlo_linear_trans;_foo;0>
ループ交換は完了しませんでした: ユーザー関数の内部ループが入れ子です。
アドバイス: ループ交換は (可能であれば) 次の行のループに使用してもかまいません: 6 7
      : 推奨する順列: (1 2 ) --> ( 2 1 )

例 2: ループの入れ子によりループ交換が妨げられた例を示しています。

例 2

int foo (int *A, int **B, int N)
{
   int i, j;
   for (j=0; j<N; j++) {
      A[j] = i + B[i][1];
      for (i=0; i<N; i++) {
         B[i][j] += A[j];
      }
   }
   return 1;
}

上記のコード例では次のような結果が出力されます。

オペレーティング・システム

例 2 のレポート出力

Linux* および Mac OS* X

<sample2.c;-1:-1;hlo;foo;0>
高レベル・オプティマイザー・レポート (foo)
<sample2.c;7:7;hlo_scalar_replacement;in foo;0>
置換された配列参照スカラー foo の数 (行 7=2)
置換された配列参照スカラー foo の数 (行 7=1)
ブロック、アンロール、ジャムレポート:
(ループ行の番号、アンロールファクターおよび変換の種類)
<sample2.c;7:7;hlo_unroll;foo;0>
ループ (行:7) 剰余ありでアンロール - 2

Windows

<sample2.c;-1:-1;hlo;_foo;0>
高レベル・オプティマイザー・レポート (_foo)
QLOOPS 2/2      ENODE ループ 2 不明 0 multi_exit_do 0 do 2 linear_do 2
線形 HLO 式:  22 / 27
------------------------------------------------------------------------------
<sample2.c;7:7;hlo_scalar_replacement;in _foo;0>
置換された配列参照スカラー foo の数 (行 7=2)
<sample2.c;5:5;hlo_linear_trans;_foo;0>
ループ交換は完了しませんでした: ループの入れ子が完全ではありません (ソースのいずれかまたは
他のコンパイラー変換による)
アドバイス: ループ交換は (可能であれば) 次の行のループに使用してもかまいません: 5 7
      : 推奨する順列: (1 2 ) --> ( 2 1 )

例 3: この例では、データの依存関係によりループ交換が禁止されている状態を示しています。

例 3

int foo (int **A, int **B, int **C, int N)
{
   int i, j;
   for (j=0; j<N; j++) {
      for (i=0; i<N; i++) {
         A[i][j] = C[i][j] * 2;
         B[i][j] += A[i][j] * C[i][j];
      }
   }
   return 1;
}

上記のコード例では次のような結果が出力されます。

オペレーティング・システム

例 3 のレポート出力

Linux* および Mac OS* X

<sample3.c;-1:-1;hlo;foo;0>
高レベル・オプティマイザー・レポート (foo)
ブロック、アンロール、ジャムレポート:
(ループ行の番号、アンロールファクターおよび変換の種類)
<sample3.c;6:6;hlo_unroll;foo;0>
ループ (行:6) 剰余ありでアンロール - 2

Windows

<sample3.c;-1:-1;hlo;_foo;0>
高レベル・オプティマイザー・レポート (_foo)
QLOOPS 2/2      ENODE ループ 2 不明 0 multi_exit_do 0 do 2 linear_do 2
線形 HLO 式:  36 / 36
------------------------------------------------------------------------------
<sample3.c;5:5;hlo_linear_trans;_foo;0>
ループ交換は完了しませんでした: データの依存関係があります。
  以下の文の間で依存関係が見つかりました:
    [From_Line# -> (依存関係の種類) To_Line#]
    [7 ->(Anti) 8] [7 ->(Flow) 8] [7 ->(Output) 8]
    [7 ->(Flow) 7] [7 ->(Anti) 7] [7 ->(Output) 7]
アドバイス: ループ交換は (可能であれば) 次の行のループに使用してもかまいません: 5 6
      : 推奨する順列: (1 2 ) --> ( 2 1 )

例 4: この例は、ループの順序は適切だと判断されたけれども、ループ交換による効果がわずかしか見込めない場合を示しています。このコードをコンパイルするには、レポート生成時に -restrict (Linux* および Mac OS* X) または /Qrestrict (Windows*) オプションをほかのオプションに追加します。

例 4

int foo (int ** restrict A, int ** restrict B, int N)
{
   int i, j, value;
   for (j=0; j<N; j++) {
      for (i=0; i<N; i++) {
         A[j][i] += B[i][j];       
      }
   }
   value = A[1][1];
   return value;
}

上記のコード例では次のような結果が出力されます。

オペレーティング・システム

例 4 のレポート出力

Linux* および Mac OS* X

<sample4.c;-1:-1;hlo;foo;0>
高レベル・オプティマイザー・レポート (foo)
ブロック、アンロール、ジャムレポート:
(ループ行の番号、アンロールファクターおよび変換の種類)
<sample4.c;6:6;hlo_unroll;foo;0>
ループ (行:6) 剰余ありでアンロール - 2

Windows

<sample4.c;-1:-1;hlo;_foo;0>
高レベル・オプティマイザー・レポート (_foo)
QLOOPS 2/2      ENODE ループ 2 不明 0 multi_exit_do 0 do 2 linear_do 2
線形 HLO 式:  18 / 18

例 5: この例では、ループの入れ子が不完全でループの順序は良いが、ループ交換による効果がわずかしかない場合を示しています。このコードをコンパイルするには、レポート生成時に -restrict (Linux* および Mac OS* X) または /Qrestrict (Windows*) オプションをほかのオプションに追加します。

例 5

int foo (int ** restrict A, int ** restrict B, int ** restrict C, int N)
{
   int i, j, sum;
   for (j=0; j<N; j++) {
      sum += A[1][1];
      for (i=0; i<N; i++) {
         sum = B[j][i] + C[i][j];
      }
   }
   return sum;
}

上記のコード例では次のような結果が出力されます。

オペレーティング・システム

例 5 のレポート出力

Linux* および Mac OS* X

<sample5.c;-1:-1;hlo;foo;0>
高レベル・オプティマイザー・レポート (foo)

Windows

<sample5.c;-1:-1;hlo;_foo;0>
高レベル・オプティマイザー・レポート (_foo)
QLOOPS 2/2      ENODE ループ 2 不明 0 multi_exit_do 0 do 2 linear_do 2
線形 HLO 式:  16 / 19
------------------------------------------------------------------------------
<sample5.c;5:5;hlo_linear_trans;_foo;0>
ループ交換は完了しませんでした: ループの入れ子が完全ではありません (ソースのいずれかまたは
他のコンパイラー変換による)
アドバイス: ループ交換は (可能であれば) 次の行のループに使用してもかまいません: 5 7
      : 推奨する順列: (1 2 ) --> ( 2 1 )

例 6: この例は、完全なループの入れ子と不完全なループの入れ子があり、正しくネストされたループにはデータの依存関係が含まれる場合を示しています。

例 6

int foo (int ***A, int ***B, int **C, int N)
{
   int q, i, j, k;
   q = 0;
   while ( A[q][0][0] != 0) {
   for (j=0; j<N; j++) {
      A[j][0][0] = j + B[j][0][0];
      for (i=0; i<N; i++) {
         for (k=0; k<N; k++) {
            B[k][i][j] += A[j][0][0] + C[i][j];
         }
      }
   }
   A[q][0][0] = B[0][q][0] + 5;
   }
   return 1;
}

上記のコード例では次のような結果が出力されます。

オペレーティング・システム

レポート出力例

Linux* および Mac OS* X

<sample6.c;-1:-1;hlo;foo;0>
高レベル・オプティマイザー・レポート (foo)
ブロック、アンロール、ジャムレポート:
(ループ行の番号、アンロールファクターおよび変換の種類)
<sample6.c;9:9;hlo_unroll;foo;0>
ループ (行:9) 剰余ありでアンロール - 2  
[root@infodev-test hlo_samples_cpp]#

Windows

<sample6.c;-1:-1;hlo;_foo;0>
高レベル・オプティマイザー・レポート (_foo)
QLOOPS 2/4      ENODE ループ 2 不明 0 multi_exit_do 0 do 2 linear_do 2
線形 HLO 式:  34 / 34
------------------------------------------------------------------------------
<sample6.c;8:8;hlo_linear_trans;_foo;0>
ループ交換は完了しませんでした: データの依存関係があります。
  以下の文の間で依存関係が見つかりました:
    [From_Line# -> (依存関係の種類) To_Line#]
    [10 ->(Flow) 10] [10 ->(Anti) 10] [10 ->(Output) 10]
アドバイス: ループ交換は (可能であれば) 次の行のループに使用してもかまいません: 8 9
      : 推奨する順列: (1 2 ) --> ( 2 1 )

レポート結果に基づくコードの変更

HLO レポートにより、コンパイラーが行ったループ変換について知ることができ、またいくつかのアドバイスを得られますが、ループの変換が省略されたことにより、コンパイラーが試みた変換があることも示唆している可能性があります。次のリストは、適用できる可能性のあるいくつかの変換を示しています。(手動キャッシュブロックのような手動の最適化テクニックは避けるか、または最後の手段としてください。)


このヘルプトピックについてのフィードバックを送信

© 1996-2010 Intel Corporation. 無断での引用、転載を禁じます。