Add option to specify output file location in sunspider.
[WebKit-https.git] / PerformanceTests / SunSpider / sunspider
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2007 Apple Inc. All rights reserved.
4 # Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 #    notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 #    notice, this list of conditions and the following disclaimer in the
13 #    documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 # PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26
27 use strict;
28 use Getopt::Long;
29 use File::Basename;
30 use File::Spec;
31 use Cwd;
32 use POSIX qw(strftime);
33 use Time::HiRes qw(gettimeofday tv_interval);
34
35 my $showHelp = 0;
36 my $runInstruments = 0;
37 my $ubench = 0;
38 my $v8suite = 0;
39 my $suite = "";
40 my $parseOnly = 0;
41 my $jsShellPath;
42 my $jsShellArgs = "";
43 my $setBaseline = 0;
44 my $testsPattern;
45 my $testRuns = 10;
46 my $resultsFile = "";
47
48 my $programName = basename($0);
49 my $usage = <<EOF;
50 Usage: $programName --shell=[path] [options]
51   --help            Show this help message
52   --set-baseline    Set baseline for future comparisons
53   --shell           Path to JavaScript shell
54   --args            Arguments to pass to JavaScript shell
55   --runs            Number of times to run tests (default: $testRuns)
56   --tests           Only run tests matching provided pattern
57   --instruments     Sample execution time with the Mac OS X "Instruments" tool (Time Profile) (implies --runs=1)
58   --suite           Select a specific benchmark suite. The default is sunspider-1.0.1
59   --ubench          Use microbenchmark suite instead of regular tests. Same as --suite=ubench
60   --v8-suite        Use the V8 benchmark suite. Same as --suite=v8-v4
61   --output          Override the default output path and filename
62   --parse-only      Use the parse-only benchmark suite. Same as --suite=parse-only
63 EOF
64
65 GetOptions('runs=i' => \$testRuns,
66            'set-baseline' => \$setBaseline,
67            'shell=s' => \$jsShellPath,
68            'args=s' => \$jsShellArgs,
69            'instruments' => \$runInstruments,
70            'suite=s' => \$suite,
71            'ubench' => \$ubench,
72            'v8-suite' => \$v8suite,
73            'parse-only' => \$parseOnly,
74            'tests=s' => \$testsPattern,
75            'output=s' => \$resultsFile,
76            'help' => \$showHelp);
77
78
79 $suite = "ubench" if ($ubench);
80 $suite = "v8-v4" if ($v8suite);
81 $suite = "parse-only" if ($parseOnly);
82 $suite = "sunspider-1.0.1" if (!$suite);
83
84 my $resultDirectory = "${suite}-results";
85
86 my $suitePath = $suite;
87 $suitePath = "tests/" . $suitePath unless ($suite =~ /\//);
88
89 $testRuns = 1 if $runInstruments;
90
91 if (!$jsShellPath || $showHelp) {
92    print STDERR $usage;
93    exit 1;
94 }
95
96 sub dumpToFile($$)
97 {
98     my ($contents, $path) = @_;
99     open FILE, ">", $path or die "Failed to open $path";
100     print FILE $contents;
101     close FILE;
102 }
103
104 my @tests = ();
105 my @categories = ();
106 my %uniqueCategories = ();
107
108 sub loadTestsList()
109 {
110     open TESTLIST, "<", "${suitePath}/LIST" or die "Can't find ${suitePath}/LIST";
111     while (<TESTLIST>) {
112         chomp;
113         next unless !$testsPattern || /$testsPattern/;
114         
115         push @tests, $_;
116         my $category = $_;
117         $category =~ s/-.*//;
118         if (!$uniqueCategories{$category}) {
119             push @categories, $category;
120             $uniqueCategories{$category} = $category;
121         }
122     }
123     close TESTLIST;
124 }
125
126 my $timeString = strftime "%Y-%m-%d-%H.%M.%S", localtime $^T;
127 my $prefixFile = "$resultDirectory/sunspider-test-prefix.js";
128 $resultsFile = "$resultDirectory/sunspider-results-$timeString.js" unless $resultsFile;
129
130 sub writePrefixFile()
131 {
132     my $prefix = "var suitePath = " . '"' . $suitePath . '"' . ";\n";
133     $prefix .= "var tests = [ " . join(", ", map { '"' . $_ . '"' } @tests) . " ];\n";
134     $prefix .= "var categories = [ " . join(", ", map { '"' . $_ . '"' } @categories) . " ];\n";
135
136     mkdir "$resultDirectory";
137     dumpToFile($prefix, $prefixFile);
138 }
139
140 sub runTestsOnce($)
141 {
142     my ($useInstruments) = @_;
143     my $shellArgs = $jsShellArgs . " -f $prefixFile -f resources/sunspider-standalone-driver.js 2> " . File::Spec->devnull();
144     my $output;
145     if ($useInstruments) {
146         $output = `instruments -t "resources/TimeProfile20us.tracetemplate" "$jsShellPath" $shellArgs`;
147     } else {
148         $output = `"$jsShellPath" $shellArgs | grep -v break`;
149     }
150     return $output;
151 }
152
153 sub newestFile($$)
154 {
155     my ($dir, $pattern) = @_;
156
157     my $newestAge;
158     my $newestFile = "";
159     opendir DIR, $dir or die;
160     for my $file (readdir DIR) {
161         if ($file =~ $pattern) {
162             my $age = -M "$dir/$file";
163             if (!defined $newestAge || $age < $newestAge) {
164                 $newestFile = $file;
165                 $newestAge = $age;
166             }
167         }
168     }
169     closedir DIR;
170
171     return "$dir/$newestFile";
172 }
173
174 loadTestsList();
175 if ($testsPattern) {
176     print STDERR "Found " . scalar(@tests) . " tests matching '" . $testsPattern . "'\n";
177 } else {
178     print STDERR "Found " . scalar(@tests) . " tests\n";
179 }
180 die "No tests to run"  unless scalar(@tests);
181 print STDERR "Running SunSpider once for warmup, then " . ($runInstruments ? "under Instruments" : "$testRuns time" . ($testRuns == 1 ? "" : "s")) . "\n";
182 writePrefixFile();
183
184 runTestsOnce(0);
185 print "Discarded first run.\n";
186
187 my $result;
188 my $count = 0;
189 my @results = ();
190 my $total = 0;
191 print "[";
192 while ($count++ < $testRuns) {
193     $result = runTestsOnce($runInstruments);
194     $result =~ s/\r\n/\n/g;
195     chomp $result;
196     push @results, $result;
197     print $result;
198     print ",\n" unless ($count == $testRuns);
199 }
200 print "]\n";
201
202 my $output = "var output = [\n" . join(",\n", @results) . "\n];\n";
203 dumpToFile($output, $resultsFile);
204 dumpToFile(File::Spec->rel2abs($resultsFile), "$resultDirectory/baseline-filename.txt") if $setBaseline;
205
206 system("$jsShellPath", "-f", $prefixFile, "-f", $resultsFile, "-f", "resources/sunspider-analyze-results.js");
207
208 print("\nResults are located at $resultsFile\n");
209
210 if ($runInstruments) {
211     my $newestTrace = newestFile(".", qr/\.trace$/);
212     if ($newestTrace) {
213         my $profileFile = "$resultDirectory/sunspider-profile-$timeString.trace";
214         rename $newestTrace, $profileFile or die;
215         exec "/usr/bin/open", $profileFile;
216     }
217 }