5 use POSIX
qw(strftime);
10 ############################################################################
11 # UnixBench - Release 5.1.1, based on:
12 # The BYTE UNIX Benchmarks - Release 3
13 # Module: Run SID: 3.11 5/15/91 19:30:14
14 # Original Byte benchmarks written by:
15 # Ben Smith, Tom Yager at BYTE Magazine
16 # ben@bytepb.byte.com tyager@bytepb.byte.com
17 # BIX: bensmith tyager
19 #######################################################################
20 # General Purpose Benchmark
21 # based on the work by Ken McDonell, Computer Science, Monash University
24 # perl Time::HiRes IO::Handlecat cc chmod comm cp date dc df echo
25 # kill ls make mkdir rm sed test time touch tty umask who
26 ###############################################################################
28 # $Header: run,v 5.2 88/01/12 06:23:43 kenj Exp $
29 # Ken McDonell, Computer Science, Monash University
31 # 3/89 - Ben Smith - BYTE: globalized many variables, modernized syntax
32 # 5/89 - commented and modernized. Removed workload items till they
33 # have been modernized. Added database server test.
34 # 11/14/89 - Made modifications to reflect new version of fstime
35 # and elimination of mem tests.
36 # 10/22/90 - Many tests have been flipped so that they run for
37 # a specified length of time and loops are counted.
38 # 4/3/91 - Cleaned up and debugged several test parameters - Ben
39 # 4/9/91 - Added structure for creating index and determing flavor of UNIX
40 # 4/26/91 - Made changes and corrections suggested by Tin Le of Sony
41 # 5/15/91 - Removed db from distribution
42 # 4/4/92 Jon Tombs <jon@robots.ox.ac.uk> fixed for GNU time to look like
43 # BSD (don't know the format of sysV!)
44 # 12/95 - Massive changes for portability, speed, and more meaningful index
45 # DCN David C Niemi <niemi@tux.org>
46 # 1997.06.20 DCN Fixed overflow condition in fstime.c on fast machines
47 # 1997.08.24 DCN Modified "system", replaced double with
48 # whetstone-double in "index"
49 # 1997.09.10 DCN Added perlbench as an Exhibition benchmark
50 # 1997.09.23 DCN Added rgooch's select as an Exhibition benchmark
51 # 1999.07.28 DCN "select" not compiled or run by default, because it
52 # does not compile on many platforms. PerlBench also
54 # 2007.09.26 IS Huge rewrite -- see release notes in README.
55 # 2007.10.12 IS Added graphics tests, categories feature.
56 # 2007.10.14 IS Set and report LANG. Added "grep" and "sysexec".
57 # 2007.12.22 IS Tiny fixes; see README.
60 ############################################################################
62 ############################################################################
64 # Version number of the script.
65 my $version = "5.1.2";
67 # The setting of LANG makes a huge difference to some of the scores,
68 # particularly depending on whether UTF-8 is used. So we always set
69 # it to the same value, which is configured here.
71 # If you want your results to be meaningful when compared to other peoples'
72 # results, you should not change this. Change it if you want to measure the
73 # effect of different languages.
74 my $language = "en_US.utf8";
76 # The number of iterations per test.
77 my $longIterCount = 10;
78 my $shortIterCount = 3;
80 # C compiler to use in compilation tests.
81 my $cCompiler = $ENV{CC
};
83 # Establish full paths to directories. These need to be full pathnames
84 # (or do they, any more?). They can be set in env.
85 # variables whose names are the first parameter to getDir() below.
89 # Directory where the test programs live.
90 my $BINDIR = getDir
('UB_BINDIR', $BASEDIR . "/pgms");
92 # Temp directory, for temp files.
93 my $TMPDIR = getDir
('UB_TMPDIR', $BASEDIR . "/tmp");
95 # Directory to put results in.
96 my $RESULTDIR = getDir
('UB_RESULTDIR', $BASEDIR . "/results");
98 # Directory where the tests are executed.
99 my $TESTDIR = getDir
('UB_TESTDIR', $BASEDIR . "/testdir");
102 ############################################################################
103 # TEST SPECIFICATIONS
104 ############################################################################
106 # Configure the categories to which tests can belong.
108 'system' => { 'name' => "System Benchmarks", 'maxCopies' => 16 },
109 '2d' => { 'name' => "2D Graphics Benchmarks", 'maxCopies' => 1 },
110 '3d' => { 'name' => "3D Graphics Benchmarks", 'maxCopies' => 1 },
111 'misc' => { 'name' => "Non-Index Benchmarks", 'maxCopies' => 16 },
116 "arithoh", "short", "int", "long", "float", "double", "whetstone-double"
120 "fstime-w", "fstime-r", "fstime",
121 "fsbuffer-w", "fsbuffer-r", "fsbuffer",
122 "fsdisk-w", "fsdisk-r", "fsdisk"
126 "execl", "fstime", "fsbuffer", "fsdisk", "pipe", "context1", "spawn",
131 @
$oldsystem, "shell1", "shell8" # , "shell16"
135 "dhry2reg", "whetstone-double", @
$oldsystem, "shell1", "shell8"
139 "2d-rects", "2d-ellipse", "2d-aashapes", "2d-text", "2d-blit",
140 "2d-window", "ubgears"
144 # List of all supported test names.
148 "whetstone-double" => undef,
157 "fsbuffer-w" => undef,
158 "fsbuffer-r" => undef,
180 "2d-circle" => undef,
181 "2d-ellipse" => undef,
182 "2d-shapes" => undef,
183 "2d-aashapes" => undef,
187 "2d-window" => undef,
191 # Named combos and shorthands.
192 "arithmetic" => $arithmetic,
193 "dhry" => [ "dhry2reg" ],
194 "dhrystone" => [ "dhry2reg" ],
195 "whets" => [ "whetstone-double" ],
196 "whetstone" => [ "whetstone-double" ],
197 "load" => [ "shell" ],
198 "misc" => [ "C", "dc", "hanoi" ],
199 "speed" => [ @
$arithmetic, @
$system ],
200 "oldsystem" => $oldsystem,
203 "shell" => [ "shell1", "shell8" ],
204 "graphics" => $graphics,
206 # The tests which constitute the official index.
209 # The tests which constitute the official index plus the graphics
211 "gindex" => [ @
$index, @
$graphics ],
215 # Default parameters for benchmarks. Note that if "prog" is used,
216 # it must contain just the program name, as it will be quoted (this
217 # is necessary if BINDIR contains spaces). Put any options in "options".
222 "stdout" => 1, # Non-0 to keep stdout.
228 # Individual parameters for all benchmarks.
231 ##########################
232 ## System Benchmarks ##
233 ##########################
236 "logmsg" => "Dhrystone 2 using register variables",
241 "whetstone-double" => {
242 "logmsg" => "Double-Precision Whetstone",
247 "logmsg" => "System Call Overhead",
253 "logmsg" => "Pipe-based Context Switching",
259 "logmsg" => "Pipe Throughput",
265 "logmsg" => "Process Creation",
270 "logmsg" => "Execl Throughput",
275 "logmsg" => "File Write 1024 bufsize 2000 maxblocks",
277 "prog" => "${BINDIR}/fstime",
278 "options" => "-w -t 30 -d \"${TMPDIR}\" -b 1024 -m 2000",
281 "logmsg" => "File Read 1024 bufsize 2000 maxblocks",
283 "prog" => "${BINDIR}/fstime",
284 "options" => "-r -t 30 -d \"${TMPDIR}\" -b 1024 -m 2000",
287 "logmsg" => "File Copy 1024 bufsize 2000 maxblocks",
289 "prog" => "${BINDIR}/fstime",
290 "options" => "-c -t 30 -d \"${TMPDIR}\" -b 1024 -m 2000",
293 "logmsg" => "File Write 256 bufsize 500 maxblocks",
295 "prog" => "${BINDIR}/fstime",
296 "options" => "-w -t 30 -d \"${TMPDIR}\" -b 256 -m 500",
299 "logmsg" => "File Read 256 bufsize 500 maxblocks",
301 "prog" => "${BINDIR}/fstime",
302 "options" => "-r -t 30 -d \"${TMPDIR}\" -b 256 -m 500",
305 "logmsg" => "File Copy 256 bufsize 500 maxblocks",
307 "prog" => "${BINDIR}/fstime",
308 "options" => "-c -t 30 -d \"${TMPDIR}\" -b 256 -m 500",
311 "logmsg" => "File Write 4096 bufsize 8000 maxblocks",
313 "prog" => "${BINDIR}/fstime",
314 "options" => "-w -t 30 -d \"${TMPDIR}\" -b 4096 -m 8000",
317 "logmsg" => "File Read 4096 bufsize 8000 maxblocks",
319 "prog" => "${BINDIR}/fstime",
320 "options" => "-r -t 30 -d \"${TMPDIR}\" -b 4096 -m 8000",
323 "logmsg" => "File Copy 4096 bufsize 8000 maxblocks",
325 "prog" => "${BINDIR}/fstime",
326 "options" => "-c -t 30 -d \"${TMPDIR}\" -b 4096 -m 8000",
329 "logmsg" => "Shell Scripts (1 concurrent)",
331 "prog" => "${BINDIR}/looper",
332 "options" => "60 \"${BINDIR}/multi.sh\" 1",
335 "logmsg" => "Shell Scripts (8 concurrent)",
337 "prog" => "${BINDIR}/looper",
338 "options" => "60 \"${BINDIR}/multi.sh\" 8",
341 "logmsg" => "Shell Scripts (16 concurrent)",
343 "prog" => "${BINDIR}/looper",
344 "options" => "60 \"${BINDIR}/multi.sh\" 16",
347 ##########################
348 ## Graphics Benchmarks ##
349 ##########################
352 "logmsg" => "2D graphics: rectangles",
354 "prog" => "${BINDIR}/gfx-x11",
355 "options" => "rects 3 2",
359 "logmsg" => "2D graphics: lines",
361 "prog" => "${BINDIR}/gfx-x11",
362 "options" => "lines 3 2",
366 "logmsg" => "2D graphics: circles",
368 "prog" => "${BINDIR}/gfx-x11",
369 "options" => "circle 3 2",
373 "logmsg" => "2D graphics: ellipses",
375 "prog" => "${BINDIR}/gfx-x11",
376 "options" => "ellipse 3 2",
380 "logmsg" => "2D graphics: polygons",
382 "prog" => "${BINDIR}/gfx-x11",
383 "options" => "shapes 3 2",
387 "logmsg" => "2D graphics: aa polygons",
389 "prog" => "${BINDIR}/gfx-x11",
390 "options" => "aashapes 3 2",
394 "logmsg" => "2D graphics: complex polygons",
396 "prog" => "${BINDIR}/gfx-x11",
397 "options" => "polys 3 2",
401 "logmsg" => "2D graphics: text",
403 "prog" => "${BINDIR}/gfx-x11",
404 "options" => "text 3 2",
408 "logmsg" => "2D graphics: images and blits",
410 "prog" => "${BINDIR}/gfx-x11",
411 "options" => "blit 3 2",
415 "logmsg" => "2D graphics: windows",
417 "prog" => "${BINDIR}/gfx-x11",
418 "options" => "window 3 2",
422 "logmsg" => "3D graphics: gears",
424 "options" => "-time 20 -v",
428 ##########################
429 ## Non-Index Benchmarks ##
430 ##########################
433 "logmsg" => "C Compiler Throughput ($cCompiler)",
435 "prog" => "${BINDIR}/looper",
436 "options" => "60 $cCompiler cctest.c",
439 "logmsg" => "Arithoh",
444 "logmsg" => "Arithmetic Test (short)",
449 "logmsg" => "Arithmetic Test (int)",
454 "logmsg" => "Arithmetic Test (long)",
459 "logmsg" => "Arithmetic Test (float)",
464 "logmsg" => "Arithmetic Test (double)",
469 "logmsg" => "Dc: sqrt(2) to 99 decimal places",
471 "prog" => "${BINDIR}/looper",
472 "options" => "30 dc",
476 "logmsg" => "Recursion Test -- Tower of Hanoi",
481 "logmsg" => "Grep a large file (system's grep)",
483 "prog" => "${BINDIR}/looper",
484 "options" => "30 grep -c gimp large.txt",
487 "logmsg" => "Exec System Call Overhead",
490 "prog" => "${BINDIR}/syscall",
491 "options" => "10 exec",
496 # CPU flags of interest.
498 'pae' => "Physical Address Ext",
499 'sep' => "SYSENTER/SYSEXIT",
500 'syscall' => "SYSCALL/SYSRET",
502 'mmxext' => "AMD MMX",
503 'cxmmx' => "Cyrix MMX",
504 'xmm' => "Streaming SIMD",
505 'xmm2' => "Streaming SIMD-2",
506 'xmm3' => "Streaming SIMD-3",
507 'ht' => "Hyper-Threading",
508 'ia64' => "IA-64 processor",
510 'vmx' => "Intel virtualization",
511 'svm' => "AMD virtualization",
515 ############################################################################
517 ############################################################################
519 # Exec the given command, and catch its standard output.
520 # We return an array containing the PID and the filehandle on the
521 # process' standard output. It's up to the caller to wait for the command
526 my $pid = open(my $childFd, "-|");
527 if (!defined($pid)) {
528 die("Run: fork() failed (undef)\n");
529 } elsif ($pid == 0) {
531 die("Run: exec() failed (returned)\n");
534 return ( $pid, $childFd );
538 # Get data from running a system command. Used for things like getting
539 # the host OS from `uname -o` etc.
541 # Ignores initial blank lines from the command and returns the first
542 # non-blank line, with white space trimmed off. Returns a blank string
543 # if there is no output; undef if the command fails.
547 my ( $pid, $fd ) = command
($cmd . " 2>/dev/null");
554 $result =~ s/^[ \t]+//;
555 $result =~ s/[ \t]+$//;
559 # Close the command and wait for it to die.
563 return $status == 0 ?
$result : undef;
567 # Get a directory pathname from an environment variable, or the given
568 # default. Canonicalise and return the value.
570 my ( $var, $def ) = @_;
572 my $val = $ENV{$var} || $def;
574 # Canonicalise the value.
586 # Get the name of the file we're going to log to. The name uses the hostname
587 # and date, plus a sequence number to make it unique.
589 my ( $sysInfo ) = @_;
593 # Use the date in the base file name.
594 my $ymd = strftime
"%Y-%m-%d", localtime;
597 my $log = sprintf "%s/%s-%s-%02d",
598 ${RESULTDIR
}, $sysInfo->{'name'}, $ymd, $count;
599 return $log if (! -e
$log);
605 # Print a message to the named log file. We use this method rather than
606 # keeping the FD open because we use shell redirection to send command
607 # output to the same file.
609 my ( $logFile, @args ) = @_;
611 open(my $fd, ">>", $logFile) || abortRun
("can't append to $logFile");
617 # Display a number of something, auto-selecting the plural form
618 # if appropriate. We are given the number, the singular, and the
619 # plural; if the plural is omitted, it defaults to singular + "s".
621 my ( $n, $what, $plural ) = @_;
623 $plural = $what . "s" if !defined($plural);
626 return sprintf "unknown %s", $plural;
628 return sprintf "%d %s", $n, $n == 1 ?
$what : $plural;
633 # Merge two sets of test parameters -- defaults and actual parameters.
634 # Return the merged parameter hash.
636 my ( $def, $vals ) = @_;
639 foreach my $k (keys(%$def)) {
640 $params->{$k} = $def->{$k};
642 foreach my $k (keys(%$vals)) {
643 $params->{$k} = $vals->{$k};
650 ############################################################################
652 ############################################################################
654 # Extract interesting flags from the given processor flags string and
655 # convert them to descriptive names.
656 sub processCpuFlags
{
657 my ( $flagStr ) = @_;
660 foreach my $f (sort split(/\s+/, $flagStr)) {
661 my $name = $x86CpuFlags->{$f};
662 push(@names, $name) if $name;
669 # Get information on the CPUs in the system. Returns a reference to an
670 # array of N entries, one per CPU, where each entry is a hash containing
672 # describing the model etc. Returns undef if the information can't be got.
674 open(my $fd, "<", "/proc/cpuinfo") || return undef;
680 my ( $field, $val ) = split(/[ \t]*:[ \t]*/);
681 next if (!$field || !$val);
682 if ($field eq "processor") {
684 } elsif ($field eq "model name") {
687 $cpus->[$cpu]{'model'} = $model;
688 } elsif ($field eq "bogomips") {
689 $cpus->[$cpu]{'bogo'} = $val;
690 } elsif ($field eq "flags") {
691 $cpus->[$cpu]{'flags'} = processCpuFlags
($val);
701 # Get information on the host system. Returns a reference to a hash
702 # with the following fields:
705 # osRel Host OS release
706 # osVer Host OS version
707 # mach Host machine name (eg. "SparcStation 20", but on
708 # PC/Linux usually "i686" etc.)
709 # platform Hardware platform; on Linux, the base CPU type?
710 # system System name (eg. hostname and Linux distro, like
711 # "hostname: openSUSE 10.2 (i586)").
712 # cpus Value returned by getCpuInfo(), undef if not avail.
713 # numCpus Number of CPUs if known, else undef.
714 # load System load message as per "uptime".
715 # numUsers Number of users and/or open shell sessions.
719 # Get host system data.
721 $info->{'name'} = getCmdOutput
("uname -a");
723 $info->{'name'} = getCmdOutput
("hostname");
725 $info->{'os'} = getCmdOutput
("uname -o") || getCmdOutput
("uname -s");
726 $info->{'osRel'} = getCmdOutput
("uname -r");
727 $info->{'osVer'} = getCmdOutput
("uname -v");
728 $info->{'mach'} = getCmdOutput
("uname -m");
730 $info->{'platform'} = getCmdOutput
("uname -i");
733 # Get the system name (SUSE, Red Hat, etc.) if possible.
734 $info->{'system'} = $info->{'os'};
735 if ( -r
"/etc/SuSE-release" ) {
736 $info->{'system'} = getCmdOutput
("cat /etc/SuSE-release");
737 } elsif ( -r
"/etc/release" ) {
738 $info->{'system'} = getCmdOutput
("cat /etc/release");
741 # Get the language info.
743 my $lang = getCmdOutput
("printenv LANG");
744 my $map = getCmdOutput
("locale -k LC_CTYPE | grep charmap");
746 my $coll = getCmdOutput
("locale -k LC_COLLATE | grep collate-codeset");
748 $info->{'language'} = sprintf "%s (charmap=%s, collate=%s)",
752 # Get details on the CPUs, if possible.
753 my $cpus = getCpuInfo
();
754 if (defined($cpus)) {
755 $info->{'cpus'} = $cpus;
756 $info->{'numCpus'} = scalar(@
$cpus);
759 # Get graphics hardware info.
760 # if (!$ENV{MINIX}) {
761 # $info->{'graphics'} = getCmdOutput("3dinfo | cut -f1 -d\'(\'");
764 # Get system run state, load and usage info.
766 $info->{'runlevel'} = getCmdOutput
("runlevel | cut -f2 -d\" \"");
768 $info->{'load'} = getCmdOutput
("uptime");
769 $info->{'numUsers'} = getCmdOutput
("who | wc -l");
775 ############################################################################
777 ############################################################################
779 # Abort the benchmarking run with an error message.
783 printf STDERR
"\n**********************************************\n";
784 printf STDERR
"Run: %s; aborting\n", $err;
789 ############################################################################
791 ############################################################################
793 # Do checks that everything's ready for testing.
796 $ENV{'LANG'} = $language;
798 # Check that the required files are in the proper places.
799 system("make check");
803 abortRun
("\"make all\" failed");
807 # Create a script to kill this run.
808 system("echo \"kill -9 $$\" > \"${TMPDIR}/kill_run\"");
809 chmod(0755, $TMPDIR . "/kill_run");
813 # Parse the command arguments.
817 # The accumulator for the bench units to be run.
819 my $params = { 'tests' => $tests };
821 # Generate the requested list of bench programs.
824 while ($word = shift(@words)) {
825 if ($word !~ m/^-/) { # A test name.
826 if ($word eq "all") {
827 foreach my $t (keys(%$testList)) {
828 push(@
$tests, $t) if (!defined($testList->{$t}));
830 } elsif (exists($testList->{$word})) {
831 my $val = $testList->{$word} || [ $word ];
832 push(@
$tests, @
$val);
834 die("Run: unknown test \"$word\"\n");
836 } elsif ($word eq "-q") {
837 $params->{'verbose'} = 0;
838 } elsif ($word eq "-v") {
839 $params->{'verbose'} = 2;
840 } elsif ($word eq "-i") {
841 $params->{'iterations'} = shift(@words);
842 } elsif ($word eq "-c") {
843 if (!defined($params->{'copies'})) {
844 $params->{'copies'} = [ ];
846 push(@
{$params->{'copies'}}, shift(@words));
848 die("Run: unknown option $word\n");
856 ############################################################################
857 # RESULTS INPUT / OUTPUT
858 ############################################################################
860 # Read a set of benchmarking results from the given file.
861 # Returns results in the form returned by runTests(), but without the
862 # individual pass results.
863 sub readResultsFromFile
{
866 # Attempt to get the baseline data file; if we can't, just return undef.
867 open(my $fd, "<", $file) || return undef;
873 # Dump comments, ignore blank lines.
877 my ( $name, $time, $slab, $sum, $score, $iters ) = split(/\|/);
879 $bresult->{'score'} = $score;
880 $bresult->{'scorelabel'} = $slab;
881 $bresult->{'time'} = $time;
882 $bresult->{'iterations'} = $iters;
884 $results->{$name} = $bresult;
893 ############################################################################
895 ############################################################################
897 # Process a set of results from a single test by averaging the individal
898 # pass results into a single final value.
899 # First, though, dump the worst 1/3 of the scores. The logic is that a
900 # glitch in the system (background process waking up, for example) may
901 # make one or two runs go slow, so let's discard those.
903 # $bresult is a hashed array representing the results of a single test;
904 # $bresult->{'passes'} is an array of the output from the individual
906 sub combinePassResults
{
907 my ( $bench, $tdata, $bresult, $logFile ) = @_;
909 $bresult->{'cat'} = $tdata->{'cat'};
918 my $pres = $bresult->{'passes'};
920 # We're going to throw away the worst 1/3 of the pass results.
921 # Figure out how many to keep.
922 my $npasses = scalar(@
$pres);
923 my $ndump = int($npasses / 3);
925 foreach my $presult (sort { $a->{'COUNT0'} <=> $b->{'COUNT0'} } @
$pres) {
926 my $count = $presult->{'COUNT0'};
927 my $timebase = $presult->{'COUNT1'};
928 $label = $presult->{'COUNT2'};
929 my $time = $presult->{'TIME'} || $presult->{'elapsed'};
931 # Skip this result if it's one of the worst ones.
933 printLog
($logFile, "*Dump score: %12.1f\n", $count);
940 printLog
($logFile, "Count score: %12.1f\n", $count);
942 # If $timebase is 0 the figure is a rate; else compute
943 # counts per $timebase. $time is always seconds.
945 $sum += $count / ($time / $timebase);
946 $product += log($count) - log($time / $timebase);
949 $product += log($count);
954 # Save the results for the benchmark.
955 if ($iterations > 0) {
956 $bresult->{'score'} = exp($product / $iterations);
957 $bresult->{'scorelabel'} = $label;
958 $bresult->{'time'} = $totalTime / $iterations;
959 $bresult->{'iterations'} = $iterations;
961 $bresult->{'error'} = "No measured results";
966 # Index the given full benchmark results against the baseline results.
967 # $results is a hashed array of test names to test results.
969 # Adds the following fields to each benchmark result:
970 # iscore The baseline score for this test
971 # index The index of this test against the baseline
972 # Adds the following fields to $results:
973 # indexed The number of tests for which index values were
975 # fullindex Non-0 if all the index tests were indexed
976 # index The computed overall index for the run
977 # Note that the index values are computed as
978 # result / baseline * 10
979 # so an index of 523 indicates that a test ran 52.3 times faster than
982 my ( $results ) = @_;
984 # Read in the baseline result data. If we can't get it, just return
985 # without making indexed results.
986 my $index = readResultsFromFile
($BINDIR . "/index.base");
987 if (!defined($index)) {
991 # Count the number of results we have (indexed or not) in
994 foreach my $bench (@
{$results->{'list'}}) {
995 my $bresult = $results->{$bench};
996 ++$numCat->{$bresult->{'cat'}};
998 $results->{'numCat'} = $numCat;
1003 foreach my $bench (sort(keys(%$index))) {
1004 # Get the test data for this benchmark.
1005 my $tdata = $testParams->{$bench};
1006 if (!defined($tdata)) {
1007 abortRun
("unknown benchmark \"$bench\" in $BINDIR/index.base");
1010 # Get the test category. Count the total tests in this cat.
1011 my $cat = $tdata->{'cat'};
1012 ++$numIndex->{$cat};
1014 # If we don't have a result for this test, skip.
1015 next if (!defined($results->{$bench}));
1017 # Get the index and actual results. Calcluate the score.
1018 my $iresult = $index->{$bench};
1019 my $bresult = $results->{$bench};
1020 my $ratio = $bresult->{'score'} / $iresult->{'score'};
1022 # Save the indexed score.
1023 $bresult->{'iscore'} = $iresult->{'score'};
1024 $bresult->{'index'} = $ratio * 10;
1026 # Sun the scores, and count this test for this category.
1027 $sum->{$cat} += log($ratio);
1031 # Calculate the index scores per category.
1032 $results->{'indexed'} = $indexed;
1033 $results->{'numIndex'} = $numIndex;
1034 foreach my $c (keys(%$indexed)) {
1035 if ($indexed->{$c} > 0) {
1036 $results->{'index'}{$c} = exp($sum->{$c} / $indexed->{$c}) * 10;
1042 ############################################################################
1044 ############################################################################
1046 # Exec the given command in a sub-process.
1048 # In the child process, we run the command and store its standard output.
1049 # We also time its execution, and catch its exit status. We then write
1050 # the command's output, plus lines containing the execution time and status,
1053 # In the parent process, we immediately return an array containing the
1054 # child PID and the filehandle to the pipe. This allows the caller to
1055 # kick off multiple commands in parallel, then gather their output.
1056 sub commandBuffered
{
1059 # Create a pipe for parent-child communication.
1062 pipe($childReader, $parentWriter) || abortRun
("pipe() failed");
1063 $parentWriter->autoflush(1);
1065 # Fork off the child process.
1067 if (!defined($pid)) {
1068 abortRun
("fork() failed (undef)");
1069 } elsif ($pid == 0) {
1070 # Close the other end of the pipe.
1073 # Start the clock and spawn the command.
1074 my $benchStart = Time
::HiRes
::time();
1075 my ( $cmdPid, $cmdFd ) = command
($cmd);
1077 # Read and buffer all the command's output.
1083 # Stop the clock and save the time.
1084 my $elTime = Time
::HiRes
::time() - $benchStart;
1085 push(@
$output, sprintf "elapsed|%f\n", $elTime);
1087 # Wait for the child to die so we can get its status.
1088 # close($cmdFd); Doesn't work???
1089 waitpid($cmdPid, 0);
1091 push(@
$output, sprintf "status|%d\n", $status);
1093 # Now that we've got the time, play back all the output to the pipe.
1094 # The parent can read this at its leisure.
1095 foreach my $line (@
$output) {
1096 print $parentWriter $line;
1099 # Terminate this child.
1100 close $parentWriter;
1104 # Close the other end of the pipe.
1105 close $parentWriter;
1107 return ( $pid, $childReader );
1111 # Read the results of a benchmark execution from a child process, given
1112 # its process ID and its filehandle. Create a results hash structure
1113 # containing the fields returned by the child, plus:
1114 # pid The child's process ID
1115 # status The child's exit status
1116 # ERROR Any stderr output from the child that isn't result data
1117 # Note that ay result fields with ultiple values are split; so eg.
1124 my ( $pid, $fd ) = @_;
1126 my $presult = { 'pid' => $pid };
1128 # Read all the result lines from the child.
1132 my ( $field, @params ) = split(/\|/);
1133 if (scalar(@params) == 0) { # Error message.
1134 $presult->{'ERROR'} .= "\n" if ($presult->{'ERROR'});
1135 $presult->{'ERROR'} .= $field;
1136 } elsif (scalar(@params) == 1) { # Simple data.
1137 $presult->{$field} = $params[0];
1138 } else { # Compound data.
1139 # Store the values in separate fields, named "FIELD$i".
1140 for (my $x = 0; $x < scalar(@params); ++$x) {
1141 $presult->{$field . $x} = $params[$x];
1146 # If the command had an error, make an appropriate message if we
1148 if ($presult->{'status'} != 0 && !defined($presult->{'ERROR'})) {
1149 $presult->{'ERROR'} = "command returned status " . $presult->{'status'};
1152 # Wait for the child to die.
1160 # Execute a benchmark command. We set off a given number of copies in
1161 # parallel to exercise multiple CPUs.
1163 # We return an array of results hashes, one per copy; each one is as
1164 # returned by readResults().
1165 sub executeBenchmark
{
1166 my ( $command, $copies ) = @_;
1168 # Array of contexts for all the copies we're running.
1171 # Kick off all the commands at once.
1172 for (my $i = 0; $i < $copies; ++$i) {
1173 my ( $cmdPid, $cmdFd ) = commandBuffered
($command);
1180 # Now, we can simply read back the command results in order. Because
1181 # the child processes read and buffer the results and time the commands,
1182 # there's no need to use select() to read the results as they appear.
1184 for (my $i = 0; $i < $copies; ++$i) {
1185 my $presult = readResults
($ctxt->[$i]{'pid'}, $ctxt->[$i]{'fd'});
1186 push(@
$pres, $presult);
1193 # Run one iteration of a benchmark, as specified by the given
1194 # benchmark parameters. We run multiple parallel copies as
1195 # specified by $copies.
1197 my ( $params, $verbose, $logFile, $copies ) = @_;
1199 # Get the command to run.
1200 my $command = $params->{'command'};
1203 printf "COMMAND: \"%s\"\n", $command;
1204 printf "COPIES: \"%d\"\n", $copies;
1207 # Remember where we are, and move to the test directory.
1211 # Execute N copies of the benchmark in parallel.
1212 my $copyResults = executeBenchmark
($command, $copies);
1213 printLog
($logFile, "\n");
1218 # Sum up the scores of the copies.
1222 foreach my $res (@
$copyResults) {
1223 # Log the result data for each copy.
1224 foreach my $k (sort(keys(%$res))) {
1225 printLog
($logFile, "# %s: %s\n", $k, $res->{$k});
1227 printLog
($logFile, "\n");
1229 # If it failed, bomb out.
1230 if (defined($res->{'ERROR'})) {
1231 my $name = $params->{'logmsg'};
1232 abortRun
("\"$name\": " . $res->{'ERROR'});
1235 # Count up the score.
1236 $count += $res->{'COUNT0'};
1237 $time += $res->{'TIME'} || $res->{'elapsed'};
1238 $elap += $res->{'elapsed'};
1241 # Make up a combined result.
1242 my $passResult = $copyResults->[0];
1243 $passResult->{'COUNT0'} = $count;
1244 $passResult->{'TIME'} = $time / $copies;
1245 $passResult->{'elapsed'} = $elap / $copies;
1252 my ( $bench, $tparams, $verbose, $logFile, $copies ) = @_;
1254 # Make up the actual benchmark parameters.
1255 my $params = mergeParams
($baseParams, $tparams);
1257 # Make up the command string based on the parameters.
1258 my $prog = $params->{'prog'} || $BINDIR . "/" . $bench;
1259 my $command = sprintf "\"%s\" %s", $prog, $params->{'options'};
1260 $command .= " < \"" . $params->{'stdin'} . "\"" if ($params->{'stdin'});
1261 $command .= " 2>&1";
1262 $command .= $params->{'stdout'} ?
(" >> \"" . $logFile . "\"") : " > /dev/null";
1263 $params->{'command'} = $command;
1265 # Set up the benchmark results structure.
1266 my $bresult = { 'name' => $bench, 'msg' => $params->{'logmsg'} };
1269 printf "\n%d x %s ", $copies, $params->{'logmsg'};
1273 "\n########################################################\n");
1274 printLog
($logFile, "%s -- %s\n",
1275 $params->{'logmsg'}, number
($copies, "copy", "copies"));
1276 printLog
($logFile, "==> %s\n\n", $command);
1278 # Run the test iterations, as given by the "repeat" parameter.
1279 my $repeats = $shortIterCount;
1280 $repeats = $longIterCount if $params->{'repeat'} eq 'long';
1281 $repeats = 1 if $params->{'repeat'} eq 'single';
1283 for (my $i = 1; $i <= $repeats; ++$i) {
1284 printLog
($logFile, "#### Pass %d\n\n", $i);
1286 # make an attempt to flush buffers
1287 system("sync; sleep 1; sync; sleep 2");
1293 # Execute one pass of the benchmark.
1294 my $presult = runOnePass
($params, $verbose, $logFile, $copies);
1295 push(@
$pres, $presult);
1297 $bresult->{'passes'} = $pres;
1299 # Calculate the averaged results for this benchmark.
1300 combinePassResults
($bench, $tparams, $bresult, $logFile);
1304 printLog
($logFile, "\n>>>> Results of 1 copy\n");
1306 printLog
($logFile, "\n>>>> Sum of %d copies\n", $copies);
1308 foreach my $k ( 'score', 'time', 'iterations' ) {
1309 printLog
($logFile, ">>>> %s: %s\n", $k, $bresult->{$k});
1311 printLog
($logFile, "\n");
1313 # Some specific cleanup routines.
1314 if ($bench eq "C") {
1315 unlink(${TESTDIR
} . "/cctest.o");
1316 unlink(${TESTDIR
} . "/a.out");
1327 # Run the named benchmarks.
1329 my ( $tests, $verbose, $logFile, $copies ) = @_;
1331 # Run all the requested tests and gather the results.
1332 my $results = { 'start' => time(), 'copies' => $copies };
1333 foreach my $bench (@
$tests) {
1334 # Get the parameters for this benchmark.
1335 my $params = $testParams->{$bench};
1336 if (!defined($params)) {
1337 abortRun
("unknown benchmark \"$bench\"");
1340 # If the benchmark doesn't want to run with this many copies, skip it.
1341 my $cat = $params->{'cat'};
1342 my $maxCopies = $testCats->{$cat}{'maxCopies'};
1343 next if ($copies > $maxCopies);
1345 # Run the benchmark.
1346 my $bresult = runBenchmark
($bench, $params, $verbose, $logFile, $copies);
1347 $results->{$bench} = $bresult;
1349 $results->{'end'} = time();
1351 # Generate a sorted list of benchmarks for which we have results.
1352 my @benches = grep {
1353 ref($results->{$_}) eq "HASH" && defined($results->{$_}{'msg'})
1356 $results->{$a}{'msg'} cmp $results->{$b}{'msg'}
1358 $results->{'list'} = \
@benches;
1360 # Generate index scores for the results relative to the baseline data.
1361 indexResults
($results);
1367 ############################################################################
1369 ############################################################################
1371 # Display a banner indicating the configuration of the system under test
1372 # to the given file desc.
1374 my ( $info, $fd ) = @_;
1376 # Display basic system info.
1377 printf $fd " System: %s: %s\n", $info->{'name'}, $info->{'system'};
1378 printf $fd " OS: %s -- %s -- %s\n",
1379 $info->{'os'}, $info->{'osRel'}, $info->{'osVer'};
1381 printf $fd " Machine: %s (%s)\n", $info->{'mach'}, $info->{'platform'};
1383 printf $fd " Machine: %s\n", $info->{'mach'};
1385 printf $fd " Language: %s\n", $info->{'language'};
1388 # Get and display details on the CPUs, if possible.
1389 my $cpus = $info->{'cpus'};
1390 if (!defined($cpus)) {
1391 printf $fd " CPU: no details available\n";
1393 for (my $i = 0; $i <= $#$cpus; ++$i) {
1394 printf $fd " CPU %d: %s (%.1f bogomips)\n",
1395 $i, $cpus->[$i]{'model'}, $cpus->[$i]{'bogo'};
1396 printf $fd " %s\n", $cpus->[$i]{'flags'};
1400 # if (!$ENV{MINIX}) {
1401 # if ($info->{'graphics'}) {
1402 # printf $fd " Graphics: %s\n", $info->{'graphics'};
1406 # Display system load and usage info.
1408 printf $fd " %s; runlevel %s\n\n", $info->{'load'}, $info->{'runlevel'};
1413 # Display the test scores from the given set of test results.
1415 my ( $results, $outFd ) = @_;
1417 # Display the individual test scores.
1418 foreach my $bench (@
{$results->{'list'}}) {
1419 my $bresult = $results->{$bench};
1421 printf $outFd "%-40s %12.1f %-5s (%.1f s, %d samples)\n",
1423 $bresult->{'score'},
1424 $bresult->{'scorelabel'},
1426 $bresult->{'iterations'};
1433 # Display index scores, if any, for the given run results.
1435 my ( $results, $cat, $outFd ) = @_;
1437 my $total = $results->{'numIndex'}{$cat};
1438 my $indexed = $results->{'indexed'}{$cat};
1439 my $iscore = $results->{'index'}{$cat};
1440 my $full = $total == $indexed;
1442 # If there are no indexed scores, just say so.
1443 if (!defined($indexed) || $indexed == 0) {
1444 printf $outFd "No index results available for %s\n\n",
1445 $testCats->{$cat}{'name'};
1449 # Display the header, depending on whether we have a full set of index
1450 # scores, or a partial set.
1451 my $head = $testCats->{$cat}{'name'} .
1452 ($full ?
" Index Values" : " Partial Index");
1453 printf $outFd "%-40s %12s %12s %8s\n",
1454 $head, "BASELINE", "RESULT", "INDEX";
1456 # Display the individual test scores.
1457 foreach my $bench (@
{$results->{'list'}}) {
1458 my $bresult = $results->{$bench};
1459 next if $bresult->{'cat'} ne $cat;
1461 if (defined($bresult->{'iscore'}) && defined($bresult->{'index'})) {
1462 printf $outFd "%-40s %12.1f %12.1f %8.1f\n",
1463 $bresult->{'msg'}, $bresult->{'iscore'},
1464 $bresult->{'score'}, $bresult->{'index'};
1466 printf $outFd "%-40s %12s %12.1f %8s\n",
1467 $bresult->{'msg'}, "---",
1468 $bresult->{'score'}, "---";
1472 # Display the overall score.
1473 my $title = $testCats->{$cat}{'name'} . " Index Score";
1475 $title .= " (Partial Only)";
1477 printf $outFd "%-40s %12s %12s %8s\n", "", "", "", "========";
1478 printf $outFd "%-66s %8.1f\n", $title, $iscore;
1484 # Display index scores, if any, for the given run results.
1486 my ( $results, $outFd ) = @_;
1488 my $count = $results->{'indexed'};
1489 foreach my $cat (keys(%$count)) {
1490 logIndexCat
($results, $cat, $outFd);
1495 # Dump the given run results into the given report file.
1497 my ( $systemInfo, $results, $verbose, $reportFd ) = @_;
1499 # Display information about this test run.
1500 printf $reportFd "------------------------------------------------------------------------\n";
1501 printf $reportFd "Benchmark Run: %s %s - %s\n",
1502 strftime
("%a %b %d %Y", localtime($results->{'start'})),
1503 strftime
("%H:%M:%S", localtime($results->{'start'})),
1504 strftime
("%H:%M:%S", localtime($results->{'end'}));
1505 printf $reportFd "%s in system; running %s of tests\n",
1506 number
($systemInfo->{'numCpus'}, "CPU"),
1507 number
($results->{'copies'}, "parallel copy", "parallel copies");
1508 printf $reportFd "\n";
1510 # Display the run scores.
1511 logResults
($results, $reportFd);
1513 # Display the indexed scores, if any.
1514 logIndex
($results, $reportFd);
1518 ############################################################################
1520 ############################################################################
1522 # Dump the given run results into the given report file.
1524 my ( $systemInfo, $reportFd ) = @_;
1526 # Display information about this test run.
1527 my $title = sprintf "Benchmark of %s / %s on %s",
1528 $systemInfo->{'name'}, $systemInfo->{'system'},
1529 strftime
("%a %b %d %Y", localtime());
1531 print $reportFd <<EOF;
1532 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
1533 "http://www.w3.org/TR/html4/loose.dtd">
1536 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
1537 <meta name="keywords" content="linux, benchmarks, benchmarking">
1538 <title>$title</title>
1539 <style type="text/css">
1541 margin: 1em 1em 1em 0;
1542 background: #f9f9f9;
1543 border: 1px #aaaaaa solid;
1544 border-collapse: collapse;
1547 table th, table td {
1548 border: 1px #aaaaaa solid;
1553 background: #f2f2f2;
1561 # Display information about this test run.
1562 printf $reportFd "<h2>%s</h2>\n", $title;
1563 printf $reportFd "<p><b>BYTE UNIX Benchmarks (Version %s)</b></p>\n\n",
1568 # Display a banner indicating the configuration of the system under test
1569 # to the given file desc.
1570 sub displaySystemHtml
{
1571 my ( $info, $fd ) = @_;
1573 printf $fd "<h3>Test System Information</h3>\n";
1574 printf $fd "<p><table>\n";
1576 # Display basic system info.
1577 printf $fd "<tr>\n";
1578 printf $fd " <td><b>System:</b></td>\n";
1579 printf $fd " <td colspan=2>%s: %s</td>\n",
1580 $info->{'name'}, $info->{'system'};
1581 printf $fd "</tr><tr>\n";
1582 printf $fd " <td><b>OS:</b></td>\n";
1583 printf $fd " <td colspan=2>%s -- %s -- %s</td>\n",
1584 $info->{'os'}, $info->{'osRel'}, $info->{'osVer'};
1585 printf $fd "</tr><tr>\n";
1586 printf $fd " <td><b>Machine:</b></td>\n";
1588 printf $fd " <td colspan=2>%s: %s</td>\n",
1589 $info->{'mach'}, $info->{'platform'};
1591 printf $fd " <td colspan=2>%s</td>\n",
1594 printf $fd "</tr><tr>\n";
1595 printf $fd " <td><b>Language:</b></td>\n";
1596 printf $fd " <td colspan=2>%s</td>\n", $info->{'language'};
1598 printf $fd "</tr>\n";
1600 # Get and display details on the CPUs, if possible.
1601 my $cpus = $info->{'cpus'};
1602 if (!defined($cpus)) {
1603 printf $fd "<tr>\n";
1604 printf $fd " <td><b>CPUs:</b></td>\n";
1605 printf $fd " <td colspan=2>no details available</td>\n";
1606 printf $fd "</tr>\n";
1608 for (my $i = 0; $i <= $#$cpus; ++$i) {
1609 printf $fd "<tr>\n";
1611 printf $fd " <td rowspan=%d><b>CPUs:</b></td>\n", $#$cpus + 1;
1613 printf $fd " <td><b>%d:</b></td>\n", $i;
1614 printf $fd " <td>%s (%.1f bogomips)<br/>\n",
1615 $cpus->[$i]{'model'}, $cpus->[$i]{'bogo'};
1616 printf $fd " %s</td>\n", $cpus->[$i]{'flags'};
1617 printf $fd "</tr>\n";
1621 # Display graphics hardware info.
1622 # if (!$ENV{MINIX}) {
1623 # if ($info->{'graphics'}) {
1624 # printf $fd "<tr>\n";
1625 # printf $fd " <td><b>Graphics:</b></td>\n";
1626 # printf $fd " <td colspan=2>%s</td>\n", $info->{'graphics'};
1627 # printf $fd "</tr>\n";
1631 # Display system runlevel, load and usage info.
1632 printf $fd "<tr>\n";
1633 printf $fd " <td><b>Uptime:</b></td>\n";
1635 printf $fd " <td colspan=2>%s; runlevel %s</td>\n",
1636 $info->{'load'}, $info->{'runlevel'};
1638 printf $fd " <td colspan=2>%s\n",
1640 printf $fd "</tr>\n";
1642 printf $fd "</table></p>\n\n";
1646 # Display the test scores from the given set of test results
1647 # for a given category of tests.
1648 sub logCatResultsHtml
{
1649 my ( $results, $cat, $fd ) = @_;
1651 my $numIndex = $results->{'numIndex'}{$cat};
1652 my $indexed = $results->{'indexed'}{$cat};
1653 my $iscore = $results->{'index'}{$cat};
1654 my $full = defined($indexed) && $indexed == $numIndex;
1656 # If there are no results in this category, just ignore it.
1657 if (!defined($results->{'numCat'}{$cat}) ||
1658 $results->{'numCat'}{$cat} == 0) {
1662 # Say the category. If there are no indexed scores, just say so.
1664 if (!defined($indexed) || $indexed == 0) {
1665 $warn = " — no index results available";
1667 $warn = " — not all index tests were run;" .
1668 " only a partial index score is available";
1670 printf $fd "<h4>%s%s</h4>\n", $testCats->{$cat}{'name'}, $warn;
1672 printf $fd "<p><table width=\"100%%\">\n";
1674 printf $fd "<tr>\n";
1675 printf $fd " <th align=left>Test</th>\n";
1676 printf $fd " <th align=right>Score</th>\n";
1677 printf $fd " <th align=left>Unit</th>\n";
1678 printf $fd " <th align=right>Time</th>\n";
1679 printf $fd " <th align=right>Iters.</th>\n";
1680 printf $fd " <th align=right>Baseline</th>\n";
1681 printf $fd " <th align=right>Index</th>\n";
1682 printf $fd "</tr>\n";
1684 # Display the individual test scores.
1685 foreach my $bench (@
{$results->{'list'}}) {
1686 my $bresult = $results->{$bench};
1687 next if $bresult->{'cat'} ne $cat;
1689 printf $fd "<tr>\n";
1690 printf $fd " <td><b>%s</b></td>\n", $bresult->{'msg'};
1691 printf $fd " <td align=right><tt>%.1f</tt></td>\n",
1692 $bresult->{'score'};
1693 printf $fd " <td align=left><tt>%s</tt></td>\n",
1694 $bresult->{'scorelabel'};
1695 printf $fd " <td align=right><tt>%.1f s</tt></td>\n",
1697 printf $fd " <td align=right><tt>%d</tt></td>\n",
1698 $bresult->{'iterations'};
1700 if (defined($bresult->{'index'})) {
1701 printf $fd " <td align=right><tt>%.1f</tt></td>\n",
1702 $bresult->{'iscore'};
1703 printf $fd " <td align=right><tt>%.1f</tt></td>\n",
1704 $bresult->{'index'};
1706 printf $fd "</tr>\n";
1709 # Display the overall score.
1710 if (defined($indexed) && $indexed > 0) {
1711 my $title = $testCats->{$cat}{'name'} . " Index Score";
1713 $title .= " (Partial Only)";
1715 printf $fd "<tr>\n";
1716 printf $fd " <td colspan=6><b>%s:</b></td>\n", $title;
1717 printf $fd " <td align=right><b><tt>%.1f</tt></b></td>\n", $iscore;
1718 printf $fd "</tr>\n";
1721 printf $fd "</table></p>\n\n";
1725 # Display index scores, if any, for the given run results.
1726 sub logResultsHtml
{
1727 my ( $results, $fd ) = @_;
1729 foreach my $cat (keys(%$testCats)) {
1730 logCatResultsHtml
($results, $cat, $fd);
1735 # Dump the given run results into the given report file.
1736 sub summarizeRunHtml
{
1737 my ( $systemInfo, $results, $verbose, $reportFd ) = @_;
1739 # Display information about this test run.
1740 my $time = $results->{'end'} - $results->{'start'};
1741 printf $reportFd "<p><hr/></p>\n";
1742 printf $reportFd "<h3>Benchmark Run: %s; %s</h3>\n",
1743 number
($systemInfo->{'numCpus'}, "CPU"),
1744 number
($results->{'copies'}, "parallel process", "parallel processes");
1745 printf $reportFd "<p>Time: %s - %s; %dm %02ds</p>\n",
1746 strftime
("%H:%M:%S", localtime($results->{'start'})),
1747 strftime
("%H:%M:%S", localtime($results->{'end'})),
1748 int($time / 60), $time % 60;
1749 printf $reportFd "\n";
1751 # Display the run scores.
1752 logResultsHtml
($results, $reportFd);
1757 my ( $reportFd ) = @_;
1759 print $reportFd <<EOF;
1761 <div><b>No Warranties:</b> This information is provided free of charge and "as
1762 is" without any warranty, condition, or representation of any kind,
1763 either express or implied, including but not limited to, any warranty
1764 respecting non-infringement, and the implied warranties of conditions
1765 of merchantability and fitness for a particular purpose. All logos or
1766 trademarks on this site are the property of their respective owner. In
1767 no event shall the author be liable for any
1768 direct, indirect, special, incidental, consequential or other damages
1769 howsoever caused whether arising in contract, tort, or otherwise,
1770 arising out of or in connection with the use or performance of the
1771 information contained on this web site.</div>
1778 ############################################################################
1780 ############################################################################
1785 my $params = parseArgs
(@args);
1786 my $verbose = $params->{'verbose'} || 1;
1787 if ($params->{'iterations'}) {
1788 $longIterCount = $params->{'iterations'};
1789 $shortIterCount = int(($params->{'iterations'} + 1) / 3);
1790 $shortIterCount = 1 if ($shortIterCount < 1);
1793 # If no benchmark units have be specified, do "index".
1794 my $tests = $params->{'tests'};
1800 my $systemInfo = getSystemInfo
();
1802 # If the number of copies to run was not set, set it to 1
1803 # and the number of CPUs in the system (if > 1).
1804 my $copies = $params->{'copies'};
1805 if (!$copies || scalar(@
$copies) == 0) {
1807 if (defined($systemInfo->{'numCpus'}) && $systemInfo->{'numCpus'} > 1) {
1808 push(@
$copies, $systemInfo->{'numCpus'});
1812 # Display the program banner.
1813 system("cat \"${BINDIR}/unixbench.logo\"");
1816 printf "\n", join(", ", @
$tests);
1817 printf "Tests to run: %s\n", join(", ", @
$tests);
1820 # Generate unique file names for the report and log file.
1821 my $reportFile = logFile
($systemInfo);
1822 my $reportHtml = $reportFile . ".html";
1823 my $logFile = $reportFile . ".log";
1825 # Open the log file for writing.
1826 open(my $reportFd, ">", $reportFile) ||
1827 die("Run: can't write to $reportFile\n");
1828 open(my $reportFd2, ">", $reportHtml) ||
1829 die("Run: can't write to $reportHtml\n");
1830 printf $reportFd " BYTE UNIX Benchmarks (Version %s)\n\n", $version;
1831 runHeaderHtml
($systemInfo, $reportFd2);
1833 # Dump information about the system under test.
1834 displaySystem
($systemInfo, $reportFd);
1835 displaySystemHtml
($systemInfo, $reportFd2);
1837 # Run the tests! Do a test run once for each desired number of copies;
1838 # for example, on a 2-CPU system, we may do a single-processing run
1839 # followed by a dual-processing run.
1840 foreach my $c (@
$copies) {
1842 printf "Run with %s\n", number
($c, "copy", "copies");
1844 my $results = runTests
($tests, $verbose, $logFile, $c);
1846 summarizeRun
($systemInfo, $results, $verbose, $reportFd);
1847 summarizeRunHtml
($systemInfo, $results, $verbose, $reportFd2);
1850 runFooterHtml
($reportFd2);
1852 # Finish the report.
1856 # Display the report, if not in quiet mode.
1859 printf "========================================================================\n";
1860 system("cat \"$reportFile\"");