1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#! @PERL@
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--------------------------------------------------------------------##
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--- Valgrind performance testing script                  vg_perf ---##
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--------------------------------------------------------------------##
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  This file is part of Valgrind, a dynamic binary instrumentation
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  framework.
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  Copyright (C) 2005 Nicholas Nethercote
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     njn@valgrind.org
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  This program is free software; you can redistribute it and/or
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  modify it under the terms of the GNU General Public License as
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  published by the Free Software Foundation; either version 2 of the
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  License, or (at your option) any later version.
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  This program is distributed in the hope that it will be useful, but
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  WITHOUT ANY WARRANTY; without even the implied warranty of
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  General Public License for more details.
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  You should have received a copy of the GNU General Public License
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  along with this program; if not, write to the Free Software
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  02111-1307, USA.
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  The GNU General Public License is contained in the file COPYING.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# usage: see usage message.
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# You can specify individual files to test, or whole directories, or both.
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Directories are traversed recursively, except for ones named, for example, 
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# CVS/ or docs/.
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Each test is defined in a file <test>.vgperf, containing one or more of the
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# following lines, in any order:
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#   - prog:   <prog to run>                         (compulsory)
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#   - args:   <args for prog>                       (default: none)
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#   - vgopts: <Valgrind options>                    (default: none)
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#   - prereq: <prerequisite command>                (default: none)
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#   - cleanup: <post-test cleanup cmd to run>       (default: none)
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# The prerequisite command, if present, must return 0 otherwise the test is
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# skipped.
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownuse warnings;
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownuse strict;
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Global vars
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $usage = <<END
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownusage: vg_perf [options] [files or dirs]
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  options for the user, with defaults in [ ], are:
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    -h --help             show this message
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --reps=<n>            number of repeats for each program [1]
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --tools=<t1,t2,t3>    tools to run [Nulgrind and Memcheck]
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    --vg                  Valgrind(s) to measure (can be specified multiple
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            times).  The "in-place" build is used.
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            [Valgrind in the current directory]
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Any tools named in --tools must be present in all directories specified
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  with --vg.  (This is not checked.)
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownEND
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown;
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Test variables
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $vgopts;             # valgrind options
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $prog;               # test prog
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $args;               # test prog args
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $prereq;             # prerequisite test to satisfy before running test
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $cleanup;            # cleanup command to run
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Command line options
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $n_reps = 1;         # Run each test $n_reps times and choose the best one.
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @vgdirs;             # Dirs of the various Valgrinds being measured.
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @tools = ("none", "memcheck");   # tools being measured
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $num_tests_done   = 0;
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy $num_timings_done = 0;
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Starting directory
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownchomp(my $tests_dir = `pwd`);
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Process command line, setup
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# If $prog is a relative path, it prepends $dir to it.  Useful for two reasons:
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# 1. Can prepend "." onto programs to avoid trouble with users who don't have
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    "." in their path (by making $dir = ".")
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# 2. Can prepend the current dir to make the command absolute to avoid
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#    subsequent trouble when we change directories.
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Also checks the program exists and is executable.
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub validate_program ($$$$) 
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($dir, $prog, $must_exist, $must_be_executable) = @_;
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # If absolute path, leave it alone.  If relative, make it
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # absolute -- by prepending current dir -- so we can change
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # dirs and still use it.
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $prog = "$dir/$prog" if ($prog !~ /^\//);
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($must_exist) {
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        (-f $prog) or die "vg_perf: '$prog' not found or not a file ($dir)\n";
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($must_be_executable) { 
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        (-x $prog) or die "vg_perf: '$prog' not executable ($dir)\n";
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return $prog;
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub add_vgdir($)
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($vgdir) = @_;
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($vgdir !~ /^\//) { $vgdir = "$tests_dir/$vgdir"; }
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    validate_program($vgdir, "./coregrind/valgrind", 1, 1);
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    push(@vgdirs, $vgdir);
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub process_command_line() 
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @fs;
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    for my $arg (@ARGV) {
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if ($arg =~ /^-/) {
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if ($arg =~ /^--reps=(\d+)$/) {
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $n_reps = $1;
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                if ($n_reps < 1) { die "bad --reps value: $n_reps\n"; }
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--vg=(.+)$/) {
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                # Make dir absolute if not already
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                add_vgdir($1);
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } elsif ($arg =~ /^--tools=(.+)$/) {
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                @tools = split(/,/, $1);
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                die $usage;
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else {
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            push(@fs, $arg);
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # If no --vg options were specified, use the current tree.
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (0 == @vgdirs) {
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        add_vgdir($tests_dir);
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    (0 != @fs) or die "No test files or directories specified\n";
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return @fs;
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Read a .vgperf file
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub read_vgperf_file($)
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($f) = @_;
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Defaults.
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    ($vgopts, $prog, $args, $prereq, $cleanup)
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = ("", undef, "", undef, undef, undef, undef);
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    open(INPUTFILE, "< $f") || die "File $f not openable\n";
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    while (my $line = <INPUTFILE>) {
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if      ($line =~ /^\s*#/ || $line =~ /^\s*$/) {
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    next;
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	} elsif ($line =~ /^\s*vgopts:\s*(.*)$/) {
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $vgopts = $1;
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif ($line =~ /^\s*prog:\s*(.*)$/) {
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $prog = validate_program(".", $1, 1, 1);
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif ($line =~ /^\s*args:\s*(.*)$/) {
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $args = $1;
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif ($line =~ /^\s*prereq:\s*(.*)$/) {
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $prereq = $1;
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif ($line =~ /^\s*cleanup:\s*(.*)$/) {
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $cleanup = $1;
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else {
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            die "Bad line in $f: $line\n";
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    close(INPUTFILE);
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (!defined $prog) {
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $prog = "";     # allow no prog for testing error and --help cases
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (0 == @tools) {
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        die "vg_perf: missing 'tools' line in $f\n";
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Do one test
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Since most of the program time is spent in system() calls, need this to
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# propagate a Ctrl-C enabling us to quit.
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub mysystem($) 
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($cmd) = @_;
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $retval = system($cmd);
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($retval == 2) { 
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        exit 1; 
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    } else {
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        return $retval;
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Run program N times, return the best user time.  Use the POSIX
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# -p flag on /usr/bin/time so as to get something parseable on AIX.
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub time_prog($$)
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($cmd, $n) = @_;
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $tmin = 999999;
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    for (my $i = 0; $i < $n; $i++) {
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        mysystem("echo '$cmd' > perf.cmd");
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $retval = mysystem("$cmd > perf.stdout 2> perf.stderr");
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        (0 == $retval) or 
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            die "\n*** Command returned non-zero ($retval)"
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              . "\n*** See perf.{cmd,stdout,stderr} to determine what went wrong.\n";
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $out = `cat perf.stderr`;
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        ($out =~ /[Uu]ser +([\d\.]+)/) or 
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            die "\n*** missing usertime in perf.stderr\n";
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        $tmin = $1 if ($1 < $tmin);
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Avoid divisions by zero!
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    return (0 == $tmin ? 0.01 : $tmin);
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub do_one_test($$) 
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($dir, $vgperf) = @_;
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $vgperf =~ /^(.*)\.vgperf/;
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $name = $1;
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my %first_tTool;    # For doing percentage speedups when comparing
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        # multiple Valgrinds
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    read_vgperf_file($vgperf);
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (defined $prereq) {
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (system("$prereq") != 0) {
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            printf("%-16s (skipping, prereq failed: $prereq)\n", "$name:");
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return;
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $timecmd = "/usr/bin/time -p";
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Do the native run(s).
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    printf("-- $name --\n") if (@vgdirs > 1);
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $cmd     = "$timecmd $prog $args";
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $tNative = time_prog($cmd, $n_reps);
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $vgdir (@vgdirs) {
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Benchmark name
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        printf("%-8s ", $name);
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Print the Valgrind version if we are measuring more than one.
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $vgdirname = $vgdir;
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        chomp($vgdirname = `basename $vgdir`);
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        printf("%-10s:", $vgdirname);
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Native execution time
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        printf("%4.2fs", $tNative);
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        foreach my $tool (@tools) {
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # First two chars of toolname for abbreviation
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $tool_abbrev = $tool;
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $tool_abbrev =~ s/(..).*/$1/;
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # Do the tool run(s).  Set both VALGRIND_LIB and VALGRIND_LIB_INNER
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # in case this Valgrind was configured with --enable-inner.  And
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # also VALGRINDLIB, which was the old name for the variable, to
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # allow comparison against old Valgrind versions (eg. 2.4.X).
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            printf("  %s:", $tool_abbrev);
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $vgsetup = "VALGRINDLIB=$vgdir/.in_place "
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        . "VALGRIND_LIB=$vgdir/.in_place "
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        . "VALGRIND_LIB_INNER=$vgdir/.in_place ";
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $vgcmd   = "$vgdir/coregrind/valgrind "
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        . "--command-line-only=yes --tool=$tool -q "
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        . "--memcheck:leak-check=no "
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        . "--trace-children=yes "
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        . "$vgopts ";
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $cmd     = "$vgsetup $timecmd $vgcmd $prog $args";
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            my $tTool   = time_prog($cmd, $n_reps);
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            printf("%4.1fs (%4.1fx,", $tTool, $tTool/$tNative);
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # If it's the first timing for this tool on this benchmark,
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # record the time so we can get the percentage speedup of the
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # subsequent Valgrinds.  Otherwise, compute and print
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # the speedup.
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (not defined $first_tTool{$tool}) {
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                $first_tTool{$tool} = $tTool;
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                print(" -----)");
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                my $speedup = 100 - (100 * $tTool / $first_tTool{$tool});
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                printf("%5.1f%%)", $speedup);
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $num_timings_done++;
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (defined $cleanup) {
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                (system("$cleanup") == 0) or 
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    print("  ($name cleanup operation failed: $cleanup)\n");
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        printf("\n");
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $num_tests_done++;
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Test one directory (and any subdirs)
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub test_one_dir($$);    # forward declaration
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub test_one_dir($$) 
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my ($dir, $prev_dirs) = @_;
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    $dir =~ s/\/$//;    # trim a trailing '/'
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    chomp(my $initial_dir = `pwd`);     # record where we started
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Ignore dirs into which we should not recurse.
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($dir =~ /^(BitKeeper|CVS|SCCS|docs|doc)$/) { return; }
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    chdir($dir) or die "Could not change into $dir\n";
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    # Nb: Don't prepend a '/' to the base directory
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $full_dir = $prev_dirs . ($prev_dirs eq "" ? "" : "/") . $dir;
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $dashes = "-" x (50 - length $full_dir);
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my @fs = glob "*";
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    my $found_tests = (0 != (grep { $_ =~ /\.vgperf$/ } @fs));
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($found_tests) {
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print "-- Running  tests in $full_dir $dashes\n";
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    foreach my $f (@fs) {
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if (-d $f) {
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            test_one_dir($f, $full_dir);
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif ($f =~ /\.vgperf$/) {
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_one_test($full_dir, $f);
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if ($found_tests) {
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        print "-- Finished tests in $full_dir $dashes\n";
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    chdir("$initial_dir");
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# Summarise results
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsub summarise_results 
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    printf("\n== %d programs, %d timings =================\n\n", 
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           $num_tests_done, $num_timings_done);
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# main()
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#----------------------------------------------------------------------------
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown# nuke VALGRIND_OPTS
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown$ENV{"VALGRIND_OPTS"} = "";
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownmy @fs = process_command_line();
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownforeach my $f (@fs) {
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (-d $f) {
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        test_one_dir($f, "");
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    } else { 
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        # Allow the .vgperf suffix to be given or omitted
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        if ($f =~ /.vgperf$/ && -r $f) {
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            # do nothing
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } elsif (-r "$f.vgperf") {
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            $f = "$f.vgperf";
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        } else {
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            die "`$f' neither a directory nor a readable test file/name\n"
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $dir  = `dirname  $f`;   chomp $dir;
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        my $file = `basename $f`;   chomp $file;
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        chdir($dir) or die "Could not change into $dir\n";
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        do_one_test($dir, $file);
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        chdir($tests_dir);
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownsummarise_results();
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--------------------------------------------------------------------##
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--- end                                                          ---##
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown##--------------------------------------------------------------------##
400