1. ホーム
  2. c++

[解決済み】g++の最適化レベル-O3は危険か?

2022-05-10 20:58:18

質問

様々な情報源から(主に私の同僚からですが)、最適化レベルを -O3 g++では、何らかの形で「危険」であり、必要性が証明されない限り、一般的には避けるべきとされています。

それは本当なのか、本当ならなぜなのか。もしそうなら、私はただ -O2 ?

解決方法は?

gccの初期(2.8など)やegcsの時代、redhat 2.96では、-O3はかなりバグが多いことがありました。しかし、これは10年以上前のことで、-O3は他のレベルの最適化と(バグの多さにおいて)大差はありません。

しかし、言語のルール、特にコーナーケースをより厳密に信頼するために、未定義の動作に依存しているケースが明らかになる傾向があります。

個人的なことですが、私は長年にわたって金融分野のプロダクションソフトウェアを-O3で運用していますが、-O2を使っていたらなかったであろうバグにはまだ遭遇していません。

ご好評につき、追加です。

-O3、特に -funroll-loop (-O3 では有効になりません) のような追加フラグにより、より多くのマシンコードが生成されることがあります。特定の状況下では(例えば、L1命令キャッシュが非常に小さいCPUの場合)、例えばある内部ループのすべてのコードがL1Iに収まらなくなり、速度低下の原因となることがあります。一般にgccはそれほど多くのコードを生成しないように努めていますが、通常は一般的なケースを最適化するため、このようなことが起こり得ます。特にこのようなことが起こりやすいオプション(ループアンローリングなど)は、 通常-O3には含まれず、マニュアルページにもそのように記載されています。そのため、高速なコードを生成するには-O3を使用し、適切な場合(プロファイラーがL1Iミスを示した場合など)だけ-O2または-Os(コードサイズに最適化しようとする)にフォールバックするのが一般的な良い方法です。

最適化を極端に行いたい場合は、gcc の --param で特定の最適化に関連するコストを調整することができます。ある関数で -O3 の問題が見つかったとき (あるいはその関数だけの特別なフラグを試したいとき)、ファイル全体、あるいはプロジェクト全体を O2 でコンパイルする必要はありません。

一方、-Ofast を使用する場合は注意が必要なようです。

-Ofast はすべての -O3 最適化を有効にします。 また、すべての標準的な最適化では有効でない最適化も有効になります。 準拠のプログラムです。

ということは、-O3は完全に標準に準拠することを意図しているという結論になりますね。