前回の
ボトルネックの特定
システムの現状が把握できたところで、
Time::HiResによる簡単な計測
Time::HiResモジュールを利用することで、
use Time::HiRes qw/ gettimeofday tv_interval /;
my $t0 = [ gettimeofday ]; # 計測開始
... # 処理時間を計測したい処理
my $elapsed = tv_interval($t0); # 経過時間(秒)
ここは遅いだろう、
Devel::KYTProfによる計測
特定の個所が遅いという目星が付いてはいないが、
use Devel::KYTProf;
use DBI;
use LWP::UserAgent;
my $dbh = DBI->connect("dbi:mysql:database=test");
my $sth = $dbh->prepare("SELECT * FROM foo WHERE name = ?");
$sth->execute("bar");
my $ua = LWP::UserAgent->new;
my $res = $ua->get("http://example.com/");
73.651 ms [DBI] connect dbi:mysql:database=test | main:4 13.390 ms [DBI::st] SELECT * FROM foo WHERE name = ? (bind: bar) (0 rows) | main:6 416.913 ms [LWP::UserAgent] GET http://example.com/ | main:8
デフォルトで計測可能なメソッドは次のとおりです。
- LWP::UserAgentのrequest
- Furl::HTTPのrequest
- DBIのconnect、
execute - Cache::Memcached::Fastのadd、
append、 set、 get、 gets、 delete、 prepend、 replace、 cas、 incr、 decr - MogileFS::Clientのedit_
file、 read_ file、 store_ file、 store_ content、 get_ paths、 get_ file_ data、 delete、 rename
このほかにも、Text::Xslate->render
を計測したい場合はリスト7のように記述します
Devel::KYTProf->add_prof(
"Text::Xslate",
"render",
sub {
my ($orig, $self, $file, $args) = @_;
return sprintf '%s %s', "render", $file;
}
);
my $xs = Text::Xslate->new;
$xs->render("test.xs", { foo => 1 });
1.972 ms [Text::Xslate] render test.xs | main:12
Devel::KYTProfは特定のメソッド呼び出しのみをTime::HiResを使用した計測処理でwrapするというしくみのため、
ただし、threshold
を設定することで、
# 100ms 以上かかった場合のみログを出力
Devel::KYTProf->threshold(100);
Devel::NYTProfによるプロファイリング
どこが問題なのか見当が付かない場合は、
perl
に-d:NYTProf
オプションを付けて実行するとnytprof.
というプロファイルデータが出力され、nytprofhtml
コマンドで処理することで、
$ perl -d:NYTProf yourprogram.pl $ nytprofhtml

コードのどの部分が何回呼ばれ、
Devel::NYTProfはPerl VMのディスパッチテーブルを書き換えることで計測処理を行います。すべての処理を計測するプロファイラとしては高速で、
PSGIアプリケーションサーバへの適用
Devel::NYTProfは比較的高速とはいえ、
# app.psgi
use POSIX::AtFork qw/:all/;
my @opts = qw( addpid=1 start=no sigexit=1
forkdepth=0 file=/tmp/nytprof.out );
$ENV{"NYTPROF"} = join ":", @opts;
require Devel::NYTProf;
pthread_atfork(
undef,
undef,
sub {
DB::enable_profile() if $$ % 11 == 0;
},
);
$app; # PSGI app
リスト8では、$$
)
リスト8の設定ではプロファイルデータは /tmp/
$$
はプロセスID)nytprofhtml
で処理できない、nytprofhtml
で処理して閲覧してください。
<続きの