4

私は多くの人々が-O3オプションについて不平を言っているのを見てきました:

GCCのマニュアルを確認します。

   -O3    Optimize yet more.  -O3 turns on all optimizations
          specified   by   -O2   and   also   turns  on  the
          -finline-functions and -frename-registers options.

また、コードを確認して、2つのオプションが-O3onに含まれる2つの最適化のみであることを確認しました。

if (optimize >= 3){
    flag_inline_functions = 1;
    flag_rename_registers = 1;
}

これら2つの最適化の場合:

  • -finline-functions-finline-limitを使用してインライン関数のサイズ(デフォルトでは600)を定義できるため、場合によっては(主にC ++で)便利です。高いインライン制限を設定すると、コンパイラはメモリ不足を訴えるエラーを報告する場合があります。
  • -frename-registersレジスタ割り当て後に残ったレジスタを利用することにより、スケジュールされたコードの誤った依存関係を回避しようとします。この最適化は、多くのレジスタを備えたプロセッサに最も役立ちます。

インライン関数の場合、関数呼び出しの数を減らすことはできますが、バイナリファイルが大きくなる可能性があるため、-finline-functions深刻なキャッシュペナルティが発生し、-O2よりもさらに遅くなる可能性があります。キャッシュのペナルティは、プログラム自体に依存するだけではないと思います。

名前変更レジスタについては、x86のようなciscアーキテクチャにプラスの影響はないと思います。

私の質問には2.5の部分があります:

  1. プログラムが-O3オプションでより速く実行できるかどうかは、基盤となるプラットフォーム/アーキテクチャに依存すると主張する権利はありますか?[回答済み]

    編集:

    最初の部分は真であることが確認されています。David Hammenはまた、IntelやAMDのような拡張精度の浮動小数点レジスタを備えたマシンで最適化と浮動小数点演算がどのように相互作用するかについて非常に注意する必要があると主張しています。

  2. -O3オプションを自信を持って使用できるのはいつですか?これらの2つの最適化、特に名前変更レジスタは、-O0/O2とは異なる動作を引き起こす可能性があると思います。コンパイルされたいくつかのプログラムが-O3実行中にクラッシュするのを見ましたが、それは決定論的ですか?実行可能ファイルをクラッシュせずに1回実行した場合、それは安全に使用できることを意味します-O3か?

    編集:決定論は最適化とは何の関係もありません、それはマルチスレッドの問題です。ただし、マルチスレッドプログラムの-O3場合、実行可能ファイルをエラーなしで1回実行すると、安全に使用できません。David Hammenは、-O3浮動小数点演算の最適化が、比較のための厳密な弱順序基準に違反する可能性があることを示しています。オプションを使用したいときに注意が必要な他の懸念事項はあり-O3ますか?

  3. 最初の質問の答えが「はい」の場合、ターゲットプラットフォームを変更するとき、または異なるマシンを使用する分散システムで、との間で変更する必要がある場合があり-O3ます-O2。でパフォーマンスを改善できるかどうかを判断する一般的な方法はあります-O3か?たとえば、より多くのレジスタ、短いインライン関数など。[回答済み]

    編集:3番目の部分はLouenによって「プラットフォームの多様性により、この問題に関する一般的な推論が不可能になる」と回答されています。によるパフォーマンスの向上を評価するときは-O3、両方で試して、コードをベンチマークしてどちらが速いかを確認する必要があります。

4

2 に答える 2

7
  1. -O3でコンパイルすると、いくつかのプログラムがクラッシュするのを見ましたが、それは決定論的ですか?

プログラムがシングルスレッドの場合、プログラムで使用されるすべてのアルゴリズムは決定論的であり、実行から実行への入力が同一である場合は、はい。これらの条件のいずれかが当てはまらない場合、答えは「必ずしも」ではありません。

-O3を使用せずにコンパイルする場合も同様です。

実行可能ファイルをクラッシュせずに1回実行した場合、-O3を使用しても安全ですか?

もちろん違います。繰り返しになりますが、-O3を使用せずにコンパイルした場合も同じことが当てはまります。アプリケーションが1回実行されたからといって、すべての場合に正常に実行されるとは限りません。それがテストを難しい問題にしている理由の一部です。


浮動小数点演算は、浮動小数点レジスタの精度がdoubleよりも高いマシンで奇妙な動作を引き起こす可能性があります。例えば、

void add (double a, double b, double & result) {
   double temp = a + b;
   result = temp;
   if (result != temp) {
      throw FunkyAdditionError (temp);
   }
}

この関数を最適化せずに使用するプログラムをコンパイルすると、おそらく例外は発生addしません。FunkyAdditionErrorコンパイルが最適化され、特定の入力が突然開始され、これらの例外が発生します。問題は、最適化を使用すると、コンパイラーはtempレジスターを作成しますresultが、参照であるため、レジスターにコンパイルされないことです。修飾子を追加するinlineと、コンパイラーをコンパイルするときにこれらの例外がなくなる可能性があります。これは、レジスターになることもできる-O3ためです。result浮動小数点演算に関する最適化は、難しい問題になる可能性があります。

最後に、プログラムが-O3、GCCでコンパイルされたときに物事が夜にぶつかったケースの1つを見てみましょう:プログラムはコンパイルオプション-O3では動作しません。この問題は-O3でのみ発生しました。これは、コンパイラがdistance関数をインライン化した可能性がありますが、結果の1つ(両方ではない)を拡張精度浮動小数点レジスタに保持したためです。この最適化により、特定のポイントp1p2の両方が発生し、p1<p2p2<p1評価される可能性がありtrueます。これは、比較関数の厳密な弱順序基準に違反します。

拡張精度の浮動小数点レジスタ(IntelやAMDなど)を備えたマシンで、最適化と浮動小数点演算がどのように相互作用するかについては、十分に注意する必要があります。

于 2013-02-13T12:29:53.260 に答える
4

1) と 3) あなたは正しいです。-O3 によって有効化される最適化の恩恵を受けるプログラムもあれば、そうでないプログラムもあります。たとえば、通常はより多くの関数をインライン化する方が適切ですが (関数呼び出しメカニズムのオーバーヘッドが回避されるため)、処理が遅くなる場合があります (たとえば、キャッシュの局所性が損なわれるため)。それとプラットフォームの多様性により、この問題についての一般的な推論は不可能になります。

簡潔に言うと、有効な唯一の答えは次のとおりです。両方で試して、コードをベンチマークして、どちらが速いかを確認してください。

2) コンパイラ/オプティマイザのバグに遭遇していないという仮説の下で (それらはまれですが、存在します)、プログラムのエラーが -O3 でのみ明らかになると仮定するのが合理的です。 -O3 オプションだけがそれを明らかにしました。

于 2013-02-13T10:49:09.117 に答える