実行プロファイルの取得とparallel-mark

追記 : コメント参照, http://d.hatena.ne.jp/mjt/20090702/p2
moshとypsilonを比較すると、マイクロベンチマークではmoshが速いが、現実的なアプリケーションではypsilonの方が2〜10倍高速だということが多い。
研究ではmoshを単に接続管理用にしか使っていない*1ので大きな問題にはならないが、(昨日のような)"ちょっとした日常のプログラミング"でもypsilonではなくmoshも使いたいのでボトルネックを検討する必要が有る。
moshには備え付けのプロファイラが有るが、使い方が不明なのとサンプルファイルを何故かtmpに作るので使わず、まずは普通にgprofする。
gprofを使うためにはオプション-pgをCXXFLAGSやCFLAGSに足す。もちろんプロファイラはフレームポインタが必要なので-fomit-frame-pointerはconfigure後にMakefileを修正して取り除く必要が有る。
昨日のプログラムのループ回数を50回から2回に減らして実行すると :

  %   cumulative   self              self     total
 time   seconds   seconds    calls   s/call   s/call  name
 63.67    116.47   116.47 11080886     0.00     0.00  GC_mark_from
 10.31    135.32    18.85 847782669     0.00     0.00  GC_header_cache_miss
  4.68    143.89     8.57 15019965     0.00     0.00  scheme::VM::run

簡単に言えば、70%の時間はGCに費やされている。ypsilonはmostly concurrent GCなのでこの70%の時間を別のCPUで実行できる。

  • 特にオプション無し :
real    2m20.074s
user    2m19.093s
sys     0m0.445s

単純にsvnをチェックアウトして./configure、実行した場合。

  • enable-parallel-mark
real    2m4.363s
user    2m57.478s
sys     0m0.741s

15秒ほど高速化した。余計なロックが必要になるため、single coreシステムでは必要以上に遅くなるかもしれない。
もっとも、Boehm GCはN coreのシステムではmark threadを(N-1)つしか起動しない。この高速化はfree-listの作成などが並列化されることによると考えている。
gcリポジトリのではなく公式のものに入れ替えて適切に設定しても数秒しか高速化しない。

  • (参考) ypsilon
real    0m12.913s
user    0m22.013s
sys     0m3.288s

ypsilonの場合はほぼ常に2つのCPUが動作する。ypsilonはデザイン上の都合から、GCを常に動作させる必要が有る。

*1:もちろんこれは重要な役目で、人間がしっかり接続を管理するコードを書くよりも、GCのある言語で適当にやるほうが結局のところ高速なのではないかと考えている。