gccのprofiledでx264をビルドする

ググっても案外使っている人が居ないみたいなので、メモを残しておく。
x264では標準でgccのprofile情報に基づいたコンパイルオプションがMakefileに書かれてある。しかし、これは標準では選択されないので明示的に選ぶ必要がある。
まずはプロファイルを採るにあたってのサンプルとなる動画を用意する。今回はffmpegを使った。

ffmpeg -y -an -t 60 -i input.mpg -f yuv4mpegpipe dest.y4m

動画全編を食わせると時間がかかりすぎるので、先頭から60秒だけをYUV4MPEGという形式で保存。これは非圧縮形式なので、非常に大きくなるので注意。
で、次にx264をビルド。configure段階では特別に指定することは無いので、用途に合わせて適当に。

./configure --enable-shared --enable-pthread

で、make時に先程用意した動画を食わせる。

make fprofiled VIDS="dest.y4m"

これで、profile付きのx264がビルドされて、その後をのプロファイル情報を元に再度バイナリができる。
実際何をやっているかと言うと、以下がMakefileの該当箇所。

fprofiled:
$(MAKE) clean
mv config.mak config.mak2
sed -e 's/CFLAGS.*/& -fprofile-generate/; s/LDFLAGS.*/& -fprofile-generate/' config.mak2 > config.mak
$(MAKE) x264$(EXE)
$(foreach V, $(VIDS), $(foreach I, 0 1 2 3 4 5 6 7, ./x264$(EXE) $(OPT$I) $(V) --progress -o $(DEVNULL)
;))
rm -f $(SRC2:%.c=%.o)
sed -e 's/CFLAGS.*/& -fprofile-use/; s/LDFLAGS.*/& -fprofile-use/' config.mak2 > config.mak
$(MAKE)
rm -f $(SRC2:%.c=%.gcda) $(SRC2:%.c=%.gcno)
mv config.mak2 config.mak

CFLAGSとLDFLAGSに-fprofile-generateを付けてバイナリを作った後、それで何度かエンコードし、実行情報を記録させている。その後バイナリなどは消して、それを使うためのオプションに替えて再度作っている。
エンコードは以下の8パターンで実行されており、これで一通りの実行パスを網羅できるのだろう。

# These should cover most of the important codepaths
OPT0 = --crf 30 -b1 -m1 -r1 --me dia --no-cabac --pre-scenecut --direct temporal --no-ssim --no-psnr
OPT1 = --crf 16 -b2 -m3 -r3 --me hex -8 --direct spatial --no-dct-decimate
OPT2 = --crf 26 -b2 -m5 -r2 --me hex -8 -w --cqm jvt --nr 100
OPT3 = --crf 18 -b3 -m9 -r5 --me umh -8 -t1 -A all --mixed-refs -w --b-pyramid --direct auto --no-fast-pskip
OPT4 = --crf 22 -b3 -m7 -r4 --me esa -8 -t2 -A all --mixed-refs
OPT5 = --frames 50 --crf 24 -b3 -m9 -r3 --me tesa -8 -t1 --mixed-refs
OPT6 = --frames 50 -q0 -m9 -r2 --me hex -Aall
OPT7 = --frames 50 -q0 -m2 -r1 --me hex --no-cabac

で、肝心の効果だが、スクリプトを書いて通常のバイナリとそうでないときを比較したところ。以下の通りとなった。データはいずれも最新のx264のソースでgcc 4.3.2の結果

動画 標準 profile反映
a 64.52 61.41 95.1
b 60.29 59.41 98.54
c 53.02 51.79 97.6
d 84.6 80.68 95.3
合計 262.43 253.29 96.5

4%程度は速くなるようだ。いずれも遅くなったケースはないので、やらないよりはやった方がいいかもしれない。
今回試したプラットフォームがx86_64だったので、アセンブラで書かれた箇所が有効になっているため実はそれほど効果が出なかったのかもしれない。アセンブラで書かれていないプラットフォームや全編がCで記述されているソフトウェアで演算中心ならば、もう少し効果がでるかも