ApacheモジュールはApache httpdに組み込んで使うために、いまいちモジュール単体のテストやプロファイルやデバッグがやりにくい印象があります。
デバッグに関しては以前gdbを使った方法を紹介しましたが、今回は色々あるプロファイラの中で比較的楽にプロファイルが得られるOProfileを使ったプロファイルの取り方を紹介したいと思います。非常に簡単です。
ちなみに、プロファイラをかます事で対象そのものに影響を大きく与えてはいけないという意味で、この話だけでも研究になりそうですが、あまり深入りし過ぎるとまた別の方向にいってしまいそうなので、今回はそういった精度よりもどれだけ簡単にできるかというところに重点を置いた方法を紹介したいと思います。
OProfileでApache httpdをプロファイル
まずは、OProfileがインストールされている状態で以下のコマンドによりプロファイルの準備をします。近頃のディストリビューションだとyumやapt-getですぐインストールできるでしょう。
また、プロファイルしたいバイナリは-gや-O0によりデバッグシンボルを残した状態でコンパイルしていることを忘れないで下さい。stripしたバイナリとかではほとんど情報は取れません。
sudo opcontrol --start
この状態で、プロファイルを取りたいモジュールが入ったApache httpdを起動させます。そして、Apacheなのでベンチマークツールなどにより負荷をかけます。
今回は「mod_mrubyとmod_rubyの比較のためにプロファイルしてみよう」という目的で、それぞれのモジュールを組み込んだ状態で、mod_mrubyで処理されるhelloworldスクリプトとmod_rubyで処理されるhelloworldスクリプトそれぞれに同じ数(10000回)だけリクエストを処理させました。そして、負荷をかけ終わった後は、以下のようにプロファイラを停止します。
そして、プロファイルしたいApacheモジュールの.soバイナリのパスを指定してプロファイルを見てみましょう。
今回の場合だと、mod_mrubyとmod_ruby、さらに、mod_rubyからダイナミックリンクされているlibruby.soの情報が欲しいはずです(mod_mrubyはスタティックにmrubyインタプリタをリンクしているため)。その場合は、以下のように該当するバイナリパスを複数指定することで、それぞれのバイナリの処理のおおよそのパフォーマンス比較が可能になります。
すると以下のような結果が得られます。
------------------
324659 53.7996 libruby.so.1.9.1
180762 29.9543 mod_mruby.so
98039 16.2461 mod_ruby.so
libruby.so.1.9.1の処理を占める割合が多い事がわかります。さらにシンボル(関数名)単位で見て行きましょう。その場合は-lオプションを指定します。
すると以下のような結果が得られるます。
53510 8.8672 libruby.so.1.9.1 st_lookup
50795 8.4173 mod_mruby.so mrb_sym2name_len
22249 3.6869 mod_mruby.so yyparse
21571 3.5746 libruby.so.1.9.1 vm_exec_core
20125 3.3349 libruby.so.1.9.1 ruby_yyparse
12161 2.0152 libruby.so.1.9.1 ruby_sip_hash24
11266 1.8669 libruby.so.1.9.1 st_foreach
8647 1.4329 libruby.so.1.9.1 __i686.get_pc_thunk.bx
6988 1.1580 libruby.so.1.9.1 rb_newobj
6537 1.0833 mod_ruby.so ruby_type_handler
6175 1.0233 mod_mruby.so __i686.get_pc_thunk.bx
6138 1.0171 libruby.so.1.9.1 slot_sweep
5788 0.9591 libruby.so.1.9.1 .plt
5093 0.8440 mod_mruby.so parser_yylex
4943 0.8191 mod_ruby.so rb_init_apache_request
4933 0.8175 libruby.so.1.9.1 rb_funcall
4559 0.7555 libruby.so.1.9.1 iseq_setup
4519 0.7488 libruby.so.1.9.1 gc_marks
4446 0.7368 libruby.so.1.9.1 rb_funcall2
4428 0.7338 mod_ruby.so ruby_handler_0
4403 0.7296 mod_ruby.so ruby_handler_internal
4357 0.7220 mod_mruby.so nextc
4058 0.6725 libruby.so.1.9.1 rb_check_funcall
3948 0.6542 mod_ruby.so .plt
3933 0.6517 mod_mruby.so mrb_run
3918 0.6493 mod_ruby.so ruby_child_cleanup
3852 0.6383 libruby.so.1.9.1 vm_call0
・
・
・
mod_mrubyの場合はmrb_sym2nam_len()の処理が占める割合が多いんだなぁと分かります。例えばこのように得られた関数に最適化の余地があれば、そこを改善することで大幅にパフォーマンス改善することも可能になるでしょう。CRubyのruby_yyparseとmrubyのyyparseはほとんど同じなんだなぁとか、mod_ruby+libruby.so側はmod_mrubyと比べて色々な関数が呼ばれている事も分かりますね。
また、opannotateコマンドを使う事で、ソースコードレベルやさらにはアセンブリレベルでプロファイラが可能ですので、上記のコマンドに加えてopannotateの-sや-aオプションで結果を眺めると面白いと思います。
まとめ
このように、非常に簡単にApacheモジュールのプロファイルを取る方法を紹介しました。これで、よりC言語によるOSやmiddlewareまわりの実装が捗りますね。
0 Comments.