2011年9月4日日曜日

コンパイラによる最適化の押し付けにむかついた件について

GCCの各オプティマイズレベルで有効になる最適化を調べるを読んでちょっと興味がわいたので、いろいろ手元の環境でも確認してみた。
試したマシンはQ9450とT7300のせいかどれもリンク先と同じ結果になったわけですが、とにかく意外だったのは
*-O2と-Osの違いは-finline-functionsの有無だけ(-Osは有り、-O2は無し)。

-Osはサイズ優先の最適化のはずだけど、-O3(とにかくスピード優先)でも-finline-functionsがつくのであれば、これを有効にすればそこそこスピードアップの可能性があるということだろう。
じゃあ、-O2の存在意義って一体なあに?
-O3程ではないが、それなりにスピード優先のはずなんだけど…。

とまあ、前置きはこのくらいにして、今度は各プロジェクトが設定しているデフォルトの最適化設定を調べてみた。

例えばx264は--extra-cflagsを設定しなければ
"-O3 -ffast-math -march=i686 -mfpmath=sse -msse -fomit-frame-pointer -fno-tree-vectorize -fno-zero-initialized-in-bss"
がつく(x86の場合)。
いかにも互換性を気にしつつも速そうな設定という感じですね。
まあ、クリティカルな部分はほぼすべてasmで書かれてCPU検出で自動的に有効にするので、コンパイラによるCコードの最適化はあまり影響しないそうですが。

これがxvidだと
"-O2 -fstrength-reduce -finline-functions -ffast-math -fomit-frame-pointer"
となっている。
configure.inには
First we test if CFLAGS have been passed on command line
I do that because autoconf defaults (-g -O2) suck and they would kill performance.
To prevent that we define a good defult CFLAGS at the end of the script if and only
if CFLAGS has not been passed on the command line
なんて書かれてますが、それにしては中途半端という印象が否めない。
現在でも更新は続いているんだから、いい加減sseをデフォルトにするくらいはしてもいいのでは?
configure.inにはこのデフォルト値に対して"Default CFLAGS -- Big impact on overall speed"とも書かれているあたり、コンパイラによる最適化はかなり重要みたいなんだけど…自分で設定したほうがよさそうですな。

さて問題はa52dec。
これのconfigure.inは以下のような感じになっている。
if test x"$GCC" = x"yes"; then
    changequote(<<,>>)
    OPT_CFLAGS=`echo "$CFLAGS"|sed "s/-O[0-9]*//g"`
    changequote([,])
    OPT_CFLAGS="$OPT_CFLAGS -O3"
    AC_TRY_CFLAGS([$OPT_CFLAGS],[CFLAGS=$OPT_CFLAGS])
なんとコンパイラがGCCだったら有無を言わさず-O3強制です。
たとえば何らかの理由でデバッグビルドしようと思ってCFLAGS="-O0 -g"しても、-O0は削除されて"-g -O3"なんていうへんてこりんなコードが出力されてしまいます。
しかも-O3は勝手につけるのに、-fno-tree-vectorizeはなし。
liba52はとても古いプロジェクトでCVSの最終更新は7年前。もはや死んだといってもおかしくない。
当時は-O3だけでも問題なかったのかも知れませんが、現在ではまともな出力が得られるかどうか非常に疑わしい、地雷コードと化しています。
これは不安定な-ftree-vectorizeを-O3で有効にしたままなかなか直さない(直せない?)GCCが悪いとも言えるかも知れないけど、素人がコードいじらなきゃいけないような自体はなるべく避けて欲しいなぁ。
とりあえずこんなパッチを書いてみたので、何かの事情で今時a52decをビルドしなければならない人は当てたほうがいいかもしれません。

あともう一つ、openjpegプロジェクト。
現在のstable release?であるはずのopenjpeg_v1_4_sources_r697.tgzをビルドしてみたら、設定したCFLAGSが全く反映されません。
なんでかな?とlibopenjpeg/Makefile.amを見てみたら
INCLUDES = -I.. -I.
COMPILERFLAGS = -Wall -O3 -ffast-math -std=c99
if with_sharedlibs
COMPILERFLAGS += -DOPJ_EXPORTS
else
COMPILERFLAGS += -DOPJ_STATIC
libopenjpeg_la_LDFLAGS += -static
endif
CFLAGS = $(COMPILERFLAGS) $(INCLUDES)
お前もかよ(そしてこれも-fno-tree-vectorizeなし)。
svnの最新コードなら直ってるかなと見てみると今度はcomfigure.acのほうで
if test "x${want_debug}" = "xyes" ; then
   OPJ_COMPILER_FLAG([-g])
   OPJ_COMPILER_FLAG([-O0])
else
   OPJ_COMPILER_FLAG([-O3])
fi
あくまでも-O3は決定ですかそーですか...........むかつくわホント

追記:
gcc4.7ではOsに-foptimize-strlenも追加されたようです(O2は追加なし)。
ますますO2の存在意義って…?

0 件のコメント:

コメントを投稿