June 21, 2004

Perl のプロファイリング via 『Perl デバッグ』

[ Perl ]

Perlデバッグ』を買って、読んでました。タイトルどおりの書籍で 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 系のモジュールの使い方も覚えていかないとなあ。

Posted by naoya at June 21, 2004 12:55 AM | トラックバック (0)  b_entry.gif
トラックバック [0件]
TrackBack URL: http://mt.bloghackers.net/mt/suck-tbspams.cgi/1071
コメント [0件]
コメントする









名前、アドレスを登録しますか?