=head1 SYNOPSIS
+ use Benchmark qw(:all) ;
+
timethis ($count, "code");
# Use Perl code in strings...
=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<cmpthese> 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<NOTE>: This result value differs from previous versions, which returned
+the C<timethese()> result structure. If you want that, just use the two
+statement C<timethese>...C<cmpthese> 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)
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
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
@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;
# --- 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 ; }
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)",
# 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
$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;
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';
}
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;
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 =
printf $format, @$_;
}
- return $results;
+ return \@rows ;
}