ラベル デバッグ の投稿を表示しています。 すべての投稿を表示
ラベル デバッグ の投稿を表示しています。 すべての投稿を表示

2014年5月24日土曜日

プロファイラを使ってみよう

プロファイラって使ってますか?

なんか思ったよりもっさり動いているなぁという時に思いつくがままに改良してみて、あまり上手くいかないというのは、改良している部分がプログラムのボトルネックではないからです。

しかしプログラムの中のどの部分が時間を食っているのかは分かりづらいこともあります。

そこで便利なのがプロファイラ。
プロファイラは実行されたプログラムの関数ごとの計算時間、呼び出し回数などなとを計測するかなり便利な代物です。

ここでは例としてgnuのg++プロファイラ、gprofの使い方を説明します。
使い方の手順としては、


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生産方式というのは有用でしょうが、一人の開発の場合資源の投下場所は考慮すべきでしょう。

2014年5月11日日曜日

Mutex Profiler Mutrace

プロファイラはコードのパフォーマンスをあげるのにとても役立ちます。コードのどこに時間がかかっているのかが非常に明瞭にわかるからです。

並列計算のパフォーマンスも一般的なプロファイラでかなり分かることがたくさんありますが、同期処理などのオーバーヘッドを見出すのは結構難しいです。
また、ロックをもっと細かくするにせよatom型を使うにせよ、そのような同期処理を改善するのは結構手間がかかるしどちらが速いか見積りずらいことは多々あります。

そういうときに便利なのがmutrace、Mutex Profilerです。

実行ファイルと一緒に使い、mutexのロック回数、ロックの推移回数、合計待ち時間、ロックの種類などを列挙してくれます。ので改善すべきロックが一目瞭然で分かります。

$ mutrace gedit

とシンプルなコマンドで使えます。出力はこんな感じ。
mutrace: 10 most contended mutexes:

 Mutex #   Locked  Changed    Cont. tot.Time[ms] avg.Time[ms] max.Time[ms]       Type
      35   368268      407      275      120,822        0,000        0,894     normal
       5   234645      100       21       86,855        0,000        0,494     normal
      26   177324       47        4       98,610        0,001        0,150     normal
(公式ページより引用)

こんな感じで出たら、35番のロックは改善した方がいいかな?って絞ることが出来るという訳です。
便利。
・参照リンク
公式ページ
mutraceのGitレポジトリ

2014年5月2日金曜日

printfよりもデバッガを使おう

デバッガを使わない人って意外にいるように思えます。

printfとかの出力で済ませられるバグも多いでしょう。いちいちデバッガをつかうのも大袈裟です。私がデバッガを使うべきだとする目安は、「ここが原因だろう」と考えて書いたprintfがハズレだった場合です。

多くの場合原因の候補箇所はいくつかの、直近に編集した表層部分のエラーでしょう。九割くらいのバグはここで解決されます。

しかし予想が外れた場合。これはえらいことです。エラーの原因がシステムのより深いところにあったということになります。人は、こういう予想外の自体に対してより近視眼にして対処してしまいがちだと言います。結果としてだんだんコードの狭い部分、狭い部分へと目を絞ってしまいます。

printfでのデバッグは、「ここに原因があるだろう」と予想して、それが正しいか否かしかわかりません。対してデバッガは「どの辺りに原因があるか」を測ることが出来ます。

謂わば、printfがクローズドクエスチョンなのに対してデバッガはオープンクエスチョンが出来る、ということです。

なので原因がよく分からないバグに対してはデバッガを使う方が賢明に思えます。二分木探索の方がリストを頭から探索するより速いですし。(そういう理由でデバッガの使い方のコツとして、二分木探索を心懸ける、というのがあったりします。)

デバッガの使い方は、UI部分はネットにいっぱい資料があります。「Eclipse デバッガ」で検索すれば丁寧な解説が見られるでしょう。デバッグの理念、例えば上述の二分木探索みたいな話を知りたい方は以下の「実践 デバッグ技法」をお勧めします。