X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FBenchmark.pm;h=cda764f6ca317bc9e7b9fe0a2fc1a98d5d9fcb4e;hb=08411240a1e5278b0232e1455d984110b1c5343b;hp=487ddd5717284e4a163ce9c147b2709d8c915e98;hpb=8a4f6ac230f3943b15bcb439d434cc52e5da1bc3;p=p5sagit%2Fp5-mst-13.2.git diff --git a/lib/Benchmark.pm b/lib/Benchmark.pm index 487ddd5..cda764f 100644 --- a/lib/Benchmark.pm +++ b/lib/Benchmark.pm @@ -6,6 +6,8 @@ Benchmark - benchmark running times of Perl code =head1 SYNOPSIS + use Benchmark qw(:all) ; + timethis ($count, "code"); # Use Perl code in strings... @@ -196,17 +198,48 @@ Clear all cached times. =item cmpthese ( COUT, CODEHASHREF, [ STYLE ] ) -=item cmpthese ( RESULTSHASHREF ) +=item cmpthese ( RESULTSHASHREF, [ STYLE ] ) + +Optionally calls timethese(), then outputs comparison chart. This: + + cmpthese( -1, { a => "++\$i", b => "\$i *= 2" } ) ; + +outputs a chart like: + + Rate b a + b 2831802/s -- -61% + a 7208959/s 155% -- + +This chart is sorted from slowest to fastest, and shows the percent speed +difference between each pair of tests. -Optionally calls timethese(), then outputs comparison chart. This -chart is sorted from slowest to fastest, and shows the percent -speed difference between each pair of tests. Can also be passed -the data structure that timethese() returns: +c can also be passed the data structure that timethese() returns: - $results = timethese( .... ); + $results = timethese( -1, { a => "++\$i", b => "\$i *= 2" } ) ; cmpthese( $results ); -Returns the data structure returned by timethese() (or passed in). +in case you want to see both sets of results. + +Returns a reference to an ARRAY of rows, each row is an ARRAY of cells from the +above chart, including labels. This: + + my $rows = cmpthese( -1, { a => '++$i', b => '$i *= 2' }, "none" ); + +returns a data structure like: + + [ + [ '', 'Rate', 'b', 'a' ], + [ 'b', '2885232/s', '--', '-59%' ], + [ 'a', '7099126/s', '146%', '--' ], + ] + +B: This result value differs from previous versions, which returned +the C result structure. If you want that, just use the two +statement C...C idiom shown above. + +Incidently, note the variance in the result values between the two examples; +this is typical of benchmarking. If this were a real benchmark, you would +probably want to run a lot more iterations. =item countit(TIME, CODE) @@ -274,29 +307,39 @@ accuracy and does not usually noticably affect runtimes. For example, - use Benchmark;$x=3;cmpthese(-5,{a=>sub{$x*$x},b=>sub{$x**2}}) + use Benchmark qw( cmpthese ) ; + $x = 3; + cmpthese( -5, { + a => sub{$x*$x}, + b => sub{$x**2}, + } ); outputs something like this: Benchmark: running a, b, each for at least 5 CPU seconds... - a: 10 wallclock secs ( 5.14 usr + 0.13 sys = 5.27 CPU) @ 3835055.60/s (n=20210743) - b: 5 wallclock secs ( 5.41 usr + 0.00 sys = 5.41 CPU) @ 1574944.92/s (n=8520452) - Rate b a - b 1574945/s -- -59% - a 3835056/s 144% -- + Rate b a + b 1559428/s -- -62% + a 4152037/s 166% -- + while - use Benchmark; - $x=3; - $r=timethese(-5,{a=>sub{$x*$x},b=>sub{$x**2}},'none'); - cmpthese($r); + use Benchmark qw( timethese cmpthese ) ; + $x = 3; + $r = timethese( -5, { + a => sub{$x*$x}, + b => sub{$x**2}, + } ); + cmpthese $r; outputs something like this: - Rate b a - b 1559428/s -- -62% - a 4152037/s 166% -- + Benchmark: running a, b, each for at least 5 CPU seconds... + a: 10 wallclock secs ( 5.14 usr + 0.13 sys = 5.27 CPU) @ 3835055.60/s (n=20210743) + b: 5 wallclock secs ( 5.41 usr + 0.00 sys = 5.41 CPU) @ 1574944.92/s (n=8520452) + Rate b a + b 1574945/s -- -59% + a 3835056/s 144% -- =head1 INHERITANCE @@ -346,6 +389,12 @@ September, 1999; by Barrie Slaymaker: math fixes and accuracy and efficiency tweaks. Added cmpthese(). A result is now returned from timethese(). Exposed countit() (was runfor()). +December, 2001; by Nicholas Clark: make timestr() recognise the style 'none' +and return an empty string. If cmpthese is calling timethese, make it pass the +style in. (so that 'none' will suppress output). Make sub new dump its +debugging output to STDERR, to be consistent with everything else. +All bugs found while writing a regression test. + =cut # evaluate something in a clean lexical environment @@ -361,8 +410,9 @@ use Exporter; @EXPORT=qw(timeit timethis timethese timediff timestr); @EXPORT_OK=qw(timesum cmpthese countit clearcache clearallcache disablecache enablecache); +%EXPORT_TAGS=( all => [ @EXPORT, @EXPORT_OK ] ) ; -$VERSION = 1.00; +$VERSION = 1.04; &init; @@ -391,7 +441,7 @@ sub disablecache { $cache = 0; } # --- Functions to process the 'time' data type sub new { my @t = (time, times, @_ == 2 ? $_[1] : 0); - print "new=@t\n" if $debug; + print STDERR "new=@t\n" if $debug; bless \@t; } sub cpu_p { my($r,$pu,$ps,$cu,$cs) = @{$_[0]}; $pu+$ps ; } @@ -423,19 +473,20 @@ sub timestr { my @t = @$tr; warn "bad time value (@t)" unless @t==6; my($r, $pu, $ps, $cu, $cs, $n) = @t; - my($pt, $ct, $t) = ($tr->cpu_p, $tr->cpu_c, $tr->cpu_a); + my($pt, $ct, $tt) = ($tr->cpu_p, $tr->cpu_c, $tr->cpu_a); $f = $defaultfmt unless defined $f; # format a time in the required style, other formats may be added here $style ||= $defaultstyle; + return '' if $style eq 'none'; $style = ($ct>0) ? 'all' : 'noc' if $style eq 'auto'; my $s = "@t $style"; # default for unknown style $s=sprintf("%2d wallclock secs (%$f usr %$f sys + %$f cusr %$f csys = %$f CPU)", - @t,$t) if $style eq 'all'; + $r,$pu,$ps,$cu,$cs,$tt) if $style eq 'all'; $s=sprintf("%2d wallclock secs (%$f usr + %$f sys = %$f CPU)", $r,$pu,$ps,$pt) if $style eq 'noc'; $s=sprintf("%2d wallclock secs (%$f cusr + %$f csys = %$f CPU)", $r,$cu,$cs,$ct) if $style eq 'nop'; - $s .= sprintf(" @ %$f/s (n=$n)", $n / ( $pu + $ps )) if $n; + $s .= sprintf(" @ %$f/s (n=$n)", $n / ( $pu + $ps )) if $n && $pu+$ps; $s; } @@ -498,7 +549,7 @@ sub timeit { if ($cache && exists $cache{$cache_key} ) { $wn = $cache{$cache_key}; } else { - $wn = &runloop($n, ref( $code ) ? sub { undef } : '' ); + $wn = &runloop($n, ref( $code ) ? sub { } : '' ); # Can't let our baseline have any iterations, or they get subtracted # out of the result. $wn->[5] = 0; @@ -552,7 +603,9 @@ sub countit { # accuracy since we're not couting these times. $n = int( $tpra * 1.05 * $n / $tc ); # Linear approximation. my $td = timeit($n, $code); - $tc = $td->[1] + $td->[2]; + my $new_tc = $td->[1] + $td->[2]; + # Make sure we are making progress. + $tc = $new_tc > 1.2 * $tc ? $new_tc : 1.2 * $tc; } # Now, do the 'for real' timing(s), repeating until we exceed @@ -581,6 +634,7 @@ sub countit { $ttot = $utot + $stot; last if $ttot >= $tmax; + $ttot = 0.01 if $ttot < 0.01; my $r = $tmax / $ttot - 1; # Linear approximation. $n = int( $r * $ntot ); $n = $nmin if $n < $nmin; @@ -643,7 +697,8 @@ sub timethese{ print " ", join(', ',@names) unless $style eq 'none'; unless ( $n > 0 ) { my $for = n_to_for( $n ); - print ", each for at least $for CPU seconds" unless $style eq 'none'; + print ", each" if $n > 1 && $style ne 'none'; + print " for at least $for CPU seconds" unless $style eq 'none'; } print "...\n" unless $style eq 'none'; @@ -658,10 +713,9 @@ sub timethese{ } sub cmpthese{ - my $results = ref $_[0] ? $_[0] : timethese( @_ ); + my ($results, $style) = ref $_[0] ? @_ : ( timethese( @_[0,1,2] ), $_[2] ) ; - return $results - if defined $_[2] && $_[2] eq 'none'; + $style = "" unless defined $style; # Flatten in to an array of arrays with the name as the first field my @vals = map{ [ $_, @{$results->{$_}} ] } keys %$results; @@ -757,6 +811,8 @@ sub cmpthese{ push @rows, \@row; } + return \@rows if $style eq "none"; + # Equalize column widths in the chart as much as possible without # exceeding 80 characters. This does not use or affect cols 0 or 1. my @sorted_width_refs = @@ -788,7 +844,7 @@ sub cmpthese{ printf $format, @$_; } - return $results; + return \@rows ; }