なんか思ったよりもっさり動いているなぁという時に思いつくがままに改良してみて、あまり上手くいかないというのは、改良している部分がプログラムのボトルネックではないからです。
しかしプログラムの中のどの部分が時間を食っているのかは分かりづらいこともあります。
そこで便利なのがプロファイラ。
プロファイラは実行されたプログラムの関数ごとの計算時間、呼び出し回数などなとを計測するかなり便利な代物です。
ここでは例としてgnuのg++プロファイラ、gprofの使い方を説明します。
使い方の手順としては、
1. -pgオプションをつけてコンパイルする。
g++ -pg main.cc
2. 実行する。
./a.out
3. gprofを実行する。
gprof a.out
とするだけでプログラムの各関数の消費時間が空間的に理解できるように表示されます。
gprof出力の全文を載せるとちょっと詳細過ぎるのでここでは一番に見るべき情報に絞ります。
Flat profile: 各関数で結局どのくらい時間がかかったのか。
Call graph: 各関数がどのように他の関数から呼ばれたか。
この辺りを見ればどの関数を手直しすべきか分かると思います。1. -pgオプションをつけてコンパイルする。
g++ -pg main.cc
2. 実行する。
./a.out
3. gprofを実行する。
gprof a.out
とするだけでプログラムの各関数の消費時間が空間的に理解できるように表示されます。
gprof出力の全文を載せるとちょっと詳細過ぎるのでここでは一番に見るべき情報に絞ります。
Flat profile: 各関数で結局どのくらい時間がかかったのか。
Call graph: 各関数がどのように他の関数から呼ばれたか。
Flat profile: Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls s/call s/call name 67.15 30.77 30.77 2 15.39 23.14 f2 33.82 46.27 15.50 1 15.50 15.50 f1 0.07 46.30 0.03 main Call graph (explanation follows) granularity: each sample hit covers 2 byte(s) for 0.02% of 46.30 seconds index %time self children called name [1] 100.0 0.03 46.27 main [1] 30.77 15.50 2/2 f2 [2] ----------------------------------------------------- 30.77 15.50 2/2 main [1] [2] 99.9 30.77 15.50 2 f2 [2] 15.50 0.00 1/1 f11 [3] ---------------------------------------------------- 15.50 0.00 1/1 f2 [2] [3] 33.5 15.50 0.00 1 f1 [3] -----------------------------------------------
プロファイラはユニットテストみたいに使うと便利なんじゃないかと思います。
つまり、
1. コードを改善する。
2. 実行してプロファイラにかける。
3. プロフィールを分析し、次に改善すべき関数を決める。
のイテレーションを行えば効率良く質の高いコードがかけます。
とにかくはしから改善していけばいいじゃないか、という考えもありますが、アムダールの法則をみるに、ボトルネックとなっている関数から改善するという考えの方がプログラマ的なんじゃないかなと思います。
複数人の開発なら端から改善していく、TOYOTA生産方式というのは有用でしょうが、一人の開発の場合資源の投下場所は考慮すべきでしょう。