sub countit {
my ( $tmax, $code ) = @_;
die usage unless @_;
if ( not defined $tmax or $tmax == 0 ) {
$tmax = $default_for;
} elsif ( $tmax < 0 ) {
$tmax = -$tmax;
}
die "countit($tmax, ...): timelimit cannot be less than $min_for.\n"
if $tmax < $min_for;
my ($n, $tc);
# First find the minimum $n that gives a significant timing.
for ($n = 1; ; $n *= 2 ) {
my $td = timeit($n, $code);
$tc = $td->[1] + $td->[2];
last if $tc > 0.1;
}
my $nmin = $n;
# Get $n high enough that we can guess the final $n with some accuracy.
my $tpra = 0.1 * $tmax; # Target/time practice.
while ( $tc < $tpra ) {
# The 5% fudge is to keep us from iterating again all
# that often (this speeds overall responsiveness when $tmax is big
# and we guess a little low). This does not noticably affect
# accuracy since we're not couting these times.
$n = int( $tpra * 1.05 * $n / $tc ); # Linear approximation.
my $td = timeit($n, $code);
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
# the max.
my $ntot = 0;
my $rtot = 0;
my $utot = 0.0;
my $stot = 0.0;
my $cutot = 0.0;
my $cstot = 0.0;
my $ttot = 0.0;
# The 5% fudge is because $n is often a few % low even for routines
# with stable times and avoiding extra timeit()s is nice for
# accuracy's sake.
$n = int( $n * ( 1.05 * $tmax / $tc ) );
while () {
my $td = timeit($n, $code);
$ntot += $n;
$rtot += $td->[0];
$utot += $td->[1];
$stot += $td->[2];
$cutot += $td->[3];
$cstot += $td->[4];
$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;
}
return bless [ $rtot, $utot, $stot, $cutot, $cstot, $ntot ];
}
# --- Functions implementing high-level time-then-print utilities
sub n_to_for {
my $n = shift;
return $n == 0 ? $default_for : $n < 0 ? -$n : undef;
}
$_Usage{timethis} = <<'USAGE';
usage: $result = timethis($time, 'code' ); or
$result = timethis($time, sub { code } );
USAGE
sub timethis{
my($n, $code, $title, $style) = @_;
my($t, $forn);
die usage unless defined $code and
(!ref $code or ref $code eq 'CODE');
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 );
=8= |