高レベルな最適化 (HLO) は、各最適化の有用性および適用可能性に基づいて特定の最適化を行います。HLO レポートは、関連するすべての領域に加えて、構造体分割およびループ運搬のスカラー置換についての情報を提供します。また、次の理由から行われなかったループ交換についての情報も提供します。
関数呼び出しがループの内部にある
ループの入れ子が不完全である
データの依存関係に基づいている (交換を妨げている依存性についてもレポートされます。)
元の順序は適切ではあるが、交換を行うには不完全であると見なされた
例えば、レポートは、コンパイラーが最適化の候補と見なされたループの入れ子になぜループ交換を適用しなかったかを知る手がかりを提供します。レポートされた問題 (ボトルネック) がソースコードを変更することで排除できる場合は、レポートは可能性のあるループ交換を示唆します。
オペレーティング・システムに応じて、次のオプションを指定し、HLO を有効にしてレポートを作成します。
Linux* および Mac OS* X: -x、-O2 または -O3、-opt-report 3、-opt-report-phase=hlo
Windows*: /Qx、/O2 または /O3、/Qopt-report:3、/Qopt-report-phase: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> |
ここでは、次の情報が含まれます。
|
いくつかのレポート要素はグループ化されます。 QLOOPS 2/2 ENODE ループ 2 不明 0 multi_exit_do 0 do 2 linear_do 2 線形 HLO 式: 17 / 18 |
Windows* のみ: レポートのこのセクションには、次の情報がリストされます。
|
上記のコード例では次のような結果が出力されます。
オペレーティング・システム |
例 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 レポートにより、コンパイラーが行ったループ変換について知ることができ、またいくつかのアドバイスを得られますが、ループの変換が省略されたことにより、コンパイラーが試みた変換があることも示唆している可能性があります。次のリストは、適用できる可能性のあるいくつかの変換を示しています。(手動キャッシュブロックのような手動の最適化テクニックは避けるか、または最後の手段としてください。)
ループ交換 - 2 つの入れ子しているループの実行順を交換して、キャッシュの局所性またはユニット・ストライド・アクセスのパフォーマンス上の利点を活用します。
分配 - 1 つの大きなループを 2 つの小さなループに分配または分割します。非常に多くのレジスターが大きなループで消費されている場合に効果的である可能性があります。
融合 - トリップカウントが同じ 2 つの小さなループを融合して、データの局所性を向上させます。
ループ・ブロッキング - キャッシュ・ブロッキングは、キャッシュにすでに存在するデータでできるだけ多くの演算を行うようにループをアレンジします。(最初のブロックを使用する演算がすべて完了するまで、データの次のブロックはキャッシュに読み込まれません。)
アンロール - アンロールは、各ループの反復を大きくすることで、必要なループの反復数を少なくして、ループ構造を部分的に逆アセンブルする方法です。アンロールは、命令とデータのレイテンシーを隠すため、浮動小数点ロードペア命令の利点を活用し、またメモリー操作ごとに行われる実際の作業の比率を増やすために使用できます。
プリフェッチ - データが実際に必要になる前に、いくつかのループ反復で相対的に遅いメモリーからより高速なキャッシュにデータを移動するようにコンパイラーに要求します。
ロードペア - メモリーから 2 つの浮動小数点データ要素を一度にロードする命令を利用します。
© 1996-2010 Intel Corporation. 無断での引用、転載を禁じます。