『Perlデバッグ』を買って、読んでました。タイトルどおりの書籍で Perl のデバッグ技法についての解説書です。Perl の文法上陥りがちな罠、Perl デバッガの使い方やエラーハンドリングに関する方針などが記述されています。割と薄めの本なので一気に読めます。
残念なことに訳がいまいち。洋書の Perl 本によくあるタイプの文章構成が巧な解説(詩的というかユーモアたっぷりというか) が直訳なので。
文章はそんな具合ですが、収穫も結構ありました。Perl デバッガの解説が簡潔でよいです。それから、Devel::DProf という Perl のプロファイラの使い方も載ってました。って、こんなのあるのいままで知らなかった..迂闊。
Deve::DProf はスクリプト上でどこの処理に時間がかかっているかを調べるもの。基本的にはサブルーチンもしくはメソッド単位でプロファイリングされます。
例えば、以下のようなコードがあったとします。これは引数に与えられた URL から LWP でリモートのコンテンツを GET し XML::RSS でパース、Template-Toolkit で整形して出力するスクリプトです。例外処理には今回の書籍でも触れられている Error モジュール (Perl で try 〜 catch 構文を可能にするモジュール) を使っています。
#!/usr/local/bin/perl
use strict;
use warnings;
use Encode qw(from_to);
use Error qw(:try);
use LWP::UserAgent;
use Template;
use XML::RSS;
## initializing Exception classes
@Exception::HTTP::ISA = 'Error';
@Exception::TT::ISA = 'Error';
@Exception::RSSParse::ISA = 'Error';
$Error::Debug = 1;
my $url = shift or die "need url";
try {
my $content = get_content($url);
my $output =
tt_process(\*DATA, {rss => parse_rss(\$content)});
Encode::_utf8_off($output);
from_to($output, 'utf-8', 'euc-jp');
print $output;
} catch Exception::HTTP with {
my $e = shift;
warn "HTTP Error: ", $e->object->message, $e->stacktrace;
} otherwise {
my $e = shift;
warn $e->stringify, $e->stacktrace;
};
sub get_content {
my $url = shift;
my $ua = LWP::UserAgent->new;
my $response = $ua->get($url);
if ($response->is_success) {
return $response->content;
} else {
throw Exception::HTTP -object => $response;
}
}
sub parse_rss {
my $content_ref = shift;
my $rss = XML::RSS->new;
eval {
$rss->parse($$content_ref);
}; if ($@) {
throw Exception::RSSParse -text => $@;
}
return $rss;
}
sub load_tt {
my $args = shift;
my $tt = Template->new($args)
or throw Exception::TT -text => $Template::ERROR;
return $tt;
}
sub tt_process {
my ($template, $param) = @_;
my $tt = load_tt();
my $output;
$tt->process($template, $param, \$output)
or throw Exception::TT -text => $tt->error;
return $output;
}
__DATA__
[% FOREACH item IN rss.items -%]
[% item.title %]
[% END -%]
このスクリプトをプロファイリングするには、スクリプトの実行時にオプションを渡します。
$ perl -d:DProf rss-dump.pl http://rr.bloghackers.net/index.rdf PAULのタルトと最近のお菓子の味わい方 Refactoring RSS feeds... 私のキャンドルナイト キノの旅 九十九十九 Caplio GX 用ワイコン DW-4 で22mmの広角域へ 世界は密室でできている。 ...
すると、カレントディレクトリに tmon.out というファイルが出力されるので、これを渡して dprofpp コマンドを実行します。
$ dprofpp tmon.out
Compress::Zlib::__ANON__ has 5 unstacked calls in outer
Exporter::Heavy::heavy_export has 6 unstacked calls in outer
Socket::__ANON__ has 6 unstacked calls in outer
Socket::AUTOLOAD has -6 unstacked calls in outer
HTTP::Message::AUTOLOAD has -5 unstacked calls in outer
Compress::Zlib::AUTOLOAD has -5 unstacked calls in outer
Exporter::export has -6 unstacked calls in outer
HTTP::Message::__ANON__ has 5 unstacked calls in outer
Total Elapsed Time = 0.548246 Seconds
User+System Time = 0.518246 Seconds
Exclusive Times
%Time ExclSec CumulS #Calls sec/call Csec/c Name
30.8 0.160 0.303 23542 0.0000 0.0000 XML::Parser::Expat::within_element
27.5 0.143 0.143 56756 0.0000 0.0000 XML::Parser::Expat::eq_name
13.8 0.072 0.108 13932 0.0000 0.0000 XML::Parser::Expat::generate_ns_na
me
10.4 0.054 0.480 3139 0.0000 0.0002 XML::RSS::handle_char
6.95 0.036 0.036 13932 0.0000 0.0000 XML::Parser::Expat::GenerateNSName
5.79 0.030 0.030 11 0.0027 0.0027 Template::Parser::BEGIN
5.79 0.030 0.070 8 0.0037 0.0087 Template::Config::load
5.79 0.030 0.099 7 0.0043 0.0141 main::BEGIN
5.02 0.026 0.522 1 0.0260 0.5218 XML::Parser::Expat::ParseString
4.63 0.024 0.024 5871 0.0000 0.0000 XML::Parser::Expat::current_elemen
t
1.93 0.010 0.010 1 0.0100 0.0100 Error::subs::with
1.93 0.010 0.010 3 0.0033 0.0033 IO::Socket::peername
1.93 0.010 0.010 3 0.0033 0.0033 Template::Stash::XS::BEGIN
1.93 0.010 0.010 8 0.0012 0.0012 DynaLoader::dl_find_symbol
1.93 0.010 0.010 6 0.0017 0.0017 Exporter::as_heavy
と、こんな具合でプロファイリング結果が得られます。XML::Parser による RSS 文書のパース、それから Template-Toolkit の初期化のオーバヘッドが結構あるのが確認できます。ここからより細かく、任意の処理をベンチしたいのであれば Benchmark モジュールを使うとよいでしょう。
CGI プログラムの場合は、shebang に
#!/usr/local/bin/perl -d:DProf
とオプションを渡してやればよいそうです。(via http://yuri.sakura.ne.jp/~propella/tips/Devel_DProf.html)
mod_perl 環境下で動作しているスクリプトのプロファイリングに関しては、Apache::DProf を使うと良いそうです。Google で検索したサイトに
mod_perlでプロファイルしてみたくなった。まず、Devel::DProfを試す。こいつは、デバッガとして起動させるものなんだが、mod_perl環境ではうまくファイル吐出しができない。なんか、うまくやる方法も出ていたんだけど、それよりもApache::DProfを使ったほうが簡単らしいのでこっちを利用。ポイントは、apache/logs/dprofって言うディレクトリにパーミッションを与えること、PerlModule Apache::DProfをhttpd.confに追加すること、Apache::Registryをロードしなければならないこと。
とありました。ふむふむ。
Devel 系のモジュールの使い方も覚えていかないとなあ。