未来のいつか/hyoshiokの日記

hyoshiokの日々思うことをあれやこれや

最適化オプション(-O2など)とデバッグオプション(-g)を一緒につける101の理由

gdb豆知識(続き)(d:id:hyoshiok:20080927#p1)で

時々、デバッグオプション(-g)を付けるときは最適化オプションをつけない、あるいは-O0(アルファベットのオーにゼロ)をするというような都市伝説のようなものがあるが、わたしは意味がないと思う。最適化したコードは、ソースコードの字面とは異なる実行フローとか、関数のインライン化とかいろいろ施されているが、それも含めてのデバッグプロセスになれるようにしたい。

と記したのであるが、id:jj1bdx よりコメントをいただいたので、補足してみたい。

最適化オプションを付けると、コンパイラの種々の最適化技術により、関数をインライン化したり、ループをアンローリングしたり、ソースコードの字面とは異なるオブジェクトコードが生成される。

例えばインライン化された関数の場合、その関数名でのブレークポイントの設定ができなくなる。オブジェクトコードのエントリーポイントがなくなるのでその関数名がシンボルテーブルに載っていないため。あれれ?という感じである。

最適化によってローカルな変数がレジスタに載っていたりすると p 変数、とかやっても表示できない。p $eax とかしてレジスタを直接表示させないといけない。またまた、あれれ?という感じである。

初心者は、ここで戸惑う。

戸惑うので、それを考慮して、最適化オプションなしでコンパイル、ビルドしたくなる。それが人情というものである。それはわかるが、そこで留まってはいけない。なぜか。

CとかC++とか手続き型プログラミング言語でしこしこプログラムを書くということは、コンパイラという道具だてを利用してコンピュータに対して期待すべき動作を伝えている。コンパイラが無色透明ということはありえない。

コンパイラの最適化オプションの詳細について逐一知る必要はないが、最適化オプションによってコードの実行の順番がソースコードの順ではない場合があるということ位は理解しておく必要があると思う。

理解した上で、実行速度を向上させるために最適化オプションをつけるわけである。

最適化オプションをつけないでコンパイル、ビルドするおもちゃのコードであれば、別にどーでもいいのであるが、通常のソフトウェアであればデフォルトで-O2はつけていると思うので、わざわざ外す必要はない。

デバッグのためだけに最適化オプションを付けないという立場も考えられる。これも悪手である。

その立場の場合、最適化オプション付きのバイナリと最適化オプションなしのバイナリの2種類のバイナリを維持管理する必要がでてくる。

管理すべき実体が増えることは管理のコストが増加して、よろしくない。最適化オプションなしのバイナリで延々デバッグしていたのだが、実は最適化オプションありのバイナリでは当該バグに遭遇しないとか、そもそも、同じソースからコンパイル、ビルドしたのかをどう管理するのかとか、様々なコストが発生する。

マーフィーの法則のとおり、状況は最悪の方向にころがるのである。最適化オプションなしのバイナリはちゃんとデバッグしたんだけど、最適化オプション付きのバイナリは一世代前のバイナリで、バグ付きのまま出荷しちゃったよ、とか悪夢は列挙のいとまがない。

2つバイナリを用意すれば間違いなくテストの工数は2倍になるし、管理のコストも増大する。

プログラマは楽をしたがる人種である。なぜ好きこのんで問題を複雑化するのか。テスト、デバッグするバイナリは一つであるべきだ。そして出荷するコードが最適化オプション付きのものであれば、当然、最適化オプション付きでテスト、デバッグする。

わたしにはそれがベストプラクティスだと思う。すくなくとも、それが「わたしの流儀」である。

異論、反論、多事争論。コメント、ブックマーク、トラックバック等いただければ望外の喜びである。