package Devel::SmallProf; # To help the CPAN indexer to identify us package DB; require 5.000; use strict; # Specify global vars use vars qw($print_lines $TIMEVAL_T $start $done $filename $line %profile %files $prevf $prevl %times $file @start @done $i $stat $time %eval_lines $pkg); $Devel::SmallProf::VERSION = '0.2'; $print_lines = 0; # Print contents of executed lines BEGIN{ $TIMEVAL_T = "LL"; $done = $start = pack($TIMEVAL_T, ()); require 'sys/syscall.ph'; syscall(&SYS_gettimeofday, $start, 0); } sub DB { syscall(&SYS_gettimeofday, $done, 0); ($pkg,$filename,$line) = (caller(0))[0..2]; no strict "refs"; if ($filename =~ /\(eval /) { $filename =~ s/(\(eval.*?\))/$pkg:$1/; $file = $1; $eval_lines{$filename}->[$line] = ${'main::_<'.$file}[$line]; } use strict "refs"; $profile{$filename}->[$line]++; @start = unpack($TIMEVAL_T,$start); @done = unpack($TIMEVAL_T,$done); $times{$prevf}->[$prevl] += ($done[0] + ($done[1]/1_000_000)) - ($start[0]+($start[1]/1_000_000)); $files{$filename}++; ($prevf, $prevl) = ($filename, $line); syscall(&SYS_gettimeofday, $start, 0); } END { # # Get time on last line executed. # syscall(&SYS_gettimeofday, $done, 0); @start = unpack($TIMEVAL_T,$start); @done = unpack($TIMEVAL_T,$done); $times{$prevf}->[$prevl] += ($done[0] + ($done[1]/1_000_000)) - ($start[0]+($start[1]/1_000_000)); # # Now write out the results. # open(OUT,">smallprof.out"); foreach $file (sort keys %eval_lines) { # print out evals first print OUT ("\n", "=" x 50, "\n", " Profile of $file\n", "=" x 50, "\n\n"); for $i (1..$#{$profile{$file}}) { $stat = $profile{$file}->[$i]; $time = $times{$file}->[$i]; chomp($_ = $eval_lines{$file}->[$i]); printf OUT ("%5d %.8f \t%4d:%s\n", $stat, $time, $i, $file.':'.$_); } } foreach $file (grep {!/\(eval/} sort keys %files) { print OUT ("\n", "=" x 50, "\n", " Profile of $file\n", "=" x 50, "\n\n"); if ($print_lines) { unless ($file =~ /\(eval /) { open(IN, "$file") || die "can't open $file."; $i = 0; while () { last if /^__END__/; $stat = $profile{$file}->[++$i]; $time = $times{$file}->[$i]; printf OUT ("%5d %.8f \t%s", $stat, $time, $_); } print OUT ("=" x 50, "\n"); } } else { unless ($file =~/\(eval /) { for ($i = 1; $i <= $#{$profile{$file}}; $i++) { $stat = $profile{$file}->[$i]; $time = $times{$file}->[$i]; printf OUT ("%5d %.8f \t%s\n", $stat, $time, $file.':'.$i); } } } } close OUT; } 1; __END__ =head1 NAME Devel::SmallProf - per-line Perl profiler =head1 SYNOPSIS perl5 -d:SmallProf test.pl =head1 DESCRIPTION The Devel::SmallProf is a small profiler which I find useful (or at least interesting :-) when used in conjuction with Devel::DProf. It collects statistics on the run times of the lines in the various files being run. Those statistics are placed in the file F in one of two formats. If C<$DB::print_lines> is false (the default), it prints: