Mercurial > pub > Impl
view Lib/IMPL/Profiler.pm @ 54:f4e045e47770
commit
author | wizard@linux-odin.local |
---|---|
date | Tue, 02 Mar 2010 20:15:57 +0300 |
parents | 16ada169ca75 |
children | 44977efed303 |
line wrap: on
line source
package IMPL::Profiler; our $Enabled; our %TrappedModules; our %InvokeInfo; our $InvokeTime = 0; my $level; BEGIN { $level = 0; if ($Enabled) { warn "profiler enabled"; no warnings 'once'; *CORE::GLOBAL::caller = sub { my $target = (shift || 0)+1; my $realFrame = 1; for (my $i = 1; $i<$target; $i++) { $realFrame ++; my $caller = CORE::caller($realFrame-1) or return; $realFrame ++ if $caller eq 'IMPL::Profiler::Proxy'; #current frame is proxy } my @frame = CORE::caller($realFrame) or return; if ( $frame[0] eq 'IMPL::Profiler::Proxy' ) { my @next = CORE::caller($realFrame+1) or return; @frame[0..2] = @next[0..2]; } #warn "\t"x$level,"$frame[0] - $frame[3]"; return wantarray ? @frame : $frame[0]; }; } } use strict; use warnings; use Time::HiRes; require Scalar::Util; sub trap_all { return if not $Enabled; no strict 'refs'; foreach my $class (@_) { next if $TrappedModules{$class}; $TrappedModules{$class} = 1; eval "warn 'load $class'; require $class;" if not %{"${class}::"}; die $@ if $@; no strict 'refs'; my $table = \%{"${class}::"}; trap($class,$_) foreach (grep *{$table->{$_}}{CODE}, keys %$table); } } sub trap { my ($class,$method) = @_; return if not $Enabled; no strict 'refs'; my $prevCode = \&{"${class}::${method}"}; my $proto = prototype $prevCode; if (defined $proto and not $proto) { return; } { package IMPL::Profiler::Proxy; no warnings 'redefine'; my $sub = sub { my $t0 = [Time::HiRes::gettimeofday]; my @arr; my $scalar; my $entry = $prevCode; my ($timeOwn,$timeTotal); my $context = wantarray; { local $InvokeTime = 0; #warn "\t"x$level,"enter ${class}::$method"; $level ++; if ($context) { @arr = &$entry(@_); } else { if (defined $context) { $scalar = &$entry(@_); } else { &$entry(@_); } } $timeTotal = Time::HiRes::tv_interval($t0); $timeOwn = $timeTotal - $InvokeTime; } $InvokeInfo{"${class}::${method}"}{Count} ++; $InvokeInfo{"${class}::${method}"}{Total} += $timeTotal; $InvokeInfo{"${class}::${method}"}{Own} += $timeOwn; $InvokeTime += $timeTotal; $level --; #warn "\t"x$level,"leave ${class}::$method"; return $context ? @arr : $scalar; }; if ($proto) { Scalar::Util::set_prototype($sub => $proto); } *{"${class}::${method}"} = $sub; } } sub PrintStatistics { my $hout = shift || *STDERR; print $hout "-- modules --\n"; print $hout "$_\n" foreach sort keys %TrappedModules; print $hout "\n-- stats --\n"; print $hout pad($_,50), pad("$InvokeInfo{$_}{Count}",10), pad(sprintf("%.3f",$InvokeInfo{$_}{Own}),10), pad(sprintf("%.3f",$InvokeInfo{$_}{Total}),10), "\n" foreach sort { $InvokeInfo{$b}{Own} <=> $InvokeInfo{$a}{Own} } keys %InvokeInfo; } sub ResetStatistics { $InvokeTime = 0; %InvokeInfo = (); } sub pad { my ($str,$len) = @_; if (length $str < $len) { return $str.(' 'x ($len- length $str)); } else { return $str; } } 1;