diff -ruN unixbench-5.1.2.orig/Makefile unixbench-5.1.2/Makefile
--- unixbench-5.1.2.orig/Makefile 2007-12-23 04:51:21.000000000 +0900
+++ unixbench-5.1.2/Makefile 2010-01-10 16:11:10.219596811 +0900
@@ -38,6 +38,10 @@
SHELL = /bin/sh
+# GMAKE: Set "GMAKE" to the name of the GNU make to use.
+# You should also set "$gMake" in the Run script.
+GMAKE = make
+
# GRAPHICS TESTS: Uncomment the definition of "GRAPHIC_TESTS" to enable
# the building of the graphics benchmarks. This will require the
# X11 libraries on your system.
@@ -133,7 +137,7 @@
# ####################### a check for Run ######################
check: $(REQD)
- make all
+ $(GMAKE) all
# ##############################################################
# distribute the files out to subdirectories if they are in this one
distr:
diff -ruN unixbench-5.1.2.orig/Run unixbench-5.1.2/Run
--- unixbench-5.1.2.orig/Run 2007-12-23 06:48:10.000000000 +0900
+++ unixbench-5.1.2/Run 2010-01-10 16:10:54.483552885 +0900
@@ -62,7 +62,7 @@
############################################################################
# Version number of the script.
-my $version = "5.1.2";
+my $version = "5.1.2-custom";
# The setting of LANG makes a huge difference to some of the scores,
# particularly depending on whether UTF-8 is used. So we always set
@@ -80,6 +80,16 @@
# C compiler to use in compilation tests.
my $cCompiler = 'gcc';
+# C compiler "version" option to show compiler details.
+my $cCompilerVerOpt = '--version';
+
+# make program for makefile. GNU make is expected.
+# You should also set "GMAKE" in the Makefile.
+my $gMake = 'make';
+
+# Location of /proc/cpuinfo file.
+my $pCpuinfo = "/proc/cpuinfo";
+
# Establish full paths to directories. These need to be full pathnames
# (or do they, any more?). They can be set in env.
# variables whose names are the first parameter to getDir() below.
@@ -671,7 +681,7 @@
# these fields:
# describing the model etc. Returns undef if the information can't be got.
sub getCpuInfo {
- open(my $fd, "<", "/proc/cpuinfo") || return undef;
+ open(my $fd, "<", $pCpuinfo) || return undef;
my $cpus = [ ];
my $cpu = 0;
@@ -713,6 +723,7 @@
# numCpus Number of CPUs if known, else undef.
# load System load message as per "uptime".
# numUsers Number of users and/or open shell sessions.
+# compilerVer Compiler Version
sub getSystemInfo {
my $info = { };
@@ -723,6 +734,7 @@
$info->{'osVer'} = getCmdOutput("uname -v");
$info->{'mach'} = getCmdOutput("uname -m");
$info->{'platform'} = getCmdOutput("uname -i");
+ $info->{'compilerVer'} = getCmdOutput("$cCompiler $cCompilerVerOpt");
# Get the system name (SUSE, Red Hat, etc.) if possible.
$info->{'system'} = $info->{'os'};
@@ -784,11 +796,11 @@
$ENV{'LANG'} = $language;
# Check that the required files are in the proper places.
- system("make check");
+ system("$gMake check");
if ($? != 0) {
- system("make all");
+ system("$gMake all");
if ($? != 0) {
- abortRun("\"make all\" failed");
+ abortRun("\"$gMake all\" failed");
}
}
@@ -1367,6 +1379,7 @@
$info->{'os'}, $info->{'osRel'}, $info->{'osVer'};
printf $fd " Machine: %s (%s)\n", $info->{'mach'}, $info->{'platform'};
printf $fd " Language: %s\n", $info->{'language'};
+ printf $fd " Compiler: %s\n", $info->{'compilerVer'};
# Get and display details on the CPUs, if possible.
my $cpus = $info->{'cpus'};
@@ -1569,6 +1582,10 @@
printf $fd "
Language: | \n";
printf $fd " %s | \n", $info->{'language'};
printf $fd "\n";
+ printf $fd "\n";
+ printf $fd " Compiler: | \n";
+ printf $fd " %s | \n", $info->{'compilerVer'};
+ printf $fd "
\n";
# Get and display details on the CPUs, if possible.
my $cpus = $info->{'cpus'};
diff -ruN unixbench-5.1.2.orig/Run_FreeBSD unixbench-5.1.2/Run_FreeBSD
--- unixbench-5.1.2.orig/Run_FreeBSD 1970-01-01 09:00:00.000000000 +0900
+++ unixbench-5.1.2/Run_FreeBSD 2010-01-10 16:10:09.484287187 +0900
@@ -0,0 +1,1889 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+use POSIX qw(strftime);
+use Time::HiRes;
+use IO::Handle;
+
+
+############################################################################
+# UnixBench - Release 5.1.1, based on:
+# The BYTE UNIX Benchmarks - Release 3
+# Module: Run SID: 3.11 5/15/91 19:30:14
+# Original Byte benchmarks written by:
+# Ben Smith, Tom Yager at BYTE Magazine
+# ben@bytepb.byte.com tyager@bytepb.byte.com
+# BIX: bensmith tyager
+#
+#######################################################################
+# General Purpose Benchmark
+# based on the work by Ken McDonell, Computer Science, Monash University
+#
+# You will need ...
+# perl Time::HiRes IO::Handlecat cc chmod comm cp date dc df echo
+# kill ls make mkdir rm sed test time touch tty umask who
+###############################################################################
+# Modification Log:
+# $Header: run,v 5.2 88/01/12 06:23:43 kenj Exp $
+# Ken McDonell, Computer Science, Monash University
+# August 1, 1983
+# 3/89 - Ben Smith - BYTE: globalized many variables, modernized syntax
+# 5/89 - commented and modernized. Removed workload items till they
+# have been modernized. Added database server test.
+# 11/14/89 - Made modifications to reflect new version of fstime
+# and elimination of mem tests.
+# 10/22/90 - Many tests have been flipped so that they run for
+# a specified length of time and loops are counted.
+# 4/3/91 - Cleaned up and debugged several test parameters - Ben
+# 4/9/91 - Added structure for creating index and determing flavor of UNIX
+# 4/26/91 - Made changes and corrections suggested by Tin Le of Sony
+# 5/15/91 - Removed db from distribution
+# 4/4/92 Jon Tombs fixed for GNU time to look like
+# BSD (don't know the format of sysV!)
+# 12/95 - Massive changes for portability, speed, and more meaningful index
+# DCN David C Niemi
+# 1997.06.20 DCN Fixed overflow condition in fstime.c on fast machines
+# 1997.08.24 DCN Modified "system", replaced double with
+# whetstone-double in "index"
+# 1997.09.10 DCN Added perlbench as an Exhibition benchmark
+# 1997.09.23 DCN Added rgooch's select as an Exhibition benchmark
+# 1999.07.28 DCN "select" not compiled or run by default, because it
+# does not compile on many platforms. PerlBench also
+# not run by default.
+# 2007.09.26 IS Huge rewrite -- see release notes in README.
+# 2007.10.12 IS Added graphics tests, categories feature.
+# 2007.10.14 IS Set and report LANG. Added "grep" and "sysexec".
+# 2007.12.22 IS Tiny fixes; see README.
+
+
+############################################################################
+# CONFIGURATION
+############################################################################
+
+# Version number of the script.
+my $version = "5.1.2-custom";
+
+# The setting of LANG makes a huge difference to some of the scores,
+# particularly depending on whether UTF-8 is used. So we always set
+# it to the same value, which is configured here.
+#
+# If you want your results to be meaningful when compared to other peoples'
+# results, you should not change this. Change it if you want to measure the
+# effect of different languages.
+my $language = "en_US.utf8";
+
+# The number of iterations per test.
+my $longIterCount = 10;
+my $shortIterCount = 3;
+
+# C compiler to use in compilation tests.
+my $cCompiler = 'gcc';
+
+# C compiler "version" option to show compiler details.
+my $cCompilerVerOpt = '--version';
+
+# make program for makefile. GNU make is expected.
+# You should also set "GMAKE" in the Makefile.
+my $gMake = 'gmake';
+
+# Location of /proc/cpuinfo file.
+my $pCpuinfo = "/proc/cpuinfo";
+
+# sysctl to get cpu informations.
+my $Sysctl = "/sbin/sysctl";
+
+# Establish full paths to directories. These need to be full pathnames
+# (or do they, any more?). They can be set in env.
+# variables whose names are the first parameter to getDir() below.
+my $BASEDIR = `pwd`;
+chomp($BASEDIR);
+
+# Directory where the test programs live.
+my $BINDIR = getDir('UB_BINDIR', $BASEDIR . "/pgms");
+
+# Temp directory, for temp files.
+my $TMPDIR = getDir('UB_TMPDIR', $BASEDIR . "/tmp");
+
+# Directory to put results in.
+my $RESULTDIR = getDir('UB_RESULTDIR', $BASEDIR . "/results");
+
+# Directory where the tests are executed.
+my $TESTDIR = getDir('UB_TESTDIR', $BASEDIR . "/testdir");
+
+
+############################################################################
+# TEST SPECIFICATIONS
+############################################################################
+
+# Configure the categories to which tests can belong.
+my $testCats = {
+ 'system' => { 'name' => "System Benchmarks", 'maxCopies' => 16 },
+ '2d' => { 'name' => "2D Graphics Benchmarks", 'maxCopies' => 1 },
+ '3d' => { 'name' => "3D Graphics Benchmarks", 'maxCopies' => 1 },
+ 'misc' => { 'name' => "Non-Index Benchmarks", 'maxCopies' => 16 },
+};
+
+
+my $arithmetic = [
+ "arithoh", "short", "int", "long", "float", "double", "whetstone-double"
+];
+
+my $fs = [
+ "fstime-w", "fstime-r", "fstime",
+ "fsbuffer-w", "fsbuffer-r", "fsbuffer",
+ "fsdisk-w", "fsdisk-r", "fsdisk"
+];
+
+my $oldsystem = [
+ "execl", "fstime", "fsbuffer", "fsdisk", "pipe", "context1", "spawn",
+ "syscall"
+];
+
+my $system = [
+ @$oldsystem, "shell1", "shell8", "shell16"
+];
+
+my $index = [
+ "dhry2reg", "whetstone-double", @$oldsystem, "shell1", "shell8"
+];
+
+my $graphics = [
+ "2d-rects", "2d-ellipse", "2d-aashapes", "2d-text", "2d-blit",
+ "2d-window", "ubgears"
+];
+
+
+# List of all supported test names.
+my $testList = {
+ # Individual tests.
+ "dhry2reg" => undef,
+ "whetstone-double" => undef,
+ "syscall" => undef,
+ "pipe" => undef,
+ "context1" => undef,
+ "spawn" => undef,
+ "execl" => undef,
+ "fstime-w" => undef,
+ "fstime-r" => undef,
+ "fstime" => undef,
+ "fsbuffer-w" => undef,
+ "fsbuffer-r" => undef,
+ "fsbuffer" => undef,
+ "fsdisk-w" => undef,
+ "fsdisk-r" => undef,
+ "fsdisk" => undef,
+ "shell1" => undef,
+ "shell8" => undef,
+ "shell16" => undef,
+ "short" => undef,
+ "int" => undef,
+ "long" => undef,
+ "float" => undef,
+ "double" => undef,
+ "arithoh" => undef,
+ "C" => undef,
+ "dc" => undef,
+ "hanoi" => undef,
+ "grep" => undef,
+ "sysexec" => undef,
+
+ "2d-rects" => undef,
+ "2d-lines" => undef,
+ "2d-circle" => undef,
+ "2d-ellipse" => undef,
+ "2d-shapes" => undef,
+ "2d-aashapes" => undef,
+ "2d-polys" => undef,
+ "2d-text" => undef,
+ "2d-blit" => undef,
+ "2d-window" => undef,
+
+ "ubgears" => undef,
+
+ # Named combos and shorthands.
+ "arithmetic" => $arithmetic,
+ "dhry" => [ "dhry2reg" ],
+ "dhrystone" => [ "dhry2reg" ],
+ "whets" => [ "whetstone-double" ],
+ "whetstone" => [ "whetstone-double" ],
+ "load" => [ "shell" ],
+ "misc" => [ "C", "dc", "hanoi" ],
+ "speed" => [ @$arithmetic, @$system ],
+ "oldsystem" => $oldsystem,
+ "system" => $system,
+ "fs" => $fs,
+ "shell" => [ "shell1", "shell8", "shell16" ],
+ "graphics" => $graphics,
+
+ # The tests which constitute the official index.
+ "index" => $index,
+
+ # The tests which constitute the official index plus the graphics
+ # index.
+ "gindex" => [ @$index, @$graphics ],
+};
+
+
+# Default parameters for benchmarks. Note that if "prog" is used,
+# it must contain just the program name, as it will be quoted (this
+# is necessary if BINDIR contains spaces). Put any options in "options".
+my $baseParams = {
+ "prog" => undef,
+ "options" => "",
+ "repeat" => 'short',
+ "stdout" => 1, # Non-0 to keep stdout.
+ "stdin" => "",
+ "logmsg" => "",
+};
+
+
+# Individual parameters for all benchmarks.
+my $testParams = {
+
+ ##########################
+ ## System Benchmarks ##
+ ##########################
+
+ "dhry2reg" => {
+ "logmsg" => "Dhrystone 2 using register variables",
+ "cat" => 'system',
+ "options" => "10",
+ "repeat" => 'long',
+ },
+ "whetstone-double" => {
+ "logmsg" => "Double-Precision Whetstone",
+ "cat" => 'system',
+ "repeat" => 'long',
+ },
+ "syscall" => {
+ "logmsg" => "System Call Overhead",
+ "cat" => 'system',
+ "repeat" => 'long',
+ "options" => "10",
+ },
+ "context1" => {
+ "logmsg" => "Pipe-based Context Switching",
+ "cat" => 'system',
+ "repeat" => 'long',
+ "options" => "10",
+ },
+ "pipe" => {
+ "logmsg" => "Pipe Throughput",
+ "cat" => 'system',
+ "repeat" => 'long',
+ "options" => "10",
+ },
+ "spawn" => {
+ "logmsg" => "Process Creation",
+ "cat" => 'system',
+ "options" => "30",
+ },
+ "execl" => {
+ "logmsg" => "Execl Throughput",
+ "cat" => 'system',
+ "options" => "30",
+ },
+ "fstime-w" => {
+ "logmsg" => "File Write 1024 bufsize 2000 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-w -t 30 -d \"${TMPDIR}\" -b 1024 -m 2000",
+ },
+ "fstime-r" => {
+ "logmsg" => "File Read 1024 bufsize 2000 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-r -t 30 -d \"${TMPDIR}\" -b 1024 -m 2000",
+ },
+ "fstime" => {
+ "logmsg" => "File Copy 1024 bufsize 2000 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-c -t 30 -d \"${TMPDIR}\" -b 1024 -m 2000",
+ },
+ "fsbuffer-w" => {
+ "logmsg" => "File Write 256 bufsize 500 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-w -t 30 -d \"${TMPDIR}\" -b 256 -m 500",
+ },
+ "fsbuffer-r" => {
+ "logmsg" => "File Read 256 bufsize 500 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-r -t 30 -d \"${TMPDIR}\" -b 256 -m 500",
+ },
+ "fsbuffer" => {
+ "logmsg" => "File Copy 256 bufsize 500 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-c -t 30 -d \"${TMPDIR}\" -b 256 -m 500",
+ },
+ "fsdisk-w" => {
+ "logmsg" => "File Write 4096 bufsize 8000 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-w -t 30 -d \"${TMPDIR}\" -b 4096 -m 8000",
+ },
+ "fsdisk-r" => {
+ "logmsg" => "File Read 4096 bufsize 8000 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-r -t 30 -d \"${TMPDIR}\" -b 4096 -m 8000",
+ },
+ "fsdisk" => {
+ "logmsg" => "File Copy 4096 bufsize 8000 maxblocks",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/fstime",
+ "options" => "-c -t 30 -d \"${TMPDIR}\" -b 4096 -m 8000",
+ },
+ "shell1" => {
+ "logmsg" => "Shell Scripts (1 concurrent)",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/looper",
+ "options" => "60 \"${BINDIR}/multi.sh\" 1",
+ },
+ "shell8" => {
+ "logmsg" => "Shell Scripts (8 concurrent)",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/looper",
+ "options" => "60 \"${BINDIR}/multi.sh\" 8",
+ },
+ "shell16" => {
+ "logmsg" => "Shell Scripts (16 concurrent)",
+ "cat" => 'system',
+ "prog" => "${BINDIR}/looper",
+ "options" => "60 \"${BINDIR}/multi.sh\" 16",
+ },
+
+ ##########################
+ ## Graphics Benchmarks ##
+ ##########################
+
+ "2d-rects" => {
+ "logmsg" => "2D graphics: rectangles",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "rects 3 2",
+ },
+
+ "2d-lines" => {
+ "logmsg" => "2D graphics: lines",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "lines 3 2",
+ },
+
+ "2d-circle" => {
+ "logmsg" => "2D graphics: circles",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "circle 3 2",
+ },
+
+ "2d-ellipse" => {
+ "logmsg" => "2D graphics: ellipses",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "ellipse 3 2",
+ },
+
+ "2d-shapes" => {
+ "logmsg" => "2D graphics: polygons",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "shapes 3 2",
+ },
+
+ "2d-aashapes" => {
+ "logmsg" => "2D graphics: aa polygons",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "aashapes 3 2",
+ },
+
+ "2d-polys" => {
+ "logmsg" => "2D graphics: complex polygons",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "polys 3 2",
+ },
+
+ "2d-text" => {
+ "logmsg" => "2D graphics: text",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "text 3 2",
+ },
+
+ "2d-blit" => {
+ "logmsg" => "2D graphics: images and blits",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "blit 3 2",
+ },
+
+ "2d-window" => {
+ "logmsg" => "2D graphics: windows",
+ "cat" => '2d',
+ "prog" => "${BINDIR}/gfx-x11",
+ "options" => "window 3 2",
+ },
+
+ "ubgears" => {
+ "logmsg" => "3D graphics: gears",
+ "cat" => '3d',
+ "options" => "-time 20 -v",
+ },
+
+
+ ##########################
+ ## Non-Index Benchmarks ##
+ ##########################
+
+ "C" => {
+ "logmsg" => "C Compiler Throughput ($cCompiler)",
+ "cat" => 'misc',
+ "prog" => "${BINDIR}/looper",
+ "options" => "60 $cCompiler cctest.c",
+ },
+ "arithoh" => {
+ "logmsg" => "Arithoh",
+ "cat" => 'misc',
+ "options" => "10",
+ },
+ "short" => {
+ "logmsg" => "Arithmetic Test (short)",
+ "cat" => 'misc',
+ "options" => "10",
+ },
+ "int" => {
+ "logmsg" => "Arithmetic Test (int)",
+ "cat" => 'misc',
+ "options" => "10",
+ },
+ "long" => {
+ "logmsg" => "Arithmetic Test (long)",
+ "cat" => 'misc',
+ "options" => "10",
+ },
+ "float" => {
+ "logmsg" => "Arithmetic Test (float)",
+ "cat" => 'misc',
+ "options" => "10",
+ },
+ "double" => {
+ "logmsg" => "Arithmetic Test (double)",
+ "cat" => 'misc',
+ "options" => "10",
+ },
+ "dc" => {
+ "logmsg" => "Dc: sqrt(2) to 99 decimal places",
+ "cat" => 'misc',
+ "prog" => "${BINDIR}/looper",
+ "options" => "30 dc",
+ "stdin" => "dc.dat",
+ },
+ "hanoi" => {
+ "logmsg" => "Recursion Test -- Tower of Hanoi",
+ "cat" => 'misc',
+ "options" => "20",
+ },
+ "grep" => {
+ "logmsg" => "Grep a large file (system's grep)",
+ "cat" => 'misc',
+ "prog" => "${BINDIR}/looper",
+ "options" => "30 grep -c gimp large.txt",
+ },
+ "sysexec" => {
+ "logmsg" => "Exec System Call Overhead",
+ "cat" => 'misc',
+ "repeat" => 'long',
+ "prog" => "${BINDIR}/syscall",
+ "options" => "10 exec",
+ },
+};
+
+
+# CPU flags of interest.
+my $x86CpuFlags = {
+ 'pae' => "Physical Address Ext",
+ 'sep' => "SYSENTER/SYSEXIT",
+ 'syscall' => "SYSCALL/SYSRET",
+ 'mmx' => "MMX",
+ 'mmxext' => "AMD MMX",
+ 'cxmmx' => "Cyrix MMX",
+ 'xmm' => "Streaming SIMD",
+ 'xmm2' => "Streaming SIMD-2",
+ 'xmm3' => "Streaming SIMD-3",
+ 'ht' => "Hyper-Threading",
+ 'ia64' => "IA-64 processor",
+ 'lm' => "x86-64",
+ 'vmx' => "Intel virtualization",
+ 'svm' => "AMD virtualization",
+};
+
+
+############################################################################
+# UTILITIES
+############################################################################
+
+# Exec the given command, and catch its standard output.
+# We return an array containing the PID and the filehandle on the
+# process' standard output. It's up to the caller to wait for the command
+# to terminate.
+sub command {
+ my ( $cmd ) = @_;
+
+ my $pid = open(my $childFd, "-|");
+ if (!defined($pid)) {
+ die("Run: fork() failed (undef)\n");
+ } elsif ($pid == 0) {
+ exec($cmd);
+ die("Run: exec() failed (returned)\n");
+ }
+
+ return ( $pid, $childFd );
+}
+
+
+# Get data from running a system command. Used for things like getting
+# the host OS from `uname -o` etc.
+#
+# Ignores initial blank lines from the command and returns the first
+# non-blank line, with white space trimmed off. Returns a blank string
+# if there is no output; undef if the command fails.
+sub getCmdOutput {
+ my ( $cmd ) = @_;
+
+ my ( $pid, $fd ) = command($cmd . " 2>/dev/null");
+ my $result = "";
+ while (<$fd>) {
+ chomp;
+ next if /^[ \t]*$/;
+
+ $result = $_;
+ $result =~ s/^[ \t]+//;
+ $result =~ s/[ \t]+$//;
+ last;
+ }
+
+ # Close the command and wait for it to die.
+ waitpid($pid, 0);
+ my $status = $?;
+
+ return $status == 0 ? $result : undef;
+}
+
+
+# Get a directory pathname from an environment variable, or the given
+# default. Canonicalise and return the value.
+sub getDir {
+ my ( $var, $def ) = @_;
+
+ my $val = $ENV{$var} || $def;
+
+ # Canonicalise the value.
+ my $wd;
+ chomp($wd = `pwd`);
+ chdir($val);
+ chomp($val = `pwd`);
+ chdir($wd);
+ $ENV{$var} = $val;
+
+ $val;
+}
+
+
+# Get the name of the file we're going to log to. The name uses the hostname
+# and date, plus a sequence number to make it unique.
+sub logFile {
+ my ( $sysInfo ) = @_;
+
+ my $count = 1;
+
+ # Use the date in the base file name.
+ my $ymd = strftime "%Y-%m-%d", localtime;
+
+ while (1) {
+ my $log = sprintf "%s/%s-%s-%02d",
+ ${RESULTDIR}, $sysInfo->{'name'}, $ymd, $count;
+ return $log if (! -e $log);
+ ++$count;
+ }
+}
+
+
+# Print a message to the named log file. We use this method rather than
+# keeping the FD open because we use shell redirection to send command
+# output to the same file.
+sub printLog {
+ my ( $logFile, @args ) = @_;
+
+ open(my $fd, ">>", $logFile) || abortRun("can't append to $logFile");
+ printf $fd @args;
+ close($fd);
+}
+
+
+# Display a number of something, auto-selecting the plural form
+# if appropriate. We are given the number, the singular, and the
+# plural; if the plural is omitted, it defaults to singular + "s".
+sub number {
+ my ( $n, $what, $plural ) = @_;
+
+ $plural = $what . "s" if !defined($plural);
+
+ if (!defined($n)) {
+ return sprintf "unknown %s", $plural;
+ } else {
+ return sprintf "%d %s", $n, $n == 1 ? $what : $plural;
+ }
+}
+
+
+# Merge two sets of test parameters -- defaults and actual parameters.
+# Return the merged parameter hash.
+sub mergeParams {
+ my ( $def, $vals ) = @_;
+
+ my $params = { };
+ foreach my $k (keys(%$def)) {
+ $params->{$k} = $def->{$k};
+ }
+ foreach my $k (keys(%$vals)) {
+ $params->{$k} = $vals->{$k};
+ }
+
+ $params;
+}
+
+
+############################################################################
+# SYSTEM ANALYSIS
+############################################################################
+
+# Extract interesting flags from the given processor flags string and
+# convert them to descriptive names.
+sub processCpuFlags {
+ my ( $flagStr ) = @_;
+
+ my @names;
+ foreach my $f (sort split(/\s+/, $flagStr)) {
+ my $name = $x86CpuFlags->{$f};
+ push(@names, $name) if $name;
+ }
+
+ join(", ", @names);
+}
+
+
+# Get information on the CPUs in the system. Returns a reference to an
+# array of N entries, one per CPU, where each entry is a hash containing
+# these fields:
+# describing the model etc. Returns undef if the information can't be got.
+sub getCpuInfo {
+ open(my $fd, "<", $pCpuinfo) || return undef;
+
+ my $cpus = [ ];
+ my $cpu = 0;
+ while (<$fd>) {
+ chomp;
+ my ( $field, $val ) = split(/[ \t]*:[ \t]*/);
+ next if (!$field || !$val);
+ if ($field eq "processor") {
+ $cpu = $val;
+ } elsif ($field eq "model name") {
+ my $model = $val;
+ $model =~ s/ +/ /g;
+ $cpus->[$cpu]{'model'} = $model;
+ } elsif ($field eq "bogomips") {
+ $cpus->[$cpu]{'bogo'} = $val;
+ } elsif ($field eq "flags") {
+ $cpus->[$cpu]{'flags'} = processCpuFlags($val);
+ }
+ }
+
+ close($fd);
+
+ $cpus;
+}
+
+# Get information on the CPUs in the system on FreeBSD.
+# Returns a reference to an array of N entries, one per CPU, where each entry is
+# a hash containing these fields:
+# describing the model etc. Returns undef if the information can't be got.
+sub getCpuInfoFreeBSD {
+ my $cpus = [ ];
+ my $numcpu = 0;
+ my $sysctlCpu = getCmdOutput("$Sysctl kern.smp.cpus") ;
+ my $sysctlCpumodel = getCmdOutput("$Sysctl hw.model") ;
+ my $cpuid = 0;
+
+ my ( $field, $val ) = split(/[ \t]*:[ \t]*/, $sysctlCpu);
+ $numcpu = $val;
+
+ for($cpuid=0;$cpuid<$numcpu;$cpuid++){
+ $cpus->[$cpuid]{'model'} = $sysctlCpumodel;
+ $cpus->[$cpuid]{'bogo'} = 0;
+ $cpus->[$cpuid]{'flags'} = "";
+ }
+
+ if ($numcpu == 0) {
+ return undef;
+ }
+
+ $cpus;
+}
+
+# Get information on the host system. Returns a reference to a hash
+# with the following fields:
+# name Host name
+# os Host OS name
+# osRel Host OS release
+# osVer Host OS version
+# mach Host machine name (eg. "SparcStation 20", but on
+# PC/Linux usually "i686" etc.)
+# platform Hardware platform; on Linux, the base CPU type?
+# system System name (eg. hostname and Linux distro, like
+# "hostname: openSUSE 10.2 (i586)").
+# cpus Value returned by getCpuInfo(), undef if not avail.
+# numCpus Number of CPUs if known, else undef.
+# load System load message as per "uptime".
+# numUsers Number of users and/or open shell sessions.
+# compilerVer Compiler Version
+sub getSystemInfo {
+ my $info = { };
+
+ # Get host system data.
+ $info->{'name'} = getCmdOutput("hostname");
+ $info->{'os'} = getCmdOutput("uname -o") || getCmdOutput("uname -s");
+ $info->{'osRel'} = getCmdOutput("uname -r");
+ $info->{'osVer'} = getCmdOutput("uname -v");
+ $info->{'mach'} = getCmdOutput("uname -m");
+ $info->{'platform'} = getCmdOutput("uname -i");
+ $info->{'compilerVer'} = getCmdOutput("$cCompiler $cCompilerVerOpt");
+
+ # Get the system name (SUSE, Red Hat, etc.) if possible.
+ $info->{'system'} = $info->{'os'};
+ if ( -r "/etc/SuSE-release" ) {
+ $info->{'system'} = getCmdOutput("cat /etc/SuSE-release");
+ } elsif ( -r "/etc/release" ) {
+ $info->{'system'} = getCmdOutput("cat /etc/release");
+ }
+
+ # Get the language info.
+ my $lang = getCmdOutput("printenv LANG");
+ my $map = getCmdOutput("locale -k LC_CTYPE | grep charmap");
+ $map =~ s/.*=//;
+ my $coll = getCmdOutput("locale -k LC_COLLATE | grep collate-codeset");
+ $coll =~ s/.*=//;
+ $info->{'language'} = sprintf "%s (charmap=%s, collate=%s)",
+ $lang, $map, $coll;
+
+ # Get details on the CPUs, if possible.
+
+ my $cpus;
+# if (($info->{'os'} =~ /BSD/)&&( -x $Sysctl)){
+ if (($info->{'os'} =~ /FreeBSD/)&&( -x $Sysctl)){
+ $cpus = getCpuInfoFreeBSD();
+ }else{
+ $cpus = getCpuInfo();
+ }
+
+ if (defined($cpus)) {
+ $info->{'cpus'} = $cpus;
+ $info->{'numCpus'} = scalar(@$cpus);
+ }
+
+ # Get graphics hardware info.
+ $info->{'graphics'} = getCmdOutput("3dinfo | cut -f1 -d\'(\'");
+
+ # Get system run state, load and usage info.
+ $info->{'runlevel'} = getCmdOutput("runlevel | cut -f2 -d\" \"");
+ $info->{'load'} = getCmdOutput("uptime");
+ $info->{'numUsers'} = getCmdOutput("who | wc -l");
+
+ $info;
+}
+
+
+############################################################################
+# ERROR HANDLING
+############################################################################
+
+# Abort the benchmarking run with an error message.
+sub abortRun {
+ my ( $err ) = @_;
+
+ printf STDERR "\n**********************************************\n";
+ printf STDERR "Run: %s; aborting\n", $err;
+ exit(1);
+}
+
+
+############################################################################
+# TEST SETUP
+############################################################################
+
+# Do checks that everything's ready for testing.
+sub preChecks {
+ # Set the language.
+ $ENV{'LANG'} = $language;
+
+ # Check that the required files are in the proper places.
+ system("$gMake check");
+ if ($? != 0) {
+ system("$gMake all");
+ if ($? != 0) {
+ abortRun("\"$gMake all\" failed");
+ }
+ }
+
+ # Create a script to kill this run.
+ system("echo \"kill -9 $$\" > \"${TMPDIR}/kill_run\"");
+ chmod(0755, $TMPDIR . "/kill_run");
+}
+
+
+# Parse the command arguments.
+sub parseArgs {
+ my @words = @_;
+
+ # The accumulator for the bench units to be run.
+ my $tests = [ ];
+ my $params = { 'tests' => $tests };
+
+ # Generate the requested list of bench programs.
+ my $opt;
+ my $word;
+ while ($word = shift(@words)) {
+ if ($word !~ m/^-/) { # A test name.
+ if ($word eq "all") {
+ foreach my $t (keys(%$testList)) {
+ push(@$tests, $t) if (!defined($testList->{$t}));
+ }
+ } elsif (exists($testList->{$word})) {
+ my $val = $testList->{$word} || [ $word ];
+ push(@$tests, @$val);
+ } else {
+ die("Run: unknown test \"$word\"\n");
+ }
+ } elsif ($word eq "-q") {
+ $params->{'verbose'} = 0;
+ } elsif ($word eq "-v") {
+ $params->{'verbose'} = 2;
+ } elsif ($word eq "-i") {
+ $params->{'iterations'} = shift(@words);
+ } elsif ($word eq "-c") {
+ if (!defined($params->{'copies'})) {
+ $params->{'copies'} = [ ];
+ }
+ push(@{$params->{'copies'}}, shift(@words));
+ } else {
+ die("Run: unknown option $word\n");
+ }
+ }
+
+ $params;
+}
+
+
+############################################################################
+# RESULTS INPUT / OUTPUT
+############################################################################
+
+# Read a set of benchmarking results from the given file.
+# Returns results in the form returned by runTests(), but without the
+# individual pass results.
+sub readResultsFromFile {
+ my ( $file ) = @_;
+
+ # Attempt to get the baseline data file; if we can't, just return undef.
+ open(my $fd, "<", $file) || return undef;
+
+ my $results = { };
+ while (<$fd>) {
+ chomp;
+
+ # Dump comments, ignore blank lines.
+ s/#.*//;
+ next if /^\s*$/;
+
+ my ( $name, $time, $slab, $sum, $score, $iters ) = split(/\|/);
+ my $bresult = { };
+ $bresult->{'score'} = $score;
+ $bresult->{'scorelabel'} = $slab;
+ $bresult->{'time'} = $time;
+ $bresult->{'iterations'} = $iters;
+
+ $results->{$name} = $bresult;
+ }
+
+ close($fd);
+
+ $results;
+}
+
+
+############################################################################
+# RESULTS PROCESSING
+############################################################################
+
+# Process a set of results from a single test by averaging the individal
+# pass results into a single final value.
+# First, though, dump the worst 1/3 of the scores. The logic is that a
+# glitch in the system (background process waking up, for example) may
+# make one or two runs go slow, so let's discard those.
+#
+# $bresult is a hashed array representing the results of a single test;
+# $bresult->{'passes'} is an array of the output from the individual
+# passes.
+sub combinePassResults {
+ my ( $bench, $tdata, $bresult, $logFile ) = @_;
+
+ $bresult->{'cat'} = $tdata->{'cat'};
+
+ # Computed results.
+ my $iterations = 0;
+ my $totalTime = 0;
+ my $sum = 0;
+ my $product = 0;
+ my $label;
+
+ my $pres = $bresult->{'passes'};
+
+ # We're going to throw away the worst 1/3 of the pass results.
+ # Figure out how many to keep.
+ my $npasses = scalar(@$pres);
+ my $ndump = int($npasses / 3);
+
+ foreach my $presult (sort { $a->{'COUNT0'} <=> $b->{'COUNT0'} } @$pres) {
+ my $count = $presult->{'COUNT0'};
+ my $timebase = $presult->{'COUNT1'};
+ $label = $presult->{'COUNT2'};
+ my $time = $presult->{'TIME'} || $presult->{'elapsed'};
+
+ # Skip this result if it's one of the worst ones.
+ if ($ndump > 0) {
+ printLog($logFile, "*Dump score: %12.1f\n", $count);
+ --$ndump;
+ next;
+ }
+
+ # Count this result.
+ ++$iterations;
+ printLog($logFile, "Count score: %12.1f\n", $count);
+
+ # If $timebase is 0 the figure is a rate; else compute
+ # counts per $timebase. $time is always seconds.
+ if ($timebase > 0) {
+ $sum += $count / ($time / $timebase);
+ $product += log($count) - log($time / $timebase);
+ } else {
+ $sum += $count;
+ $product += log($count);
+ }
+ $totalTime += $time;
+ }
+
+ # Save the results for the benchmark.
+ if ($iterations > 0) {
+ $bresult->{'score'} = exp($product / $iterations);
+ $bresult->{'scorelabel'} = $label;
+ $bresult->{'time'} = $totalTime / $iterations;
+ $bresult->{'iterations'} = $iterations;
+ } else {
+ $bresult->{'error'} = "No measured results";
+ }
+}
+
+
+# Index the given full benchmark results against the baseline results.
+# $results is a hashed array of test names to test results.
+#
+# Adds the following fields to each benchmark result:
+# iscore The baseline score for this test
+# index The index of this test against the baseline
+# Adds the following fields to $results:
+# indexed The number of tests for which index values were
+# generated
+# fullindex Non-0 if all the index tests were indexed
+# index The computed overall index for the run
+# Note that the index values are computed as
+# result / baseline * 10
+# so an index of 523 indicates that a test ran 52.3 times faster than
+# the baseline.
+sub indexResults {
+ my ( $results ) = @_;
+
+ # Read in the baseline result data. If we can't get it, just return
+ # without making indexed results.
+ my $index = readResultsFromFile($BINDIR . "/index.base");
+ if (!defined($index)) {
+ return;
+ }
+
+ # Count the number of results we have (indexed or not) in
+ # each category.
+ my $numCat = { };
+ foreach my $bench (@{$results->{'list'}}) {
+ my $bresult = $results->{$bench};
+ ++$numCat->{$bresult->{'cat'}};
+ }
+ $results->{'numCat'} = $numCat;
+
+ my $numIndex = { };
+ my $indexed = { };
+ my $sum = { };
+ foreach my $bench (sort(keys(%$index))) {
+ # Get the test data for this benchmark.
+ my $tdata = $testParams->{$bench};
+ if (!defined($tdata)) {
+ abortRun("unknown benchmark \"$bench\" in $BINDIR/index.base");
+ }
+
+ # Get the test category. Count the total tests in this cat.
+ my $cat = $tdata->{'cat'};
+ ++$numIndex->{$cat};
+
+ # If we don't have a result for this test, skip.
+ next if (!defined($results->{$bench}));
+
+ # Get the index and actual results. Calcluate the score.
+ my $iresult = $index->{$bench};
+ my $bresult = $results->{$bench};
+ my $ratio = $bresult->{'score'} / $iresult->{'score'};
+
+ # Save the indexed score.
+ $bresult->{'iscore'} = $iresult->{'score'};
+ $bresult->{'index'} = $ratio * 10;
+
+ # Sun the scores, and count this test for this category.
+ $sum->{$cat} += log($ratio);
+ ++$indexed->{$cat};
+ }
+
+ # Calculate the index scores per category.
+ $results->{'indexed'} = $indexed;
+ $results->{'numIndex'} = $numIndex;
+ foreach my $c (keys(%$indexed)) {
+ if ($indexed->{$c} > 0) {
+ $results->{'index'}{$c} = exp($sum->{$c} / $indexed->{$c}) * 10;
+ }
+ }
+}
+
+
+############################################################################
+# TEST EXECUTION
+############################################################################
+
+# Exec the given command in a sub-process.
+#
+# In the child process, we run the command and store its standard output.
+# We also time its execution, and catch its exit status. We then write
+# the command's output, plus lines containing the execution time and status,
+# to a pipe.
+#
+# In the parent process, we immediately return an array containing the
+# child PID and the filehandle to the pipe. This allows the caller to
+# kick off multiple commands in parallel, then gather their output.
+sub commandBuffered {
+ my ( $cmd ) = @_;
+
+ # Create a pipe for parent-child communication.
+ my $childReader;
+ my $parentWriter;
+ pipe($childReader, $parentWriter) || abortRun("pipe() failed");
+ $parentWriter->autoflush(1);
+
+ # Fork off the child process.
+ my $pid = fork();
+ if (!defined($pid)) {
+ abortRun("fork() failed (undef)");
+ } elsif ($pid == 0) {
+ # Close the other end of the pipe.
+ close $childReader;
+
+ # Start the clock and spawn the command.
+ my $benchStart = Time::HiRes::time();
+ my ( $cmdPid, $cmdFd ) = command($cmd);
+
+ # Read and buffer all the command's output.
+ my $output = [ ];
+ while (<$cmdFd>) {
+ push(@$output, $_);
+ }
+
+ # Stop the clock and save the time.
+ my $elTime = Time::HiRes::time() - $benchStart;
+ push(@$output, sprintf "elapsed|%f\n", $elTime);
+
+ # Wait for the child to die so we can get its status.
+ # close($cmdFd); Doesn't work???
+ waitpid($cmdPid, 0);
+ my $status = $?;
+ push(@$output, sprintf "status|%d\n", $status);
+
+ # Now that we've got the time, play back all the output to the pipe.
+ # The parent can read this at its leisure.
+ foreach my $line (@$output) {
+ print $parentWriter $line;
+ }
+
+ # Terminate this child.
+ close $parentWriter;
+ exit(0);
+ }
+
+ # Close the other end of the pipe.
+ close $parentWriter;
+
+ return ( $pid, $childReader );
+}
+
+
+# Read the results of a benchmark execution from a child process, given
+# its process ID and its filehandle. Create a results hash structure
+# containing the fields returned by the child, plus:
+# pid The child's process ID
+# status The child's exit status
+# ERROR Any stderr output from the child that isn't result data
+# Note that ay result fields with ultiple values are split; so eg.
+# COUNT|x|y|x
+# becomes
+# COUNT0 = x
+# COUNT1 = y
+# COUNT2 = z
+sub readResults {
+ my ( $pid, $fd ) = @_;
+
+ my $presult = { 'pid' => $pid };
+
+ # Read all the result lines from the child.
+ while (<$fd>) {
+ chomp;
+
+ my ( $field, @params ) = split(/\|/);
+ if (scalar(@params) == 0) { # Error message.
+ $presult->{'ERROR'} .= "\n" if ($presult->{'ERROR'});
+ $presult->{'ERROR'} .= $field;
+ } elsif (scalar(@params) == 1) { # Simple data.
+ $presult->{$field} = $params[0];
+ } else { # Compound data.
+ # Store the values in separate fields, named "FIELD$i".
+ for (my $x = 0; $x < scalar(@params); ++$x) {
+ $presult->{$field . $x} = $params[$x];
+ }
+ }
+ }
+
+ # If the command had an error, make an appropriate message if we
+ # don't have one.
+ if ($presult->{'status'} != 0 && !defined($presult->{'ERROR'})) {
+ $presult->{'ERROR'} = "command returned status " . $presult->{'status'};
+ }
+
+ # Wait for the child to die.
+ close($fd);
+ waitpid($pid, 0);
+
+ $presult;
+}
+
+
+# Execute a benchmark command. We set off a given number of copies in
+# parallel to exercise multiple CPUs.
+#
+# We return an array of results hashes, one per copy; each one is as
+# returned by readResults().
+sub executeBenchmark {
+ my ( $command, $copies ) = @_;
+
+ # Array of contexts for all the copies we're running.
+ my $ctxt = [ ];
+
+ # Kick off all the commands at once.
+ for (my $i = 0; $i < $copies; ++$i) {
+ my ( $cmdPid, $cmdFd ) = commandBuffered($command);
+ $ctxt->[$i] = {
+ 'pid' => $cmdPid,
+ 'fd' => $cmdFd,
+ };
+ }
+
+ # Now, we can simply read back the command results in order. Because
+ # the child processes read and buffer the results and time the commands,
+ # there's no need to use select() to read the results as they appear.
+ my $pres = [ ];
+ for (my $i = 0; $i < $copies; ++$i) {
+ my $presult = readResults($ctxt->[$i]{'pid'}, $ctxt->[$i]{'fd'});
+ push(@$pres, $presult);
+ }
+
+ $pres;
+}
+
+
+# Run one iteration of a benchmark, as specified by the given
+# benchmark parameters. We run multiple parallel copies as
+# specified by $copies.
+sub runOnePass {
+ my ( $params, $verbose, $logFile, $copies ) = @_;
+
+ # Get the command to run.
+ my $command = $params->{'command'};
+ if ($verbose > 1) {
+ printf "\n";
+ printf "COMMAND: \"%s\"\n", $command;
+ printf "COPIES: \"%d\"\n", $copies;
+ }
+
+ # Remember where we are, and move to the test directory.
+ my $pwd = `pwd`;
+ chdir($TESTDIR);
+
+ # Execute N copies of the benchmark in parallel.
+ my $copyResults = executeBenchmark($command, $copies);
+ printLog($logFile, "\n");
+
+ # Move back home.
+ chdir($pwd);
+
+ # Sum up the scores of the copies.
+ my $count = 0;
+ my $time = 0;
+ my $elap = 0;
+ foreach my $res (@$copyResults) {
+ # Log the result data for each copy.
+ foreach my $k (sort(keys(%$res))) {
+ printLog($logFile, "# %s: %s\n", $k, $res->{$k});
+ }
+ printLog($logFile, "\n");
+
+ # If it failed, bomb out.
+ if (defined($res->{'ERROR'})) {
+ my $name = $params->{'logmsg'};
+ abortRun("\"$name\": " . $res->{'ERROR'});
+ }
+
+ # Count up the score.
+ $count += $res->{'COUNT0'};
+ $time += $res->{'TIME'} || $res->{'elapsed'};
+ $elap += $res->{'elapsed'};
+ }
+
+ # Make up a combined result.
+ my $passResult = $copyResults->[0];
+ $passResult->{'COUNT0'} = $count;
+ $passResult->{'TIME'} = $time / $copies;
+ $passResult->{'elapsed'} = $elap / $copies;
+
+ $passResult;
+}
+
+
+sub runBenchmark {
+ my ( $bench, $tparams, $verbose, $logFile, $copies ) = @_;
+
+ # Make up the actual benchmark parameters.
+ my $params = mergeParams($baseParams, $tparams);
+
+ # Make up the command string based on the parameters.
+ my $prog = $params->{'prog'} || $BINDIR . "/" . $bench;
+ my $command = sprintf "\"%s\" %s", $prog, $params->{'options'};
+ $command .= " < \"" . $params->{'stdin'} . "\"" if ($params->{'stdin'});
+ $command .= " 2>&1";
+ $command .= $params->{'stdout'} ? (" >> \"" . $logFile . "\"") : " > /dev/null";
+ $params->{'command'} = $command;
+
+ # Set up the benchmark results structure.
+ my $bresult = { 'name' => $bench, 'msg' => $params->{'logmsg'} };
+
+ if ($verbose > 0) {
+ printf "\n%d x %s ", $copies, $params->{'logmsg'};
+ }
+
+ printLog($logFile,
+ "\n########################################################\n");
+ printLog($logFile, "%s -- %s\n",
+ $params->{'logmsg'}, number($copies, "copy", "copies"));
+ printLog($logFile, "==> %s\n\n", $command);
+
+ # Run the test iterations, as given by the "repeat" parameter.
+ my $repeats = $shortIterCount;
+ $repeats = $longIterCount if $params->{'repeat'} eq 'long';
+ $repeats = 1 if $params->{'repeat'} eq 'single';
+ my $pres = [ ];
+ for (my $i = 1; $i <= $repeats; ++$i) {
+ printLog($logFile, "#### Pass %d\n\n", $i);
+
+ # make an attempt to flush buffers
+ system("sync; sleep 1; sync; sleep 2");
+ # display heartbeat
+ if ($verbose > 0) {
+ printf " %d", $i;
+ }
+
+ # Execute one pass of the benchmark.
+ my $presult = runOnePass($params, $verbose, $logFile, $copies);
+ push(@$pres, $presult);
+ }
+ $bresult->{'passes'} = $pres;
+
+ # Calculate the averaged results for this benchmark.
+ combinePassResults($bench, $tparams, $bresult, $logFile);
+
+ # Log the results.
+ if ($copies == 1) {
+ printLog($logFile, "\n>>>> Results of 1 copy\n");
+ } else {
+ printLog($logFile, "\n>>>> Sum of %d copies\n", $copies);
+ }
+ foreach my $k ( 'score', 'time', 'iterations' ) {
+ printLog($logFile, ">>>> %s: %s\n", $k, $bresult->{$k});
+ }
+ printLog($logFile, "\n");
+
+ # Some specific cleanup routines.
+ if ($bench eq "C") {
+ unlink(${TESTDIR} . "/cctest.o");
+ unlink(${TESTDIR} . "/a.out");
+ }
+
+ if ($verbose > 0) {
+ printf "\n";
+ }
+
+ $bresult;
+}
+
+
+# Run the named benchmarks.
+sub runTests {
+ my ( $tests, $verbose, $logFile, $copies ) = @_;
+
+ # Run all the requested tests and gather the results.
+ my $results = { 'start' => time(), 'copies' => $copies };
+ foreach my $bench (@$tests) {
+ # Get the parameters for this benchmark.
+ my $params = $testParams->{$bench};
+ if (!defined($params)) {
+ abortRun("unknown benchmark \"$bench\"");
+ }
+
+ # If the benchmark doesn't want to run with this many copies, skip it.
+ my $cat = $params->{'cat'};
+ my $maxCopies = $testCats->{$cat}{'maxCopies'};
+ next if ($copies > $maxCopies);
+
+ # Run the benchmark.
+ my $bresult = runBenchmark($bench, $params, $verbose, $logFile, $copies);
+ $results->{$bench} = $bresult;
+ }
+ $results->{'end'} = time();
+
+ # Generate a sorted list of benchmarks for which we have results.
+ my @benches = grep {
+ ref($results->{$_}) eq "HASH" && defined($results->{$_}{'msg'})
+ } keys(%$results);
+ @benches = sort {
+ $results->{$a}{'msg'} cmp $results->{$b}{'msg'}
+ } @benches;
+ $results->{'list'} = \@benches;
+
+ # Generate index scores for the results relative to the baseline data.
+ indexResults($results);
+
+ $results;
+}
+
+
+############################################################################
+# TEXT REPORTS
+############################################################################
+
+# Display a banner indicating the configuration of the system under test
+# to the given file desc.
+sub displaySystem {
+ my ( $info, $fd ) = @_;
+
+ # Display basic system info.
+ printf $fd " System: %s: %s\n", $info->{'name'}, $info->{'system'};
+ printf $fd " OS: %s -- %s -- %s\n",
+ $info->{'os'}, $info->{'osRel'}, $info->{'osVer'};
+ printf $fd " Machine: %s (%s)\n", $info->{'mach'}, $info->{'platform'};
+ printf $fd " Language: %s\n", $info->{'language'};
+ printf $fd " Compiler: %s\n", $info->{'compilerVer'};
+
+ # Get and display details on the CPUs, if possible.
+ my $cpus = $info->{'cpus'};
+ if (!defined($cpus)) {
+ printf $fd " CPU: no details available\n";
+ } else {
+ for (my $i = 0; $i <= $#$cpus; ++$i) {
+ printf $fd " CPU %d: %s (%.1f bogomips)\n",
+ $i, $cpus->[$i]{'model'}, $cpus->[$i]{'bogo'};
+ printf $fd " %s\n", $cpus->[$i]{'flags'};
+ }
+ }
+
+ if ($info->{'graphics'}) {
+ printf $fd " Graphics: %s\n", $info->{'graphics'};
+ }
+
+ # Display system load and usage info.
+ printf $fd " %s; runlevel %s\n\n", $info->{'load'}, $info->{'runlevel'};
+}
+
+
+# Display the test scores from the given set of test results.
+sub logResults {
+ my ( $results, $outFd ) = @_;
+
+ # Display the individual test scores.
+ foreach my $bench (@{$results->{'list'}}) {
+ my $bresult = $results->{$bench};
+
+ printf $outFd "%-40s %12.1f %-5s (%.1f s, %d samples)\n",
+ $bresult->{'msg'},
+ $bresult->{'score'},
+ $bresult->{'scorelabel'},
+ $bresult->{'time'},
+ $bresult->{'iterations'};
+ }
+
+ printf $outFd "\n";
+}
+
+
+# Display index scores, if any, for the given run results.
+sub logIndexCat {
+ my ( $results, $cat, $outFd ) = @_;
+
+ my $total = $results->{'numIndex'}{$cat};
+ my $indexed = $results->{'indexed'}{$cat};
+ my $iscore = $results->{'index'}{$cat};
+ my $full = $total == $indexed;
+
+ # If there are no indexed scores, just say so.
+ if (!defined($indexed) || $indexed == 0) {
+ printf $outFd "No index results available for %s\n\n",
+ $testCats->{$cat}{'name'};
+ return;
+ }
+
+ # Display the header, depending on whether we have a full set of index
+ # scores, or a partial set.
+ my $head = $testCats->{$cat}{'name'} .
+ ($full ? " Index Values" : " Partial Index");
+ printf $outFd "%-40s %12s %12s %8s\n",
+ $head, "BASELINE", "RESULT", "INDEX";
+
+ # Display the individual test scores.
+ foreach my $bench (@{$results->{'list'}}) {
+ my $bresult = $results->{$bench};
+ next if $bresult->{'cat'} ne $cat;
+
+ if (defined($bresult->{'iscore'}) && defined($bresult->{'index'})) {
+ printf $outFd "%-40s %12.1f %12.1f %8.1f\n",
+ $bresult->{'msg'}, $bresult->{'iscore'},
+ $bresult->{'score'}, $bresult->{'index'};
+ } else {
+ printf $outFd "%-40s %12s %12.1f %8s\n",
+ $bresult->{'msg'}, "---",
+ $bresult->{'score'}, "---";
+ }
+ }
+
+ # Display the overall score.
+ my $title = $testCats->{$cat}{'name'} . " Index Score";
+ if (!$full) {
+ $title .= " (Partial Only)";
+ }
+ printf $outFd "%-40s %12s %12s %8s\n", "", "", "", "========";
+ printf $outFd "%-66s %8.1f\n", $title, $iscore;
+
+ printf $outFd "\n";
+}
+
+
+# Display index scores, if any, for the given run results.
+sub logIndex {
+ my ( $results, $outFd ) = @_;
+
+ my $count = $results->{'indexed'};
+ foreach my $cat (keys(%$count)) {
+ logIndexCat($results, $cat, $outFd);
+ }
+}
+
+
+# Dump the given run results into the given report file.
+sub summarizeRun {
+ my ( $systemInfo, $results, $verbose, $reportFd ) = @_;
+
+ # Display information about this test run.
+ printf $reportFd "------------------------------------------------------------------------\n";
+ printf $reportFd "Benchmark Run: %s %s - %s\n",
+ strftime("%a %b %d %Y", localtime($results->{'start'})),
+ strftime("%H:%M:%S", localtime($results->{'start'})),
+ strftime("%H:%M:%S", localtime($results->{'end'}));
+ printf $reportFd "%s in system; running %s of tests\n",
+ number($systemInfo->{'numCpus'}, "CPU"),
+ number($results->{'copies'}, "parallel copy", "parallel copies");
+ printf $reportFd "\n";
+
+ # Display the run scores.
+ logResults($results, $reportFd);
+
+ # Display the indexed scores, if any.
+ logIndex($results, $reportFd);
+}
+
+
+############################################################################
+# HTML REPORTS
+############################################################################
+
+# Dump the given run results into the given report file.
+sub runHeaderHtml {
+ my ( $systemInfo, $reportFd ) = @_;
+
+ # Display information about this test run.
+ my $title = sprintf "Benchmark of %s / %s on %s",
+ $systemInfo->{'name'}, $systemInfo->{'system'},
+ strftime("%a %b %d %Y", localtime());
+
+ print $reportFd <
+
+
+
+
+ $title
+
+
+
+EOF
+
+ # Display information about this test run.
+ printf $reportFd "%s
\n", $title;
+ printf $reportFd "BYTE UNIX Benchmarks (Version %s)
\n\n",
+ $version;
+}
+
+
+# Display a banner indicating the configuration of the system under test
+# to the given file desc.
+sub displaySystemHtml {
+ my ( $info, $fd ) = @_;
+
+ printf $fd "Test System Information
\n";
+ printf $fd "\n";
+
+ # Display basic system info.
+ printf $fd "\n";
+ printf $fd " System: | \n";
+ printf $fd " %s: %s | \n",
+ $info->{'name'}, $info->{'system'};
+ printf $fd "
\n";
+ printf $fd " OS: | \n";
+ printf $fd " %s -- %s -- %s | \n",
+ $info->{'os'}, $info->{'osRel'}, $info->{'osVer'};
+ printf $fd "
\n";
+ printf $fd " Machine: | \n";
+ printf $fd " %s: %s | \n",
+ $info->{'mach'}, $info->{'platform'};
+ printf $fd "
\n";
+ printf $fd " Language: | \n";
+ printf $fd " %s | \n", $info->{'language'};
+ printf $fd "
\n";
+ printf $fd "\n";
+ printf $fd " Compiler: | \n";
+ printf $fd " %s | \n", $info->{'compilerVer'};
+ printf $fd "
\n";
+
+ # Get and display details on the CPUs, if possible.
+ my $cpus = $info->{'cpus'};
+ if (!defined($cpus)) {
+ printf $fd "\n";
+ printf $fd " CPUs: | \n";
+ printf $fd " no details available | \n";
+ printf $fd "
\n";
+ } else {
+ for (my $i = 0; $i <= $#$cpus; ++$i) {
+ printf $fd "\n";
+ if ($i == 0) {
+ printf $fd " CPUs: | \n", $#$cpus + 1;
+ }
+ printf $fd " %d: | \n", $i;
+ printf $fd " %s (%.1f bogomips) \n",
+ $cpus->[$i]{'model'}, $cpus->[$i]{'bogo'};
+ printf $fd " %s | \n", $cpus->[$i]{'flags'};
+ printf $fd "
\n";
+ }
+ }
+
+ # Display graphics hardware info.
+ if ($info->{'graphics'}) {
+ printf $fd "\n";
+ printf $fd " Graphics: | \n";
+ printf $fd " %s | \n", $info->{'graphics'};
+ printf $fd "
\n";
+ }
+
+ # Display system runlevel, load and usage info.
+ printf $fd "\n";
+ printf $fd " Uptime: | \n";
+ printf $fd " %s; runlevel %s | \n",
+ $info->{'load'}, $info->{'runlevel'};
+ printf $fd "
\n";
+
+ printf $fd "
\n\n";
+}
+
+
+# Display the test scores from the given set of test results
+# for a given category of tests.
+sub logCatResultsHtml {
+ my ( $results, $cat, $fd ) = @_;
+
+ my $numIndex = $results->{'numIndex'}{$cat};
+ my $indexed = $results->{'indexed'}{$cat};
+ my $iscore = $results->{'index'}{$cat};
+ my $full = defined($indexed) && $indexed == $numIndex;
+
+ # If there are no results in this category, just ignore it.
+ if (!defined($results->{'numCat'}{$cat}) ||
+ $results->{'numCat'}{$cat} == 0) {
+ return;
+ }
+
+ # Say the category. If there are no indexed scores, just say so.
+ my $warn = "";
+ if (!defined($indexed) || $indexed == 0) {
+ $warn = " — no index results available";
+ } elsif (!$full) {
+ $warn = " — not all index tests were run;" .
+ " only a partial index score is available";
+ }
+ printf $fd "%s%s
\n", $testCats->{$cat}{'name'}, $warn;
+
+ printf $fd "\n";
+
+ printf $fd "\n";
+ printf $fd " Test | \n";
+ printf $fd " Score | \n";
+ printf $fd " Unit | \n";
+ printf $fd " Time | \n";
+ printf $fd " Iters. | \n";
+ printf $fd " Baseline | \n";
+ printf $fd " Index | \n";
+ printf $fd "
\n";
+
+ # Display the individual test scores.
+ foreach my $bench (@{$results->{'list'}}) {
+ my $bresult = $results->{$bench};
+ next if $bresult->{'cat'} ne $cat;
+
+ printf $fd "\n";
+ printf $fd " %s | \n", $bresult->{'msg'};
+ printf $fd " %.1f | \n",
+ $bresult->{'score'};
+ printf $fd " %s | \n",
+ $bresult->{'scorelabel'};
+ printf $fd " %.1f s | \n",
+ $bresult->{'time'};
+ printf $fd " %d | \n",
+ $bresult->{'iterations'};
+
+ if (defined($bresult->{'index'})) {
+ printf $fd " %.1f | \n",
+ $bresult->{'iscore'};
+ printf $fd " %.1f | \n",
+ $bresult->{'index'};
+ }
+ printf $fd "
\n";
+ }
+
+ # Display the overall score.
+ if (defined($indexed) && $indexed > 0) {
+ my $title = $testCats->{$cat}{'name'} . " Index Score";
+ if (!$full) {
+ $title .= " (Partial Only)";
+ }
+ printf $fd "\n";
+ printf $fd " %s: | \n", $title;
+ printf $fd " %.1f | \n", $iscore;
+ printf $fd "
\n";
+ }
+
+ printf $fd "
\n\n";
+}
+
+
+# Display index scores, if any, for the given run results.
+sub logResultsHtml {
+ my ( $results, $fd ) = @_;
+
+ foreach my $cat (keys(%$testCats)) {
+ logCatResultsHtml($results, $cat, $fd);
+ }
+}
+
+
+# Dump the given run results into the given report file.
+sub summarizeRunHtml {
+ my ( $systemInfo, $results, $verbose, $reportFd ) = @_;
+
+ # Display information about this test run.
+ my $time = $results->{'end'} - $results->{'start'};
+ printf $reportFd "
\n";
+ printf $reportFd "Benchmark Run: %s; %s
\n",
+ number($systemInfo->{'numCpus'}, "CPU"),
+ number($results->{'copies'}, "parallel process", "parallel processes");
+ printf $reportFd "Time: %s - %s; %dm %02ds
\n",
+ strftime("%H:%M:%S", localtime($results->{'start'})),
+ strftime("%H:%M:%S", localtime($results->{'end'})),
+ int($time / 60), $time % 60;
+ printf $reportFd "\n";
+
+ # Display the run scores.
+ logResultsHtml($results, $reportFd);
+}
+
+
+sub runFooterHtml {
+ my ( $reportFd ) = @_;
+
+ print $reportFd <
+No Warranties: This information is provided free of charge and "as
+is" without any warranty, condition, or representation of any kind,
+either express or implied, including but not limited to, any warranty
+respecting non-infringement, and the implied warranties of conditions
+of merchantability and fitness for a particular purpose. All logos or
+trademarks on this site are the property of their respective owner. In
+no event shall the author be liable for any
+direct, indirect, special, incidental, consequential or other damages
+howsoever caused whether arising in contract, tort, or otherwise,
+arising out of or in connection with the use or performance of the
+information contained on this web site.
+
+
+EOF
+}
+
+
+############################################################################
+# MAIN
+############################################################################
+
+sub main {
+ my @args = @_;
+
+ my $params = parseArgs(@args);
+ my $verbose = $params->{'verbose'} || 1;
+ if ($params->{'iterations'}) {
+ $longIterCount = $params->{'iterations'};
+ $shortIterCount = int(($params->{'iterations'} + 1) / 3);
+ $shortIterCount = 1 if ($shortIterCount < 1);
+ }
+
+ # If no benchmark units have be specified, do "index".
+ my $tests = $params->{'tests'};
+ if ($#$tests < 0) {
+ $tests = $index;
+ }
+
+ preChecks();
+ my $systemInfo = getSystemInfo();
+
+ # If the number of copies to run was not set, set it to 1
+ # and the number of CPUs in the system (if > 1).
+ my $copies = $params->{'copies'};
+ if (!$copies || scalar(@$copies) == 0) {
+ push(@$copies, 1);
+ if (defined($systemInfo->{'numCpus'}) && $systemInfo->{'numCpus'} > 1) {
+ push(@$copies, $systemInfo->{'numCpus'});
+ }
+ }
+
+ # Display the program banner.
+ system("cat \"${BINDIR}/unixbench.logo\"");
+
+ if ($verbose > 1) {
+ printf "\n", join(", ", @$tests);
+ printf "Tests to run: %s\n", join(", ", @$tests);
+ }
+
+ # Generate unique file names for the report and log file.
+ my $reportFile = logFile($systemInfo);
+ my $reportHtml = $reportFile . ".html";
+ my $logFile = $reportFile . ".log";
+
+ # Open the log file for writing.
+ open(my $reportFd, ">", $reportFile) ||
+ die("Run: can't write to $reportFile\n");
+ open(my $reportFd2, ">", $reportHtml) ||
+ die("Run: can't write to $reportHtml\n");
+ printf $reportFd " BYTE UNIX Benchmarks (Version %s)\n\n", $version;
+ runHeaderHtml($systemInfo, $reportFd2);
+
+ # Dump information about the system under test.
+ displaySystem($systemInfo, $reportFd);
+ displaySystemHtml($systemInfo, $reportFd2);
+
+ # Run the tests! Do a test run once for each desired number of copies;
+ # for example, on a 2-CPU system, we may do a single-processing run
+ # followed by a dual-processing run.
+ foreach my $c (@$copies) {
+ if ($verbose > 1) {
+ printf "Run with %s\n", number($c, "copy", "copies");
+ }
+ my $results = runTests($tests, $verbose, $logFile, $c);
+
+ summarizeRun($systemInfo, $results, $verbose, $reportFd);
+ summarizeRunHtml($systemInfo, $results, $verbose, $reportFd2);
+ }
+
+ runFooterHtml($reportFd2);
+
+ # Finish the report.
+ close($reportFd);
+ close($reportFd2);
+
+ # Display the report, if not in quiet mode.
+ if ($verbose > 0) {
+ printf "\n";
+ printf "========================================================================\n";
+ system("cat \"$reportFile\"");
+ }
+
+ 0;
+}
+
+
+exit(main(@ARGV));
+