今日はコンパイルの最適化オプションが単純なループと整数演算をどのくらい高速化できるかを見てみます。
サンプルプログラムをCで書きました。1からコマンド引数に渡した値まで順番に足し合わせるtest.cです。
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { long long unsigned int i=0, j=0, a=atoll(argv[1]); while (i<a) j += ++i; printf("%llu\n", j); return 0; }
環境は Ubuntu 12.04 の gcc version 4.6.3 を使います。
$ gcc -v ... gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
まずは、普通にコンパイルして実行します。
$ gcc test.c $ time ./a.out 9876543210 11879564747017720423 real 0m21.469s user 0m21.469s sys 0m0.000s
1から9876543210まで足し合わせるのに21秒かかりました。さて、最適化オプションを試してみましょう。ちなみに -O2 で有効になっているオプションを見るにはこんな感じでコマンドを打ちます。
$ gcc -c -Q -O2 --help=optimizers | grep enabled -falign-functions [enabled] -falign-jumps [enabled] -falign-labels [enabled] -falign-loops [enabled] -fasynchronous-unwind-tables [enabled] -fbranch-count-reg [enabled] -fcaller-saves [enabled] -fcombine-stack-adjustments [enabled] ...
うーん。なんとなく何をしてくれるかわかるのもあれば、よくわからないのもあります。ちゃんと知りたいときはmanを読めばいいんじゃないかな。とりあえず実行速度がどうなるのか知りたいだけなので -O2 を指定して実行してみましょう。
$ gcc test.c -O2 $ time ./a.out 9876543210 11879564747017720423 real 0m2.755s user 0m2.748s sys 0m0.004s
おぉ、速くなった、速くなった。どんな理屈で速くなってるかは謎ですが、ちゃんと9876543210サイクルの計算をしてる気もします。詳しく調べてみると面白そう。せっかくだから Mac OS X Mavericks でもやってみましょう。
$ gcc test.c -O $ time ./a.out 9876543210 11879564747017720423 real 0m0.005s user 0m0.001s sys 0m0.002s
なにこれ速すぎ。 Mavericks の xcode に入ってるコンパイラは、「これって等差数列の和を計算してるんだから、ループなんて必要ないじゃん」てことを解析してるっぽい。このコンパイラのバージョンはを見てみると、
$ gcc -v ... Apple LLVM version 5.0 (clang-500.2.79) ...
これ gcc やない、LLVM clang や。どうやら Mac OS X Mavericks の gcc コマンドの中身は LLVM clang みたいです。 LLVM かしこい。