diff Lib/IMPL/Profiler.pm @ 0:03e58a454b20

Создан репозитарий
author Sergey
date Tue, 14 Jul 2009 12:54:37 +0400
parents
children 16ada169ca75
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lib/IMPL/Profiler.pm	Tue Jul 14 12:54:37 2009 +0400
@@ -0,0 +1,139 @@
+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;