Devel::NYTProf で Starlet/Starman (Plack) でうごくウェブアプリケーションのプロファイリングをおこなう方法まとめ
Devel::NYTProf は Perl5 の世界でもっとも人気があるプロファイラである。表示が美麗であるし、ステップごとの処理速度が簡単にわかるのでとても便利だ。
そんな Devel::NYTProf であるが、Starlet/Starman のようなプリフォーク式のサーバーでうごくウェブアプリケーションとくみあわせる場合の方法論として、わかりやすい資料がみあたらなかったのでここに記すものである。
環境変数 NYTPROF を設定する
Devel::NYTProf は環境変数で挙動を変えられる。 plack とくみあわせる場合には、以下のようにするとよい。
NYTPROF=sigexit=int:savesrc=0:start=no
sigexit=int
通常、Devel::NYTProf は END { } ブロックでデータのファイナライズ処理をおこなうのだが、SIGNAL によってプロセスが終了させられた場合はデータがちょちょぎれてしまう。sigexit=int という風に指定すると SIGINT のハンドラを設定して、データのファイナライズ処理をはしらせます。
savesrc=0
Devel::NYTprof はデフォルトではソースを全部 nytprof.out の中にコピーします。これは不要な場合もあるので、不要な場合は savesrc=0 を指定することにより、nytprof.out のデータサイズがちいさくなる気がしています。
start=no
Devel::NYTProf はデフォルトでは読みこまれた時点でプロファイリングがスタートするのですが、Plack のアプリケーションを起動する時点からプロファイラうごかしはじめると、accept や wait3 などの、Starlet の httpd 部分の処理がデータにのってきてしまってワケワカメとなる。
start=no を指定しておくと、NYTProf の処理は起動せず、明示的に起動したタイミングからプロファイラがはしることになる。
stmt=0
上記にはでていないが、おぼえておきたいのがこのオプションだ。これを指定すると、ステートメントレベルでのプロファイリングが無効になるので、爆速になる。本番のサーバーにいれこんだりする場合にはこれをつかうのも有効だろう。
file=/tmp/report/nytprof.out
nytprof.out を出力するパスを変更できる。file の指定をしているときに、fork すると出力ファイルが /tmp/report/nytprof.out.$$ になることに注意していただきたい。
Plack のミドルウェアを指定する
以下のようなシンプルなコードをぶっこんでやればよい。アプリケーションのコードが実行される前にプロファイラを有効にし、おわったら無効にするだけである。
enable sub {
my $app = shift;
sub {
my $env = shift;
DB::enable_profile();
my $res = $app->($env);
DB::disable_profile();
return $res;
};
};
DB::enable_profile("/tmp/oyoyoo." . $i++);
みたいにすれば、任意のファイル名を記入することができる。
データを集計する
nytprofmerge nytprof.out.*
nytprofhtml -m --file=nytprof-merged.out --open
nytprofmerge コマンドにより、nytprof.out.$$
なファイルたちを1ファイルにマージすることが必要だ。特定のファイルだけでいいなら、特定のファイルのぶんだけnytprofhtml しても別によい。
マージしたら、あとは nytprofhtml をかけるだけだ。nytprofhtml --file=nytprof-merged.out を指定して、マージ結果をもとにデータをだすようにする。-m オプションにより、あんまいらないデータをはぶいて、高速にデータをつくります。
まあ、このへんは単純ですね。
まとめ
単純な操作のつみかさねで Starlet/Starman でうごいているアプリケーションのプロファイリングができるということがおわかりいただけたことだろう。
このあたりのコツを体得すれば、パフォーマンスチューニングは怖くない。
P.S.
Plack::Middleware::Profiler::NYTProf はぶっこわれてるそうなので、つかわないのがいいとおもいます。
P.S. (2)
ついでに「DB::enable_profile() if $$ % 100 = 0」とかやって本番に入れておくと常にプロファイルが取れて、後から問題発生源を探すことができて楽だとかそうでないとか / “Devel::NYTProf…” http://t.co/LTjJxJUmS1
— Kazuho Oku (@kazuho) October 8, 2013
P.S. (3)
Starman/StarletでNYTProfでのプロファイリングするのは1年前にWEB+DB Pressに書いてた http://t.co/H3rBzSN6bG
— fujiwara (@fujiwara) October 8, 2013