# This code runs on perl4.036 and newer perls.  Usage:
#
#   require 'benchlib.pl';
#   runtest(1000, <<'ENDTEST');
#       # some testing code here
#   ENDTEST

package benchlib;

$cpu_factor = shift;
if (!$cpu_factor) {
    die "No CPU factor specified\n";
}
$empty_cycles_per_sec = shift;

sub main::runtest
{
    local($scale, $code) = @_;
    print "Date: " . &time2iso() . "\n";
    print "Test: $0\n";
    print "Perl: $^X $]\n";
    $scale = int($scale * $cpu_factor);
    $scale = 1 if $scale < 1;
    $code = <<'EOT1' . $code . <<EOT2 . $code . <<'EOT3';
# warm up
for ($i = 0; $i < 2; $i++) {
   package main;
   #---- test code ----
EOT1
   #-------------------
}

\$before_r = time;
(\$before_u, \$before_s, \$before_cu, \$before_cs) = times;
for (\$i = 0; \$i < $scale; \$i++) {
   package main;
   #---- test code ----
EOT2
   #-------------------
}
($after_u, $after_s, $after_cu, $after_cs) = times;
$after_r = time;

$user   = ($after_u - $before_u) + ($after_cu - $before_cu);
$system = ($after_s - $before_s) + ($after_cs - $before_cs);
$real   = ($after_r - $before_r);
$used   = $user + $system;

print "Cycles: $scale\n";
print "User-Time: $user\n";
print "System-Time: $system\n";
printf "Real-Time: %.*f\n", ($hires ? 3 : 0), $real;
printf "CPU: %.0f%%\n", 100*$used/$real if $real > 0;
if ($used > 0.1) {
    my $cps = $scale / $used;
    printf "Cycles-Per-Sec: %.*f\n", ($cps < 100 ? 3 : 0), $cps;
    if (defined $empty_cycles_per_sec) {
	printf "Empty-Cycles-Per-Sec: %.0f\n", $empty_cycles_per_sec;
	$loop_overhead = $scale / $empty_cycles_per_sec;
	$p = 100 * $loop_overhead / $used;
        printf "Loop-Overhead: %.1f%%\n", $p;
	$used -= $loop_overhead;
	print "Adjusted-Used-Time: $used\n";
    }
    printf "Bench-Points: %.5g\n", 1000 / $used if $used > 0;
}
EOT3

    if ($] >= 5.002) {
	$code = <<'EOT' . $code;
BEGIN {
    # If Time::HiRes is available, we can get better resolution
    eval {
        require Time::HiRes;
        Time::HiRes->import('time');
        $hires++;
    };
}

EOT
    }

    print $code if $main'debug;
    eval $code;
    if ($@) {
        die $@;
    }
}

sub time2iso
{
    my $time = shift;
    $time = time unless defined $time;
    my($sec,$min,$hour,$mday,$mon,$year) = localtime($time);
    return sprintf("%04d-%02d-%02d %02d:%02d:%02d",
            $year+1900, $mon+1, $mday, $hour, $min, $sec);
}


1;
