| Benchmark-ProgressBar documentation | Contained in the Benchmark-ProgressBar distribution. |
Benchmark::ProgressBar - Display Progress Bar While You Wait For Your Benchmark
use Benchmark::ProgressBar qw(cmpthese);
cmpthese(10_000, {
a => sub { ... },
b => sub { ... },
} );
This is a VERY crude combination of Benchmark.pm and Term::ProgressBar. Basically I got sick of waiting for my benchmarks to finish up without knowing an ETA.
You can use it as a drop-in replacement for Benchmark.pm, but the only functions that would display a progress bar are the ones listed here: cmpthese, timethese, and timeit.
This is achieved via crude (a VERY crude) re-definition of Benchmark.pm's subrountines, so you shouldn't be mixing it with Benchmark.pm (I don't know why you would)
It does the job for me, YMMV. Patches are welcome.
Copyright (c) 2008 Daisuke Maki daisuke@endeworks.jp
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
See http://www.perl.com/perl/misc/Artistic.html
| Benchmark-ProgressBar documentation | Contained in the Benchmark-ProgressBar distribution. |
# $Id$ package Benchmark::ProgressBar; use strict; use warnings; use Benchmark; use Term::ProgressBar; our $VERSION = '0.00001'; sub import { Benchmark->export_to_level(1, @_); } package # hide from PAUSE Benchmark; use strict; no warnings 'redefine'; my $default_for = 3; my $min_for = 0.1; our $ProgressTitle; sub runloop { my($n, $c) = @_; $n+=0; # force numeric now, so garbage won't creep into the eval croak "negative loopcount $n" if $n<0; confess usage unless defined $c; my($t0, $t1, $td); # before, after, difference # find package of caller so we can execute code there my($curpack) = caller(0); my($i, $pack)= 0; while (($pack) = caller(++$i)) { last if $pack ne $curpack; } my $progress = Term::ProgressBar->new({ count => $n, remove => 1, name => $ProgressTitle || "progress" }); my ($subcode, $subref); if (ref $c eq 'CODE') { $subcode = "sub { for (1 .. $n) { local \$_; package $pack; \$progress->update(\$_); &\$c; } }"; $subref = eval $subcode; } else { $subcode = "sub { for (1 .. $n) { local \$_; package $pack; \$progress->update(\$_); $c;} }"; $subref = _doeval($subcode); } croak "runloop unable to compile '$c': $@\ncode: $subcode\n" if $@; print STDERR "runloop $n '$subcode'\n" if $Benchmark::Debug; # Give one more line so that the progress bar is easier on the eye #print "\n"; # Wait for the user timer to tick. This makes the error range more like # -0.01, +0. If we don't wait, then it's more like -0.01, +0.01. This # may not seem important, but it significantly reduces the chances of # getting a too low initial $n in the initial, 'find the minimum' loop # in &countit. This, in turn, can reduce the number of calls to # &runloop a lot, and thus reduce additive errors. my $tbase = Benchmark->new(0)->[1]; while ( ( $t0 = Benchmark->new(0) )->[1] == $tbase ) {} ; $subref->(); $t1 = Benchmark->new($n); $td = &timediff($t1, $t0); timedebug("runloop:",$td); $td; } sub timethis{ my($n, $code, $title, $style) = @_; my($t, $forn); die usage unless defined $code and (!ref $code or ref $code eq 'CODE'); local $ProgressTitle = $title; if ( $n > 0 ) { croak "non-integer loopcount $n, stopped" if int($n)<$n; $t = timeit($n, $code); $title = "timethis $n" unless defined $title; } else { my $fort = n_to_for( $n ); $t = countit( $fort, $code ); $title = "timethis for $fort" unless defined $title; $forn = $t->[-1]; } local $| = 1; $style = "" unless defined $style; printf("%10s: ", $title) unless $style eq 'none'; print timestr($t, $style, $Benchmark::Default_Format),"\n" unless $style eq 'none'; $n = $forn if defined $forn; # A conservative warning to spot very silly tests. # Don't assume that your benchmark is ok simply because # you don't get this warning! print " (warning: too few iterations for a reliable count)\n" if $n < $Benchmark::Min_Count || ($t->real < 1 && $n < 1000) || $t->cpu_a < $Benchmark::Min_CPU; $t; } 1; __END__