Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: Tools/Scripts/bencher

Issue 1253013003: Remove all perl scripts from Tools/Scripts (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Remove the python code to invoke Perl \o/ Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/env ruby
2
3 # Copyright (C) 2011 Apple Inc. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 # 1. Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # 2. Redistributions in binary form must reproduce the above copyright
11 # notice, this list of conditions and the following disclaimer in the
12 # documentation and/or other materials provided with the distribution.
13 #
14 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 # THE POSSIBILITY OF SUCH DAMAGE.
25
26 require 'rubygems'
27
28 require 'getoptlong'
29 require 'pathname'
30 require 'tempfile'
31 require 'socket'
32
33 begin
34 require 'json'
35 rescue LoadError => e
36 $stderr.puts "It does not appear that you have the 'json' package installed. Try running 'sudo gem install json'."
37 exit 1
38 end
39
40 # Configuration
41
42 CONFIGURATION_FLNM = ENV["HOME"]+"/.bencher"
43
44 unless FileTest.exist? CONFIGURATION_FLNM
45 $stderr.puts "Error: no configuration file at ~/.bencher."
46 $stderr.puts "This file should contain paths to SunSpider, V8, and Kraken, as well as a"
47 $stderr.puts "temporary directory that bencher can use for its remote mode. It should be"
48 $stderr.puts "formatted in JSON. For example:"
49 $stderr.puts "{"
50 $stderr.puts " \"sunSpiderPath\": \"/Volumes/Data/pizlo/OpenSource/Performa nceTests/SunSpider/tests/sunspider-1.0\","
51 $stderr.puts " \"v8Path\": \"/Volumes/Data/pizlo/OpenSource/PerformanceTest s/SunSpider/tests/v8-v6\","
52 $stderr.puts " \"krakenPath\": \"/Volumes/Data/pizlo/kraken/kraken-e119421c b325/tests/kraken-1.1\","
53 $stderr.puts " \"tempPath\": \"/Volumes/Data/pizlo/bencher/temp\""
54 $stderr.puts "}"
55 exit 1
56 end
57
58 CONFIGURATION = JSON.parse(File::read(CONFIGURATION_FLNM))
59
60 SUNSPIDER_PATH = CONFIGURATION["sunSpiderPath"]
61 V8_PATH = CONFIGURATION["v8Path"]
62 KRAKEN_PATH = CONFIGURATION["krakenPath"]
63 TEMP_PATH = CONFIGURATION["tempPath"]
64 BENCH_DATA_PATH = TEMP_PATH + "/benchdata"
65
66 IBR_LOOKUP=[0.00615583, 0.0975, 0.22852, 0.341628, 0.430741, 0.500526, 0.555933,
67 0.600706, 0.637513, 0.668244, 0.694254, 0.716537, 0.735827, 0.752684 ,
68 0.767535, 0.780716, 0.792492, 0.803074, 0.812634, 0.821313, 0.829227 ,
69 0.836472, 0.843129, 0.849267, 0.854943, 0.860209, 0.865107, 0.869674 ,
70 0.873942, 0.877941, 0.881693, 0.885223, 0.888548, 0.891686, 0.894652 ,
71 0.897461, 0.900124, 0.902652, 0.905056, 0.907343, 0.909524, 0.911604 ,
72 0.91359, 0.91549, 0.917308, 0.919049, 0.920718, 0.92232, 0.923859, 0 .925338,
73 0.926761, 0.92813, 0.929449, 0.930721, 0.931948, 0.933132, 0.934275, 0.93538,
74 0.936449, 0.937483, 0.938483, 0.939452, 0.940392, 0.941302, 0.942185 ,
75 0.943042, 0.943874, 0.944682, 0.945467, 0.94623, 0.946972, 0.947694,
76 0.948396, 0.94908, 0.949746, 0.950395, 0.951027, 0.951643, 0.952244,
77 0.952831, 0.953403, 0.953961, 0.954506, 0.955039, 0.955559, 0.956067 ,
78 0.956563, 0.957049, 0.957524, 0.957988, 0.958443, 0.958887, 0.959323 ,
79 0.959749, 0.960166, 0.960575, 0.960975, 0.961368, 0.961752, 0.962129 ,
80 0.962499, 0.962861, 0.963217, 0.963566, 0.963908, 0.964244, 0.964574 ,
81 0.964897, 0.965215, 0.965527, 0.965834, 0.966135, 0.966431, 0.966722 ,
82 0.967007, 0.967288, 0.967564, 0.967836, 0.968103, 0.968366, 0.968624 ,
83 0.968878, 0.969128, 0.969374, 0.969617, 0.969855, 0.97009, 0.970321,
84 0.970548, 0.970772, 0.970993, 0.97121, 0.971425, 0.971636, 0.971843,
85 0.972048, 0.97225, 0.972449, 0.972645, 0.972839, 0.973029, 0.973217,
86 0.973403, 0.973586, 0.973766, 0.973944, 0.97412, 0.974293, 0.974464,
87 0.974632, 0.974799, 0.974963, 0.975125, 0.975285, 0.975443, 0.975599 ,
88 0.975753, 0.975905, 0.976055, 0.976204, 0.97635, 0.976495, 0.976638,
89 0.976779, 0.976918, 0.977056, 0.977193, 0.977327, 0.97746, 0.977592,
90 0.977722, 0.97785, 0.977977, 0.978103, 0.978227, 0.978349, 0.978471,
91 0.978591, 0.978709, 0.978827, 0.978943, 0.979058, 0.979171, 0.979283 ,
92 0.979395, 0.979504, 0.979613, 0.979721, 0.979827, 0.979933, 0.980037 ,
93 0.98014, 0.980242, 0.980343, 0.980443, 0.980543, 0.980641, 0.980738,
94 0.980834, 0.980929, 0.981023, 0.981116, 0.981209, 0.9813, 0.981391, 0.981481,
95 0.981569, 0.981657, 0.981745, 0.981831, 0.981916, 0.982001, 0.982085 ,
96 0.982168, 0.982251, 0.982332, 0.982413, 0.982493, 0.982573, 0.982651 ,
97 0.982729, 0.982807, 0.982883, 0.982959, 0.983034, 0.983109, 0.983183 ,
98 0.983256, 0.983329, 0.983401, 0.983472, 0.983543, 0.983613, 0.983683 ,
99 0.983752, 0.98382, 0.983888, 0.983956, 0.984022, 0.984089, 0.984154,
100 0.984219, 0.984284, 0.984348, 0.984411, 0.984474, 0.984537, 0.984599 ,
101 0.98466, 0.984721, 0.984782, 0.984842, 0.984902, 0.984961, 0.985019,
102 0.985077, 0.985135, 0.985193, 0.985249, 0.985306, 0.985362, 0.985417 ,
103 0.985472, 0.985527, 0.985582, 0.985635, 0.985689, 0.985742, 0.985795 ,
104 0.985847, 0.985899, 0.985951, 0.986002, 0.986053, 0.986103, 0.986153 ,
105 0.986203, 0.986252, 0.986301, 0.98635, 0.986398, 0.986446, 0.986494,
106 0.986541, 0.986588, 0.986635, 0.986681, 0.986727, 0.986773, 0.986818 ,
107 0.986863, 0.986908, 0.986953, 0.986997, 0.987041, 0.987084, 0.987128 ,
108 0.987171, 0.987213, 0.987256, 0.987298, 0.98734, 0.987381, 0.987423,
109 0.987464, 0.987504, 0.987545, 0.987585, 0.987625, 0.987665, 0.987704 ,
110 0.987744, 0.987783, 0.987821, 0.98786, 0.987898, 0.987936, 0.987974,
111 0.988011, 0.988049, 0.988086, 0.988123, 0.988159, 0.988196, 0.988232 ,
112 0.988268, 0.988303, 0.988339, 0.988374, 0.988409, 0.988444, 0.988479 ,
113 0.988513, 0.988547, 0.988582, 0.988615, 0.988649, 0.988682, 0.988716 ,
114 0.988749, 0.988782, 0.988814, 0.988847, 0.988879, 0.988911, 0.988943 ,
115 0.988975, 0.989006, 0.989038, 0.989069, 0.9891, 0.989131, 0.989161, 0.989192,
116 0.989222, 0.989252, 0.989282, 0.989312, 0.989342, 0.989371, 0.989401 ,
117 0.98943, 0.989459, 0.989488, 0.989516, 0.989545, 0.989573, 0.989602, 0.98963,
118 0.989658, 0.989685, 0.989713, 0.98974, 0.989768, 0.989795, 0.989822,
119 0.989849, 0.989876, 0.989902, 0.989929, 0.989955, 0.989981, 0.990007 ,
120 0.990033, 0.990059, 0.990085, 0.99011, 0.990136, 0.990161, 0.990186,
121 0.990211, 0.990236, 0.990261, 0.990285, 0.99031, 0.990334, 0.990358,
122 0.990383, 0.990407, 0.99043, 0.990454, 0.990478, 0.990501, 0.990525,
123 0.990548, 0.990571, 0.990594, 0.990617, 0.99064, 0.990663, 0.990686,
124 0.990708, 0.990731, 0.990753, 0.990775, 0.990797, 0.990819, 0.990841 ,
125 0.990863, 0.990885, 0.990906, 0.990928, 0.990949, 0.99097, 0.990991,
126 0.991013, 0.991034, 0.991054, 0.991075, 0.991096, 0.991116, 0.991137 ,
127 0.991157, 0.991178, 0.991198, 0.991218, 0.991238, 0.991258, 0.991278 ,
128 0.991298, 0.991317, 0.991337, 0.991356, 0.991376, 0.991395, 0.991414 ,
129 0.991433, 0.991452, 0.991471, 0.99149, 0.991509, 0.991528, 0.991547,
130 0.991565, 0.991584, 0.991602, 0.99162, 0.991639, 0.991657, 0.991675,
131 0.991693, 0.991711, 0.991729, 0.991746, 0.991764, 0.991782, 0.991799 ,
132 0.991817, 0.991834, 0.991851, 0.991869, 0.991886, 0.991903, 0.99192,
133 0.991937, 0.991954, 0.991971, 0.991987, 0.992004, 0.992021, 0.992037 ,
134 0.992054, 0.99207, 0.992086, 0.992103, 0.992119, 0.992135, 0.992151,
135 0.992167, 0.992183, 0.992199, 0.992215, 0.99223, 0.992246, 0.992262,
136 0.992277, 0.992293, 0.992308, 0.992324, 0.992339, 0.992354, 0.992369 ,
137 0.992384, 0.9924, 0.992415, 0.992429, 0.992444, 0.992459, 0.992474, 0.992489,
138 0.992503, 0.992518, 0.992533, 0.992547, 0.992561, 0.992576, 0.99259,
139 0.992604, 0.992619, 0.992633, 0.992647, 0.992661, 0.992675, 0.992689 ,
140 0.992703, 0.992717, 0.99273, 0.992744, 0.992758, 0.992771, 0.992785,
141 0.992798, 0.992812, 0.992825, 0.992839, 0.992852, 0.992865, 0.992879 ,
142 0.992892, 0.992905, 0.992918, 0.992931, 0.992944, 0.992957, 0.99297,
143 0.992983, 0.992995, 0.993008, 0.993021, 0.993034, 0.993046, 0.993059 ,
144 0.993071, 0.993084, 0.993096, 0.993109, 0.993121, 0.993133, 0.993145 ,
145 0.993158, 0.99317, 0.993182, 0.993194, 0.993206, 0.993218, 0.99323, 0.993242,
146 0.993254, 0.993266, 0.993277, 0.993289, 0.993301, 0.993312, 0.993324 ,
147 0.993336, 0.993347, 0.993359, 0.99337, 0.993382, 0.993393, 0.993404,
148 0.993416, 0.993427, 0.993438, 0.993449, 0.99346, 0.993472, 0.993483,
149 0.993494, 0.993505, 0.993516, 0.993527, 0.993538, 0.993548, 0.993559 ,
150 0.99357, 0.993581, 0.993591, 0.993602, 0.993613, 0.993623, 0.993634,
151 0.993644, 0.993655, 0.993665, 0.993676, 0.993686, 0.993697, 0.993707 ,
152 0.993717, 0.993727, 0.993738, 0.993748, 0.993758, 0.993768, 0.993778 ,
153 0.993788, 0.993798, 0.993808, 0.993818, 0.993828, 0.993838, 0.993848 ,
154 0.993858, 0.993868, 0.993877, 0.993887, 0.993897, 0.993907, 0.993916 ,
155 0.993926, 0.993935, 0.993945, 0.993954, 0.993964, 0.993973, 0.993983 ,
156 0.993992, 0.994002, 0.994011, 0.99402, 0.99403, 0.994039, 0.994048, 0.994057,
157 0.994067, 0.994076, 0.994085, 0.994094, 0.994103, 0.994112, 0.994121 ,
158 0.99413, 0.994139, 0.994148, 0.994157, 0.994166, 0.994175, 0.994183,
159 0.994192, 0.994201, 0.99421, 0.994218, 0.994227, 0.994236, 0.994244,
160 0.994253, 0.994262, 0.99427, 0.994279, 0.994287, 0.994296, 0.994304,
161 0.994313, 0.994321, 0.994329, 0.994338, 0.994346, 0.994354, 0.994363 ,
162 0.994371, 0.994379, 0.994387, 0.994395, 0.994404, 0.994412, 0.99442,
163 0.994428, 0.994436, 0.994444, 0.994452, 0.99446, 0.994468, 0.994476,
164 0.994484, 0.994492, 0.9945, 0.994508, 0.994516, 0.994523, 0.994531, 0.994539,
165 0.994547, 0.994554, 0.994562, 0.99457, 0.994577, 0.994585, 0.994593, 0.9946,
166 0.994608, 0.994615, 0.994623, 0.994631, 0.994638, 0.994645, 0.994653 ,
167 0.99466, 0.994668, 0.994675, 0.994683, 0.99469, 0.994697, 0.994705, 0.994712,
168 0.994719, 0.994726, 0.994734, 0.994741, 0.994748, 0.994755, 0.994762 ,
169 0.994769, 0.994777, 0.994784, 0.994791, 0.994798, 0.994805, 0.994812 ,
170 0.994819, 0.994826, 0.994833, 0.99484, 0.994847, 0.994854, 0.99486, 0.994867,
171 0.994874, 0.994881, 0.994888, 0.994895, 0.994901, 0.994908, 0.994915 ,
172 0.994922, 0.994928, 0.994935, 0.994942, 0.994948, 0.994955, 0.994962 ,
173 0.994968, 0.994975, 0.994981, 0.994988, 0.994994, 0.995001, 0.995007 ,
174 0.995014, 0.99502, 0.995027, 0.995033, 0.99504, 0.995046, 0.995052, 0.995059,
175 0.995065, 0.995071, 0.995078, 0.995084, 0.99509, 0.995097, 0.995103,
176 0.995109, 0.995115, 0.995121, 0.995128, 0.995134, 0.99514, 0.995146,
177 0.995152, 0.995158, 0.995164, 0.995171, 0.995177, 0.995183, 0.995189 ,
178 0.995195, 0.995201, 0.995207, 0.995213, 0.995219, 0.995225, 0.995231 ,
179 0.995236, 0.995242, 0.995248, 0.995254, 0.99526, 0.995266, 0.995272,
180 0.995277, 0.995283, 0.995289, 0.995295, 0.995301, 0.995306, 0.995312 ,
181 0.995318, 0.995323, 0.995329, 0.995335, 0.99534, 0.995346, 0.995352,
182 0.995357, 0.995363, 0.995369, 0.995374, 0.99538, 0.995385, 0.995391,
183 0.995396, 0.995402, 0.995407, 0.995413, 0.995418, 0.995424, 0.995429 ,
184 0.995435, 0.99544, 0.995445, 0.995451, 0.995456, 0.995462, 0.995467,
185 0.995472, 0.995478, 0.995483, 0.995488, 0.995493, 0.995499, 0.995504 ,
186 0.995509, 0.995515, 0.99552, 0.995525, 0.99553, 0.995535, 0.995541, 0.995546,
187 0.995551, 0.995556, 0.995561, 0.995566, 0.995571, 0.995577, 0.995582 ,
188 0.995587, 0.995592, 0.995597, 0.995602, 0.995607, 0.995612, 0.995617 ,
189 0.995622, 0.995627, 0.995632, 0.995637, 0.995642, 0.995647, 0.995652 ,
190 0.995657, 0.995661, 0.995666, 0.995671, 0.995676, 0.995681, 0.995686 ,
191 0.995691, 0.995695, 0.9957, 0.995705, 0.99571, 0.995715, 0.995719, 0 .995724,
192 0.995729, 0.995734, 0.995738, 0.995743, 0.995748, 0.995753, 0.995757 ,
193 0.995762, 0.995767, 0.995771, 0.995776, 0.995781, 0.995785, 0.99579,
194 0.995794, 0.995799, 0.995804, 0.995808, 0.995813, 0.995817, 0.995822 ,
195 0.995826, 0.995831, 0.995835, 0.99584, 0.995844, 0.995849, 0.995853,
196 0.995858, 0.995862, 0.995867, 0.995871, 0.995876, 0.99588, 0.995885,
197 0.995889, 0.995893, 0.995898, 0.995902, 0.995906, 0.995911, 0.995915 ,
198 0.99592, 0.995924, 0.995928, 0.995932, 0.995937, 0.995941, 0.995945, 0.99595,
199 0.995954, 0.995958, 0.995962, 0.995967, 0.995971, 0.995975, 0.995979 ,
200 0.995984, 0.995988, 0.995992, 0.995996, 0.996, 0.996004, 0.996009, 0 .996013,
201 0.996017, 0.996021, 0.996025, 0.996029, 0.996033, 0.996037, 0.996041 ,
202 0.996046, 0.99605, 0.996054, 0.996058, 0.996062, 0.996066, 0.99607, 0.996074,
203 0.996078, 0.996082, 0.996086, 0.99609, 0.996094, 0.996098, 0.996102,
204 0.996106, 0.99611, 0.996114, 0.996117, 0.996121, 0.996125, 0.996129,
205 0.996133, 0.996137, 0.996141, 0.996145, 0.996149, 0.996152, 0.996156 ,
206 0.99616, 0.996164]
207
208 # Run-time configuration parameters (can be set with command-line options)
209
210 $rerun=1
211 $inner=3
212 $warmup=1
213 $outer=4
214 $includeSunSpider=true
215 $includeV8=true
216 $includeKraken=true
217 $measureGC=false
218 $benchmarkPattern=nil
219 $verbosity=0
220 $timeMode=:preciseTime
221 $forceVMKind=nil
222 $brief=false
223 $silent=false
224 $remoteHosts=[]
225 $alsoLocal=false
226 $sshOptions=[]
227 $vms = []
228 $needToCopyVMs = false
229 $dontCopyVMs = false
230
231 $prepare = true
232 $run = true
233 $analyze = []
234
235 # Helpful functions and classes
236
237 def smallUsage
238 puts "Use the --help option to get basic usage information."
239 exit 1
240 end
241
242 def usage
243 puts "bencher [options] <vm1> [<vm2> ...]"
244 puts
245 puts "Runs one or more JavaScript runtimes against SunSpider, V8, and/or Krake n"
246 puts "benchmarks, and reports detailed statistics. What makes bencher special is"
247 puts "that each benchmark/VM configuration is run in a single VM invocation, a nd"
248 puts "the invocations are run in random order. This minimizes systematics due to"
249 puts "one benchmark polluting the running time of another. The fine-grained"
250 puts "interleaving of VM invocations further minimizes systematics due to chan ges in"
251 puts "the performance or behavior of your machine."
252 puts
253 puts "Bencher is highly configurable. You can compare as many VMs as you like . You"
254 puts "can change the amount of warm-up iterations, number of iterations execut ed per"
255 puts "VM invocation, and the number of VM invocations per benchmark. By defau lt,"
256 puts "SunSpider, VM, and Kraken are all run; but you can run any combination o f these"
257 puts "suites."
258 puts
259 puts "The <vm> should be either a path to a JavaScript runtime executable (suc h as"
260 puts "jsc), or a string of the form <name>:<path>, where the <path> is the pat h to"
261 puts "the executable and <name> is the name that you would like to give the"
262 puts "configuration for the purposeof reporting. If no name is given, a gener ic name"
263 puts "of the form Conf#<n> will be ascribed to the configuration automatically ."
264 puts
265 puts "Options:"
266 puts "--rerun <n> Set the number of iterations of the benchmark that"
267 puts " contribute to the measured run time. Default is #{ $rerun}."
268 puts "--inner <n> Set the number of inner (per-runtime-invocation)"
269 puts " iterations. Default is #{$inner}."
270 puts "--outer <n> Set the number of runtime invocations for each benc hmark."
271 puts " Default is #{$outer}."
272 puts "--warmup <n> Set the number of warm-up runs per invocation. Def ault"
273 puts " is #{$warmup}."
274 puts "--timing-mode Set the way that bencher measures time. Possible v alues"
275 puts " are 'preciseTime' and 'date'. Default is 'preciseT ime'."
276 puts "--force-vm-kind Turn off auto-detection of VM kind, and assume that it is"
277 puts " the one specified. Valid arguments are 'jsc' or"
278 puts " 'DumpRenderTree'."
279 puts "--force-vm-copy Force VM builds to be copied to bencher's working d irectory."
280 puts " This may reduce pathologies resulting from path nam es."
281 puts "--dont-copy-vms Don't copy VMs even when doing a remote benchmarkin g run;"
282 puts " instead assume that they are already there."
283 puts "--v8-only Only run V8."
284 puts "--sunspider-only Only run SunSpider."
285 puts "--kraken-only Only run Kraken."
286 puts "--exclude-v8 Exclude V8 (only run SunSpider and Kraken)."
287 puts "--exclude-sunspider Exclude SunSpider (only run V8 and Kraken)."
288 puts "--exclude-kraken Exclude Kraken (only run SunSpider and V8)."
289 puts "--benchmarks Only run benchmarks matching the given regular expr ession."
290 puts "--measure-gc Turn off manual calls to gc(), so that GC time is m easured."
291 puts " Works best with large values of --inner. You can a lso say"
292 puts " --measure-gc <conf>, which turns this on for one"
293 puts " configuration only."
294 puts "--verbose or -v Print more stuff."
295 puts "--brief Print only the final result for each VM."
296 puts "--silent Don't print progress. This might slightly reduce so me"
297 puts " performance perturbation."
298 puts "--remote <sshhosts> Performance performance measurements remotely, on t he given"
299 puts " SSH host(s). Easiest way to use this is to specify the SSH"
300 puts " user@host string. However, you can also supply a co mma-"
301 puts " separated list of SSH hosts. Alternatively, you can use this"
302 puts " option multiple times to specify multiple hosts. Th is"
303 puts " automatically copies the WebKit release builds of t he VMs"
304 puts " you specified to all of the hosts."
305 puts "--ssh-options Pass additional options to SSH."
306 puts "--local Also do a local benchmark run even when doing --rem ote."
307 puts "--prepare-only Only prepare the bencher runscript (a shell script that"
308 puts " invokes the VMs to run benchmarks) but don't run it ."
309 puts "--analyze Only read the output of the runscript but don't do anything"
310 puts " else. This requires passing the same arguments to b encher"
311 puts " that you passed when running --prepare-only."
312 puts "--help or -h Display this message."
313 puts
314 puts "Example:"
315 puts "bencher TipOfTree:/Volumes/Data/pizlo/OpenSource/WebKitBuild/Release/jsc MyChanges:/Volumes/Data/pizlo/secondary/OpenSource/WebKitBuild/Release/jsc"
316 exit 1
317 end
318
319 def fail(reason)
320 if reason.respond_to? :backtrace
321 puts "FAILED: #{reason}"
322 puts "Stack trace:"
323 puts reason.backtrace.join("\n")
324 else
325 puts "FAILED: #{reason}"
326 end
327 smallUsage
328 end
329
330 def quickFail(r1,r2)
331 $stderr.puts "#{$0}: #{r1}"
332 puts
333 fail(r2)
334 end
335
336 def intArg(argName,arg,min,max)
337 result=arg.to_i
338 unless result.to_s == arg
339 quickFail("Expected an integer value for #{argName}, but got #{arg}.",
340 "Invalid argument for command-line option")
341 end
342 if min and result<min
343 quickFail("Argument for #{argName} cannot be smaller than #{min}.",
344 "Invalid argument for command-line option")
345 end
346 if max and result>max
347 quickFail("Argument for #{argName} cannot be greater than #{max}.",
348 "Invalid argument for command-line option")
349 end
350 result
351 end
352
353 def computeMean(array)
354 sum=0.0
355 array.each {
356 | value |
357 sum += value
358 }
359 sum/array.length
360 end
361
362 def computeGeometricMean(array)
363 mult=1.0
364 array.each {
365 | value |
366 mult*=value
367 }
368 mult**(1.0/array.length)
369 end
370
371 def computeHarmonicMean(array)
372 1.0 / computeMean(array.collect{ | value | 1.0 / value })
373 end
374
375 def computeStdDev(array)
376 case array.length
377 when 0
378 0.0/0.0
379 when 1
380 0.0
381 else
382 begin
383 mean=computeMean(array)
384 sum=0.0
385 array.each {
386 | value |
387 sum += (value-mean)**2
388 }
389 Math.sqrt(sum/(array.length-1))
390 rescue
391 0.0/0.0
392 end
393 end
394 end
395
396 class Array
397 def shuffle!
398 size.downto(1) { |n| push delete_at(rand(n)) }
399 self
400 end
401 end
402
403 def inverseBetaRegularized(n)
404 IBR_LOOKUP[n-1]
405 end
406
407 def numToStr(num)
408 "%.4f"%(num.to_f)
409 end
410
411 class NoChange
412 attr_reader :amountFaster
413
414 def initialize(amountFaster)
415 @amountFaster = amountFaster
416 end
417
418 def shortForm
419 " "
420 end
421
422 def longForm
423 " might be #{numToStr(@amountFaster)}x faster"
424 end
425
426 def to_s
427 if @amountFaster < 1.01
428 ""
429 else
430 longForm
431 end
432 end
433 end
434
435 class Faster
436 attr_reader :amountFaster
437
438 def initialize(amountFaster)
439 @amountFaster = amountFaster
440 end
441
442 def shortForm
443 "^"
444 end
445
446 def longForm
447 "^ definitely #{numToStr(@amountFaster)}x faster"
448 end
449
450 def to_s
451 longForm
452 end
453 end
454
455 class Slower
456 attr_reader :amountSlower
457
458 def initialize(amountSlower)
459 @amountSlower = amountSlower
460 end
461
462 def shortForm
463 "!"
464 end
465
466 def longForm
467 "! definitely #{numToStr(@amountSlower)}x slower"
468 end
469
470 def to_s
471 longForm
472 end
473 end
474
475 class MayBeSlower
476 attr_reader :amountSlower
477
478 def initialize(amountSlower)
479 @amountSlower = amountSlower
480 end
481
482 def shortForm
483 "?"
484 end
485
486 def longForm
487 "? might be #{numToStr(@amountSlower)}x slower"
488 end
489
490 def to_s
491 if @amountSlower < 1.01
492 "?"
493 else
494 longForm
495 end
496 end
497 end
498
499 class Stats
500 def initialize
501 @array = []
502 end
503
504 def add(value)
505 if value.is_a? Stats
506 add(value.array)
507 elsif value.respond_to? :each
508 value.each {
509 | v |
510 add(v)
511 }
512 else
513 @array << value.to_f
514 end
515 end
516
517 def array
518 @array
519 end
520
521 def sum
522 result=0
523 @array.each {
524 | value |
525 result += value
526 }
527 result
528 end
529
530 def min
531 @array.min
532 end
533
534 def max
535 @array.max
536 end
537
538 def size
539 @array.length
540 end
541
542 def mean
543 computeMean(array)
544 end
545
546 def arithmeticMean
547 mean
548 end
549
550 def stdDev
551 computeStdDev(array)
552 end
553
554 def stdErr
555 stdDev/Math.sqrt(size)
556 end
557
558 # Computes a 95% Student's t distribution confidence interval
559 def confInt
560 if size < 2
561 0.0/0.0
562 else
563 raise if size > 1000
564 Math.sqrt(size-1.0)*stdErr*Math.sqrt(-1.0+1.0/inverseBetaRegularized(size- 1))
565 end
566 end
567
568 def lower
569 mean-confInt
570 end
571
572 def upper
573 mean+confInt
574 end
575
576 def geometricMean
577 computeGeometricMean(array)
578 end
579
580 def harmonicMean
581 computeHarmonicMean(array)
582 end
583
584 def compareTo(other)
585 if upper < other.lower
586 Faster.new(other.mean/mean)
587 elsif lower > other.upper
588 Slower.new(mean/other.mean)
589 elsif mean > other.mean
590 MayBeSlower.new(mean/other.mean)
591 else
592 NoChange.new(other.mean/mean)
593 end
594 end
595
596 def to_s
597 "size = #{size}, mean = #{mean}, stdDev = #{stdDev}, stdErr = #{stdErr}, con fInt = #{confInt}"
598 end
599 end
600
601 def doublePuts(out1,out2,msg)
602 out1.puts "#{out2.path}: #{msg}" if $verbosity>=3
603 out2.puts msg
604 end
605
606 class Benchfile < File
607 @@counter = 0
608
609 attr_reader :filename, :basename
610
611 def initialize(name)
612 @basename, @filename = Benchfile.uniqueFilename(name)
613 super(@filename, "w")
614 end
615
616 def self.uniqueFilename(name)
617 if name.is_a? Array
618 basename = name[0] + @@counter.to_s + name[1]
619 else
620 basename = name + @@counter.to_s
621 end
622 filename = BENCH_DATA_PATH + "/" + basename
623 @@counter += 1
624 raise "Benchfile #{filename} already exists" if FileTest.exist?(filename)
625 [basename, filename]
626 end
627
628 def self.create(name)
629 file = Benchfile.new(name)
630 yield file
631 file.close
632 file.basename
633 end
634 end
635
636 $dataFiles={}
637 def ensureFile(key, filename)
638 unless $dataFiles[key]
639 $dataFiles[key] = Benchfile.create(key) {
640 | outp |
641 doublePuts($stderr,outp,IO::read(filename))
642 }
643 end
644 $dataFiles[key]
645 end
646
647 def emitBenchRunCodeFile(name, plan, benchDataPath, benchPath)
648 case plan.vm.vmType
649 when :jsc
650 Benchfile.create("bencher") {
651 | file |
652 case $timeMode
653 when :preciseTime
654 doublePuts($stderr,file,"function __bencher_curTimeMS() {")
655 doublePuts($stderr,file," return preciseTime()*1000")
656 doublePuts($stderr,file,"}")
657 when :date
658 doublePuts($stderr,file,"function __bencher_curTimeMS() {")
659 doublePuts($stderr,file," return Date.now()")
660 doublePuts($stderr,file,"}")
661 else
662 raise
663 end
664
665 if benchDataPath
666 doublePuts($stderr,file,"load(#{benchDataPath.inspect});")
667 doublePuts($stderr,file,"gc();")
668 doublePuts($stderr,file,"for (var __bencher_index = 0; __bencher_index < #{$warmup+$inner}; ++__bencher_index) {")
669 doublePuts($stderr,file," before = __bencher_curTimeMS();")
670 $rerun.times {
671 doublePuts($stderr,file," load(#{benchPath.inspect});")
672 }
673 doublePuts($stderr,file," after = __bencher_curTimeMS();")
674 doublePuts($stderr,file," if (__bencher_index >= #{$warmup}) print(\"# {name}: #{plan.vm}: #{plan.iteration}: \" + (__bencher_index - #{$warmup}) + \": Time: \"+(after-before));");
675 doublePuts($stderr,file," gc();") unless plan.vm.shouldMeasureGC
676 doublePuts($stderr,file,"}")
677 else
678 doublePuts($stderr,file,"function __bencher_run(__bencher_what) {")
679 doublePuts($stderr,file," var __bencher_before = __bencher_curTimeMS() ;")
680 $rerun.times {
681 doublePuts($stderr,file," run(__bencher_what);")
682 }
683 doublePuts($stderr,file," var __bencher_after = __bencher_curTimeMS(); ")
684 doublePuts($stderr,file," return __bencher_after - __bencher_before;")
685 doublePuts($stderr,file,"}")
686 $warmup.times {
687 doublePuts($stderr,file,"__bencher_run(#{benchPath.inspect})")
688 doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC
689 }
690 $inner.times {
691 | innerIndex |
692 doublePuts($stderr,file,"print(\"#{name}: #{plan.vm}: #{plan.iteration }: #{innerIndex}: Time: \"+__bencher_run(#{benchPath.inspect}));")
693 doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC
694 }
695 end
696 }
697 when :dumpRenderTree
698 mainCode = Benchfile.create("bencher") {
699 | file |
700 doublePuts($stderr,file,"__bencher_count = 0;")
701 doublePuts($stderr,file,"function __bencher_doNext(result) {")
702 doublePuts($stderr,file," if (__bencher_count >= #{$warmup})")
703 doublePuts($stderr,file," debug(\"#{name}: #{plan.vm}: #{plan.itera tion}: \" + (__bencher_count - #{$warmup}) + \": Time: \" + result);")
704 doublePuts($stderr,file," __bencher_count++;")
705 doublePuts($stderr,file," if (__bencher_count < #{$inner+$warmup})")
706 doublePuts($stderr,file," __bencher_runImpl(__bencher_doNext);")
707 doublePuts($stderr,file," else")
708 doublePuts($stderr,file," quit();")
709 doublePuts($stderr,file,"}")
710 doublePuts($stderr,file,"__bencher_runImpl(__bencher_doNext);")
711 }
712
713 cssCode = Benchfile.create("bencher-css") {
714 | file |
715 doublePuts($stderr,file,".pass {\n font-weight: bold;\n color: green ;\n}\n.fail {\n font-weight: bold;\n color: red;\n}\n\#console {\n whit e-space: pre-wrap;\n font-family: monospace;\n}")
716 }
717
718 preCode = Benchfile.create("bencher-pre") {
719 | file |
720 doublePuts($stderr,file,"if (window.testRunner) {")
721 doublePuts($stderr,file," if (window.enablePixelTesting) {")
722 doublePuts($stderr,file," testRunner.dumpAsTextWithPixelResults();" )
723 doublePuts($stderr,file," } else {")
724 doublePuts($stderr,file," testRunner.dumpAsText();")
725 doublePuts($stderr,file," }")
726 doublePuts($stderr,file,"}")
727 doublePuts($stderr,file,"")
728 doublePuts($stderr,file,"function debug(msg)")
729 doublePuts($stderr,file,"{")
730 doublePuts($stderr,file," var span = document.createElement(\"span\");" )
731 doublePuts($stderr,file," document.getElementById(\"console\").appendCh ild(span); // insert it first so XHTML knows the namespace")
732 doublePuts($stderr,file," span.innerHTML = msg + '<br />';")
733 doublePuts($stderr,file,"}")
734 doublePuts($stderr,file,"")
735 doublePuts($stderr,file,"function quit() {")
736 doublePuts($stderr,file," testRunner.notifyDone();")
737 doublePuts($stderr,file,"}")
738 doublePuts($stderr,file,"")
739 doublePuts($stderr,file,"__bencher_continuation=null;")
740 doublePuts($stderr,file,"")
741 doublePuts($stderr,file,"function reportResult(result) {")
742 doublePuts($stderr,file," __bencher_continuation(result);")
743 doublePuts($stderr,file,"}")
744 doublePuts($stderr,file,"")
745 doublePuts($stderr,file,"function __bencher_runImpl(continuation) {")
746 doublePuts($stderr,file," function doit() {")
747 doublePuts($stderr,file," document.getElementById(\"frameparent\"). innerHTML = \"\";")
748 doublePuts($stderr,file," document.getElementById(\"frameparent\"). innerHTML = \"<iframe id='testframe'>\";")
749 doublePuts($stderr,file," var testFrame = document.getElementById(\ "testframe\");")
750 doublePuts($stderr,file," testFrame.contentDocument.open();")
751 doublePuts($stderr,file," testFrame.contentDocument.write(\"<!DOCTY PE html>\\n<head></head><body><div id=\\\"console\\\"></div>\");")
752 if benchDataPath
753 doublePuts($stderr,file," testFrame.contentDocument.write(\"<scri pt src=\\\"#{benchDataPath}\\\"></script>\");")
754 end
755 doublePuts($stderr,file," testFrame.contentDocument.write(\"<script type=\\\"text/javascript\\\">__bencher_before = Date.now();</script><script src =\\\"#{benchPath}\\\"></script><script type=\\\"text/javascript\\\">window.paren t.reportResult(Date.now() - __bencher_before);</script></body></html>\");")
756 doublePuts($stderr,file," testFrame.contentDocument.close();")
757 doublePuts($stderr,file," }")
758 doublePuts($stderr,file," __bencher_continuation = continuation;")
759 doublePuts($stderr,file," window.setTimeout(doit, 10);")
760 doublePuts($stderr,file,"}")
761 }
762
763 Benchfile.create(["bencher-htmldoc",".html"]) {
764 | file |
765 doublePuts($stderr,file,"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\ n<html><head><link rel=\"stylesheet\" href=\"#{cssCode}\"><script src=\"#{preCod e}\"></script></head><body><div id=\"console\"></div><div id=\"frameparent\"></d iv><script src=\"#{mainCode}\"></script></body></html>")
766 }
767 else
768 raise
769 end
770 end
771
772 def emitBenchRunCode(name, plan, benchDataPath, benchPath)
773 plan.vm.emitRunCode(emitBenchRunCodeFile(name, plan, benchDataPath, benchPath) )
774 end
775
776 def planForDescription(plans, benchFullname, vmName, iteration)
777 raise unless benchFullname =~ /\//
778 suiteName = $~.pre_match
779 benchName = $~.post_match
780 result = plans.select{|v| v.suite.name == suiteName and v.benchmark.name == be nchName and v.vm.name == vmName and v.iteration == iteration}
781 raise unless result.size == 1
782 result[0]
783 end
784
785 class ParsedResult
786 attr_reader :plan, :innerIndex, :time
787
788 def initialize(plan, innerIndex, time)
789 @plan = plan
790 @innerIndex = innerIndex
791 @time = time
792
793 raise unless @plan.is_a? BenchPlan
794 raise unless @innerIndex.is_a? Integer
795 raise unless @time.is_a? Numeric
796 end
797
798 def benchmark
799 plan.benchmark
800 end
801
802 def suite
803 plan.suite
804 end
805
806 def vm
807 plan.vm
808 end
809
810 def outerIndex
811 plan.iteration
812 end
813
814 def self.parse(plans, string)
815 if string =~ /([a-zA-Z0-9\/-]+): ([a-zA-Z0-9_# ]+): ([0-9]+): ([0-9]+): Time : /
816 benchFullname = $1
817 vmName = $2
818 outerIndex = $3.to_i
819 innerIndex = $4.to_i
820 time = $~.post_match.to_f
821 ParsedResult.new(planForDescription(plans, benchFullname, vmName, outerInd ex), innerIndex, time)
822 else
823 nil
824 end
825 end
826 end
827
828 class VM
829 def initialize(origPath, name, nameKind, svnRevision)
830 @origPath = origPath.to_s
831 @path = origPath.to_s
832 @name = name
833 @nameKind = nameKind
834
835 if $forceVMKind
836 @vmType = $forceVMKind
837 else
838 if @origPath =~ /DumpRenderTree$/
839 @vmType = :dumpRenderTree
840 else
841 @vmType = :jsc
842 end
843 end
844
845 @svnRevision = svnRevision
846
847 # Try to detect information about the VM.
848 if path =~ /\/WebKitBuild\/Release\/([a-zA-Z]+)$/
849 @checkoutPath = $~.pre_match
850 # FIXME: Use some variant of this:
851 # <bdash> def retrieve_revision
852 # <bdash> `perl -I#{@path}/Tools/Scripts -MVCSUtils -e 'print svnRevis ionForDirectory("#{@path}");'`.to_i
853 # <bdash> end
854 unless @svnRevision
855 begin
856 Dir.chdir(@checkoutPath) {
857 $stderr.puts ">> cd #{@checkoutPath} && svn info" if $verbosity>=2
858 IO.popen("svn info", "r") {
859 | inp |
860 inp.each_line {
861 | line |
862 if line =~ /Revision: ([0-9]+)/
863 @svnRevision = $1
864 end
865 }
866 }
867 }
868 unless @svnRevision
869 $stderr.puts "Warning: running svn info for #{name} silently failed. "
870 end
871 rescue => e
872 # Failed to detect svn revision.
873 $stderr.puts "Warning: could not get svn revision information for #{na me}: #{e}"
874 end
875 end
876 else
877 $stderr.puts "Warning: could not identify checkout location for #{name}"
878 end
879
880 if @path =~ /\/Release\/([a-zA-Z]+)$/
881 @libPath, @relativeBinPath = $~.pre_match+"/Release", "./#{$1}"
882 elsif @path =~ /\/Contents\/Resources\/([a-zA-Z]+)$/
883 @libPath = $~.pre_match
884 elsif @path =~ /\/JavaScriptCore.framework\/Resources\/([a-zA-Z]+)$/
885 @libPath, @relativeBinPath = $~.pre_match, $&[1..-1]
886 end
887 end
888
889 def canCopyIntoBenchPath
890 if @libPath and @relativeBinPath
891 true
892 else
893 false
894 end
895 end
896
897 def copyIntoBenchPath
898 raise unless canCopyIntoBenchPath
899 basename, filename = Benchfile.uniqueFilename("vm")
900 raise unless Dir.mkdir(filename)
901 cmd = "cp -a #{@libPath.inspect}/* #{filename.inspect}"
902 $stderr.puts ">> #{cmd}" if $verbosity>=2
903 raise unless system(cmd)
904 @path = "#{basename}/#{@relativeBinPath}"
905 @libPath = basename
906 end
907
908 def to_s
909 @name
910 end
911
912 def name
913 @name
914 end
915
916 def shouldMeasureGC
917 $measureGC == true or ($measureGC == name)
918 end
919
920 def origPath
921 @origPath
922 end
923
924 def path
925 @path
926 end
927
928 def nameKind
929 @nameKind
930 end
931
932 def vmType
933 @vmType
934 end
935
936 def checkoutPath
937 @checkoutPath
938 end
939
940 def svnRevision
941 @svnRevision
942 end
943
944 def printFunction
945 case @vmType
946 when :jsc
947 "print"
948 when :dumpRenderTree
949 "debug"
950 else
951 raise @vmType
952 end
953 end
954
955 def emitRunCode(fileToRun)
956 myLibPath = @libPath
957 myLibPath = "" unless myLibPath
958 $script.puts "export DYLD_LIBRARY_PATH=#{myLibPath.to_s.inspect}"
959 $script.puts "export DYLD_FRAMEWORK_PATH=#{myLibPath.to_s.inspect}"
960 $script.puts "#{path} #{fileToRun}"
961 end
962 end
963
964 class StatsAccumulator
965 def initialize
966 @stats = []
967 ($outer*$inner).times {
968 @stats << Stats.new
969 }
970 end
971
972 def statsForIteration(outerIteration, innerIteration)
973 @stats[outerIteration*$inner + innerIteration]
974 end
975
976 def stats
977 result = Stats.new
978 @stats.each {
979 | stat |
980 result.add(yield stat)
981 }
982 result
983 end
984
985 def geometricMeanStats
986 stats {
987 | stat |
988 stat.geometricMean
989 }
990 end
991
992 def arithmeticMeanStats
993 stats {
994 | stat |
995 stat.arithmeticMean
996 }
997 end
998 end
999
1000 module Benchmark
1001 attr_accessor :benchmarkSuite
1002 attr_reader :name
1003
1004 def fullname
1005 benchmarkSuite.name + "/" + name
1006 end
1007
1008 def to_s
1009 fullname
1010 end
1011 end
1012
1013 class SunSpiderBenchmark
1014 include Benchmark
1015
1016 def initialize(name)
1017 @name = name
1018 end
1019
1020 def emitRunCode(plan)
1021 emitBenchRunCode(fullname, plan, nil, ensureFile("SunSpider-#{@name}", "#{SU NSPIDER_PATH}/#{@name}.js"))
1022 end
1023 end
1024
1025 class V8Benchmark
1026 include Benchmark
1027
1028 def initialize(name)
1029 @name = name
1030 end
1031
1032 def emitRunCode(plan)
1033 emitBenchRunCode(fullname, plan, nil, ensureFile("V8-#{@name}", "#{V8_PATH}/ v8-#{@name}.js"))
1034 end
1035 end
1036
1037 class KrakenBenchmark
1038 include Benchmark
1039
1040 def initialize(name)
1041 @name = name
1042 end
1043
1044 def emitRunCode(plan)
1045 emitBenchRunCode(fullname, plan, ensureFile("KrakenData-#{@name}", "#{KRAKEN _PATH}/#{@name}-data.js"), ensureFile("Kraken-#{@name}", "#{KRAKEN_PATH}/#{@name }.js"))
1046 end
1047 end
1048
1049 class BenchmarkSuite
1050 def initialize(name, path, preferredMean)
1051 @name = name
1052 @path = path
1053 @preferredMean = preferredMean
1054 @benchmarks = []
1055 end
1056
1057 def name
1058 @name
1059 end
1060
1061 def to_s
1062 @name
1063 end
1064
1065 def path
1066 @path
1067 end
1068
1069 def add(benchmark)
1070 if not $benchmarkPattern or "#{@name}/#{benchmark.name}" =~ $benchmarkPatter n
1071 benchmark.benchmarkSuite = self
1072 @benchmarks << benchmark
1073 end
1074 end
1075
1076 def benchmarks
1077 @benchmarks
1078 end
1079
1080 def benchmarkForName(name)
1081 result = @benchmarks.select{|v| v.name == name}
1082 raise unless result.length == 1
1083 result[0]
1084 end
1085
1086 def empty?
1087 @benchmarks.empty?
1088 end
1089
1090 def retain_if
1091 @benchmarks.delete_if {
1092 | benchmark |
1093 not yield benchmark
1094 }
1095 end
1096
1097 def preferredMean
1098 @preferredMean
1099 end
1100
1101 def computeMean(stat)
1102 stat.send @preferredMean
1103 end
1104 end
1105
1106 class BenchRunPlan
1107 def initialize(benchmark, vm, iteration)
1108 @benchmark = benchmark
1109 @vm = vm
1110 @iteration = iteration
1111 end
1112
1113 def benchmark
1114 @benchmark
1115 end
1116
1117 def suite
1118 @benchmark.benchmarkSuite
1119 end
1120
1121 def vm
1122 @vm
1123 end
1124
1125 def iteration
1126 @iteration
1127 end
1128
1129 def emitRunCode
1130 @benchmark.emitRunCode(self)
1131 end
1132 end
1133
1134 class BenchmarkOnVM
1135 def initialize(benchmark, suiteOnVM)
1136 @benchmark = benchmark
1137 @suiteOnVM = suiteOnVM
1138 @stats = Stats.new
1139 end
1140
1141 def to_s
1142 "#{@benchmark} on #{@suiteOnVM.vm}"
1143 end
1144
1145 def benchmark
1146 @benchmark
1147 end
1148
1149 def vm
1150 @suiteOnVM.vm
1151 end
1152
1153 def vmStats
1154 @suiteOnVM.vmStats
1155 end
1156
1157 def suite
1158 @benchmark.benchmarkSuite
1159 end
1160
1161 def suiteOnVM
1162 @suiteOnVM
1163 end
1164
1165 def stats
1166 @stats
1167 end
1168
1169 def parseResult(result)
1170 raise "VM mismatch; I've got #{vm} and they've got #{result.vm}" unless resu lt.vm == vm
1171 raise unless result.benchmark == @benchmark
1172 @stats.add(result.time)
1173 end
1174 end
1175
1176 class SuiteOnVM < StatsAccumulator
1177 def initialize(vm, vmStats, suite)
1178 super()
1179 @vm = vm
1180 @vmStats = vmStats
1181 @suite = suite
1182
1183 raise unless @vm.is_a? VM
1184 raise unless @vmStats.is_a? StatsAccumulator
1185 raise unless @suite.is_a? BenchmarkSuite
1186 end
1187
1188 def to_s
1189 "#{@suite} on #{@vm}"
1190 end
1191
1192 def suite
1193 @suite
1194 end
1195
1196 def vm
1197 @vm
1198 end
1199
1200 def vmStats
1201 raise unless @vmStats
1202 @vmStats
1203 end
1204 end
1205
1206 class BenchPlan
1207 def initialize(benchmarkOnVM, iteration)
1208 @benchmarkOnVM = benchmarkOnVM
1209 @iteration = iteration
1210 end
1211
1212 def to_s
1213 "#{@benchmarkOnVM} \##{@iteration+1}"
1214 end
1215
1216 def benchmarkOnVM
1217 @benchmarkOnVM
1218 end
1219
1220 def benchmark
1221 @benchmarkOnVM.benchmark
1222 end
1223
1224 def suite
1225 @benchmarkOnVM.suite
1226 end
1227
1228 def vm
1229 @benchmarkOnVM.vm
1230 end
1231
1232 def iteration
1233 @iteration
1234 end
1235
1236 def parseResult(result)
1237 raise unless result.plan == self
1238 @benchmarkOnVM.parseResult(result)
1239 @benchmarkOnVM.vmStats.statsForIteration(@iteration, result.innerIndex).add( result.time)
1240 @benchmarkOnVM.suiteOnVM.statsForIteration(@iteration, result.innerIndex).ad d(result.time)
1241 end
1242 end
1243
1244 def lpad(str,chars)
1245 if str.length>chars
1246 str
1247 else
1248 "%#{chars}s"%(str)
1249 end
1250 end
1251
1252 def rpad(str,chars)
1253 while str.length<chars
1254 str+=" "
1255 end
1256 str
1257 end
1258
1259 def center(str,chars)
1260 while str.length<chars
1261 str+=" "
1262 if str.length<chars
1263 str=" "+str
1264 end
1265 end
1266 str
1267 end
1268
1269 def statsToStr(stats)
1270 if $inner*$outer == 1
1271 string = numToStr(stats.mean)
1272 raise unless string =~ /\./
1273 left = $~.pre_match
1274 right = $~.post_match
1275 lpad(left,12)+"."+rpad(right,9)
1276 else
1277 lpad(numToStr(stats.mean),11)+"+-"+rpad(numToStr(stats.confInt),9)
1278 end
1279 end
1280
1281 def plural(num)
1282 if num == 1
1283 ""
1284 else
1285 "s"
1286 end
1287 end
1288
1289 def wrap(str, columns)
1290 array = str.split
1291 result = ""
1292 curLine = array.shift
1293 array.each {
1294 | curStr |
1295 if (curLine + " " + curStr).size > columns
1296 result += curLine + "\n"
1297 curLine = curStr
1298 else
1299 curLine += " " + curStr
1300 end
1301 }
1302 result + curLine + "\n"
1303 end
1304
1305 def runAndGetResults
1306 results = nil
1307 Dir.chdir(BENCH_DATA_PATH) {
1308 IO.popen("sh ./runscript", "r") {
1309 | inp |
1310 results = inp.read
1311 }
1312 raise "Script did not complete correctly: #{$?}" unless $?.success?
1313 }
1314 raise unless results
1315 results
1316 end
1317
1318 def parseAndDisplayResults(results)
1319 vmStatses = []
1320 $vms.each {
1321 vmStatses << StatsAccumulator.new
1322 }
1323
1324 suitesOnVMs = []
1325 suitesOnVMsForSuite = {}
1326 $suites.each {
1327 | suite |
1328 suitesOnVMsForSuite[suite] = []
1329 }
1330 suitesOnVMsForVM = {}
1331 $vms.each {
1332 | vm |
1333 suitesOnVMsForVM[vm] = []
1334 }
1335
1336 benchmarksOnVMs = []
1337 benchmarksOnVMsForBenchmark = {}
1338 $benchmarks.each {
1339 | benchmark |
1340 benchmarksOnVMsForBenchmark[benchmark] = []
1341 }
1342
1343 $vms.each_with_index {
1344 | vm, vmIndex |
1345 vmStats = vmStatses[vmIndex]
1346 $suites.each {
1347 | suite |
1348 suiteOnVM = SuiteOnVM.new(vm, vmStats, suite)
1349 suitesOnVMs << suiteOnVM
1350 suitesOnVMsForSuite[suite] << suiteOnVM
1351 suitesOnVMsForVM[vm] << suiteOnVM
1352 suite.benchmarks.each {
1353 | benchmark |
1354 benchmarkOnVM = BenchmarkOnVM.new(benchmark, suiteOnVM)
1355 benchmarksOnVMs << benchmarkOnVM
1356 benchmarksOnVMsForBenchmark[benchmark] << benchmarkOnVM
1357 }
1358 }
1359 }
1360
1361 plans = []
1362 benchmarksOnVMs.each {
1363 | benchmarkOnVM |
1364 $outer.times {
1365 | iteration |
1366 plans << BenchPlan.new(benchmarkOnVM, iteration)
1367 }
1368 }
1369
1370 hostname = nil
1371 hwmodel = nil
1372 results.each_line {
1373 | line |
1374 line.chomp!
1375 if line =~ /HOSTNAME:([^.]+)/
1376 hostname = $1
1377 elsif line =~ /HARDWARE:hw\.model: /
1378 hwmodel = $~.post_match.chomp
1379 else
1380 result = ParsedResult.parse(plans, line.chomp)
1381 if result
1382 result.plan.parseResult(result)
1383 end
1384 end
1385 }
1386
1387 # Compute the geomean of the preferred means of results on a SuiteOnVM
1388 overallResults = []
1389 $vms.each {
1390 | vm |
1391 result = Stats.new
1392 $outer.times {
1393 | outerIndex |
1394 $inner.times {
1395 | innerIndex |
1396 curResult = Stats.new
1397 suitesOnVMsForVM[vm].each {
1398 | suiteOnVM |
1399 # For a given iteration, suite, and VM, compute the suite's preferred mean
1400 # over the data collected for all benchmarks in that suite. We'll have one
1401 # sample per benchmark. For example on V8 this will be the geomean of 1
1402 # sample for crypto, 1 sample for deltablue, and so on, and 1 sample f or
1403 # splay.
1404 curResult.add(suiteOnVM.suite.computeMean(suiteOnVM.statsForIteration( outerIndex, innerIndex)))
1405 }
1406
1407 # curResult now holds 1 sample for each of the means computed in the abo ve
1408 # loop. Compute the geomean over this, and store it.
1409 result.add(curResult.geometricMean)
1410 }
1411 }
1412
1413 # $overallResults will have a Stats for each VM. That Stats object will hold
1414 # $inner*$outer geomeans, allowing us to compute the arithmetic mean and
1415 # confidence interval of the geomeans of preferred means. Convoluted, but
1416 # useful and probably sound.
1417 overallResults << result
1418 }
1419
1420 if $verbosity >= 2
1421 benchmarksOnVMs.each {
1422 | benchmarkOnVM |
1423 $stderr.puts "#{benchmarkOnVM}: #{benchmarkOnVM.stats}"
1424 }
1425
1426 $vms.each_with_index {
1427 | vm, vmIndex |
1428 vmStats = vmStatses[vmIndex]
1429 $stderr.puts "#{vm} (arithmeticMean): #{vmStats.arithmeticMeanStats}"
1430 $stderr.puts "#{vm} (geometricMean): #{vmStats.geometricMeanStats}"
1431 }
1432 end
1433
1434 reportName =
1435 (if ($vms.collect {
1436 | vm |
1437 vm.nameKind
1438 }.index :auto)
1439 ""
1440 else
1441 $vms.collect {
1442 | vm |
1443 vm.to_s
1444 }.join("_") + "_"
1445 end) +
1446 ($suites.collect {
1447 | suite |
1448 suite.to_s
1449 }.join("")) + "_" +
1450 (if hostname
1451 hostname + "_"
1452 else
1453 ""
1454 end)+
1455 (begin
1456 time = Time.now
1457 "%04d%02d%02d_%02d%02d" %
1458 [ time.year, time.month, time.day,
1459 time.hour, time.min ]
1460 end) +
1461 "_benchReport.txt"
1462
1463 unless $brief
1464 puts "Generating benchmark report at #{reportName}"
1465 end
1466
1467 outp = $stdout
1468 begin
1469 outp = File.open(reportName,"w")
1470 rescue => e
1471 $stderr.puts "Error: could not save report to #{reportName}: #{e}"
1472 $stderr.puts
1473 end
1474
1475 def createVMsString
1476 result = ""
1477 result += " " if $suites.size > 1
1478 result += rpad("", $benchpad)
1479 result += " "
1480 $vms.size.times {
1481 | index |
1482 if index != 0
1483 result += " "+NoChange.new(0).shortForm
1484 end
1485 result += lpad(center($vms[index].name, 9+9+2), 11+9+2)
1486 }
1487 result += " "
1488 if $vms.size >= 3
1489 result += center("#{$vms[-1].name} v. #{$vms[0].name}",26)
1490 elsif $vms.size >= 2
1491 result += " "*26
1492 end
1493 result
1494 end
1495
1496 columns = [createVMsString.size, 78].max
1497
1498 outp.print "Benchmark report for "
1499 if $suites.size == 1
1500 outp.print $suites[0].to_s
1501 elsif $suites.size == 2
1502 outp.print "#{$suites[0]} and #{$suites[1]}"
1503 else
1504 outp.print "#{$suites[0..-2].join(', ')}, and #{$suites[-1]}"
1505 end
1506 if hostname
1507 outp.print " on #{hostname}"
1508 end
1509 if hwmodel
1510 outp.print " (#{hwmodel})"
1511 end
1512 outp.puts "."
1513 outp.puts
1514
1515 # This looks stupid; revisit later.
1516 if false
1517 $suites.each {
1518 | suite |
1519 outp.puts "#{suite} at #{suite.path}"
1520 }
1521
1522 outp.puts
1523 end
1524
1525 outp.puts "VMs tested:"
1526 $vms.each {
1527 | vm |
1528 outp.print "\"#{vm.name}\" at #{vm.origPath}"
1529 if vm.svnRevision
1530 outp.print " (r#{vm.svnRevision})"
1531 end
1532 outp.puts
1533 }
1534
1535 outp.puts
1536
1537 outp.puts wrap("Collected #{$outer*$inner} sample#{plural($outer*$inner)} per benchmark/VM, "+
1538 "with #{$outer} VM invocation#{plural($outer)} per benchmark."+
1539 (if $rerun > 1 then (" Ran #{$rerun} benchmark iterations, and measured the "+
1540 "total time of those iterations, for each sample.")
1541 else "" end)+
1542 (if $measureGC == true then (" No manual garbage collection inv ocations were "+
1543 "emitted.")
1544 elsif $measureGC then (" Emitted a call to gc() between sample measurements for "+
1545 "all VMs except #{$measureGC}.")
1546 else (" Emitted a call to gc() between sample measurements.") end)+
1547 (if $warmup == 0 then (" Did not include any warm-up iterations ; measurements "+
1548 "began with the very first iteration.")
1549 else (" Used #{$warmup*$rerun} benchmark iteration#{plural($wa rmup*$rerun)} per VM "+
1550 "invocation for warm-up.") end)+
1551 (case $timeMode
1552 when :preciseTime then (" Used the jsc-specific preciseTime() function to get "+
1553 "microsecond-level timing.")
1554 when :date then (" Used the portable Date.now() method to get millisecond-"+
1555 "level timing.")
1556 else raise end)+
1557 " Reporting benchmark execution times with 95% confidence "+
1558 "intervals in milliseconds.",
1559 columns)
1560
1561 outp.puts
1562
1563 def printVMs(outp)
1564 outp.puts createVMsString
1565 end
1566
1567 def summaryStats(outp, accumulators, name, &proc)
1568 outp.print " " if $suites.size > 1
1569 outp.print rpad(name, $benchpad)
1570 outp.print " "
1571 accumulators.size.times {
1572 | index |
1573 if index != 0
1574 outp.print " "+accumulators[index].stats(&proc).compareTo(accumulators[i ndex-1].stats(&proc)).shortForm
1575 end
1576 outp.print statsToStr(accumulators[index].stats(&proc))
1577 }
1578 if accumulators.size>=2
1579 outp.print(" "+accumulators[-1].stats(&proc).compareTo(accumulators[0]. stats(&proc)).longForm)
1580 end
1581 outp.puts
1582 end
1583
1584 def meanName(currentMean, preferredMean)
1585 result = "<#{currentMean}>"
1586 if "#{currentMean}Mean" == preferredMean.to_s
1587 result += " *"
1588 end
1589 result
1590 end
1591
1592 def allSummaryStats(outp, accumulators, preferredMean)
1593 summaryStats(outp, accumulators, meanName("arithmetic", preferredMean)) {
1594 | stat |
1595 stat.arithmeticMean
1596 }
1597
1598 summaryStats(outp, accumulators, meanName("geometric", preferredMean)) {
1599 | stat |
1600 stat.geometricMean
1601 }
1602
1603 summaryStats(outp, accumulators, meanName("harmonic", preferredMean)) {
1604 | stat |
1605 stat.harmonicMean
1606 }
1607 end
1608
1609 $suites.each {
1610 | suite |
1611 printVMs(outp)
1612 if $suites.size > 1
1613 outp.puts "#{suite.name}:"
1614 else
1615 outp.puts
1616 end
1617 suite.benchmarks.each {
1618 | benchmark |
1619 outp.print " " if $suites.size > 1
1620 outp.print rpad(benchmark.name, $benchpad)
1621 outp.print " "
1622 myConfigs = benchmarksOnVMsForBenchmark[benchmark]
1623 myConfigs.size.times {
1624 | index |
1625 if index != 0
1626 outp.print " "+myConfigs[index].stats.compareTo(myConfigs[index-1].sta ts).shortForm
1627 end
1628 outp.print statsToStr(myConfigs[index].stats)
1629 }
1630 if $vms.size>=2
1631 outp.print(" "+myConfigs[-1].stats.compareTo(myConfigs[0].stats).to_s )
1632 end
1633 outp.puts
1634 }
1635 outp.puts
1636 allSummaryStats(outp, suitesOnVMsForSuite[suite], suite.preferredMean)
1637 outp.puts if $suites.size > 1
1638 }
1639
1640 if $suites.size > 1
1641 printVMs(outp)
1642 outp.puts "All benchmarks:"
1643 allSummaryStats(outp, vmStatses, nil)
1644
1645 outp.puts
1646 printVMs(outp)
1647 outp.puts "Geomean of preferred means:"
1648 outp.print " "
1649 outp.print rpad("<scaled-result>", $benchpad)
1650 outp.print " "
1651 $vms.size.times {
1652 | index |
1653 if index != 0
1654 outp.print " "+overallResults[index].compareTo(overallResults[index-1]). shortForm
1655 end
1656 outp.print statsToStr(overallResults[index])
1657 }
1658 if overallResults.size>=2
1659 outp.print(" "+overallResults[-1].compareTo(overallResults[0]).longForm )
1660 end
1661 outp.puts
1662 end
1663 outp.puts
1664
1665 if outp != $stdout
1666 outp.close
1667 end
1668
1669 if outp != $stdout and not $brief
1670 puts
1671 File.open(reportName) {
1672 | inp |
1673 puts inp.read
1674 }
1675 end
1676
1677 if $brief
1678 puts(overallResults.collect{|stats| stats.mean}.join("\t"))
1679 puts(overallResults.collect{|stats| stats.confInt}.join("\t"))
1680 end
1681
1682
1683 end
1684
1685 begin
1686 $sawBenchOptions = false
1687
1688 def resetBenchOptionsIfNecessary
1689 unless $sawBenchOptions
1690 $includeSunSpider = false
1691 $includeV8 = false
1692 $includeKraken = false
1693 $sawBenchOptions = true
1694 end
1695 end
1696
1697 GetoptLong.new(['--rerun', GetoptLong::REQUIRED_ARGUMENT],
1698 ['--inner', GetoptLong::REQUIRED_ARGUMENT],
1699 ['--outer', GetoptLong::REQUIRED_ARGUMENT],
1700 ['--warmup', GetoptLong::REQUIRED_ARGUMENT],
1701 ['--timing-mode', GetoptLong::REQUIRED_ARGUMENT],
1702 ['--sunspider-only', GetoptLong::NO_ARGUMENT],
1703 ['--v8-only', GetoptLong::NO_ARGUMENT],
1704 ['--kraken-only', GetoptLong::NO_ARGUMENT],
1705 ['--exclude-sunspider', GetoptLong::NO_ARGUMENT],
1706 ['--exclude-v8', GetoptLong::NO_ARGUMENT],
1707 ['--exclude-kraken', GetoptLong::NO_ARGUMENT],
1708 ['--sunspider', GetoptLong::NO_ARGUMENT],
1709 ['--v8', GetoptLong::NO_ARGUMENT],
1710 ['--kraken', GetoptLong::NO_ARGUMENT],
1711 ['--benchmarks', GetoptLong::REQUIRED_ARGUMENT],
1712 ['--measure-gc', GetoptLong::OPTIONAL_ARGUMENT],
1713 ['--force-vm-kind', GetoptLong::REQUIRED_ARGUMENT],
1714 ['--force-vm-copy', GetoptLong::NO_ARGUMENT],
1715 ['--dont-copy-vms', GetoptLong::NO_ARGUMENT],
1716 ['--verbose', '-v', GetoptLong::NO_ARGUMENT],
1717 ['--brief', GetoptLong::NO_ARGUMENT],
1718 ['--silent', GetoptLong::NO_ARGUMENT],
1719 ['--remote', GetoptLong::REQUIRED_ARGUMENT],
1720 ['--local', GetoptLong::NO_ARGUMENT],
1721 ['--ssh-options', GetoptLong::REQUIRED_ARGUMENT],
1722 ['--slave', GetoptLong::NO_ARGUMENT],
1723 ['--prepare-only', GetoptLong::NO_ARGUMENT],
1724 ['--analyze', GetoptLong::REQUIRED_ARGUMENT],
1725 ['--vms', GetoptLong::REQUIRED_ARGUMENT],
1726 ['--help', '-h', GetoptLong::NO_ARGUMENT]).each {
1727 | opt, arg |
1728 case opt
1729 when '--rerun'
1730 $rerun = intArg(opt,arg,1,nil)
1731 when '--inner'
1732 $inner = intArg(opt,arg,1,nil)
1733 when '--outer'
1734 $outer = intArg(opt,arg,1,nil)
1735 when '--warmup'
1736 $warmup = intArg(opt,arg,0,nil)
1737 when '--timing-mode'
1738 if arg.upcase == "PRECISETIME"
1739 $timeMode = :preciseTime
1740 elsif arg.upcase == "DATE"
1741 $timeMode = :date
1742 elsif arg.upcase == "AUTO"
1743 $timeMode = :auto
1744 else
1745 quickFail("Expected either 'preciseTime', 'date', or 'auto' for --time-m ode, but got '#{arg}'.",
1746 "Invalid argument for command-line option")
1747 end
1748 when '--force-vm-kind'
1749 if arg.upcase == "JSC"
1750 $forceVMKind = :jsc
1751 elsif arg.upcase == "DUMPRENDERTREE"
1752 $forceVMKind = :dumpRenderTree
1753 elsif arg.upcase == "AUTO"
1754 $forceVMKind = nil
1755 else
1756 quickFail("Expected either 'jsc' or 'DumpRenderTree' for --force-vm-kind , but got '#{arg}'.",
1757 "Invalid argument for command-line option")
1758 end
1759 when '--force-vm-copy'
1760 $needToCopyVMs = true
1761 when '--dont-copy-vms'
1762 $dontCopyVMs = true
1763 when '--sunspider-only'
1764 $includeV8 = false
1765 $includeKraken = false
1766 when '--v8-only'
1767 $includeSunSpider = false
1768 $includeKraken = false
1769 when '--kraken-only'
1770 $includeSunSpider = false
1771 $includeV8 = false
1772 when '--exclude-sunspider'
1773 $includeSunSpider = false
1774 when '--exclude-v8'
1775 $includeV8 = false
1776 when '--exclude-kraken'
1777 $includeKraken = false
1778 when '--sunspider'
1779 resetBenchOptionsIfNecessary
1780 $includeSunSpider = true
1781 when '--v8'
1782 resetBenchOptionsIfNecessary
1783 $includeV8 = true
1784 when '--kraken'
1785 resetBenchOptionsIfNecessary
1786 $includeKraken = true
1787 when '--benchmarks'
1788 $benchmarkPattern = Regexp.new(arg)
1789 when '--measure-gc'
1790 if arg == ''
1791 $measureGC = true
1792 else
1793 $measureGC = arg
1794 end
1795 when '--verbose'
1796 $verbosity += 1
1797 when '--brief'
1798 $brief = true
1799 when '--silent'
1800 $silent = true
1801 when '--remote'
1802 $remoteHosts += arg.split(',')
1803 $needToCopyVMs = true
1804 when '--ssh-options'
1805 $sshOptions << arg
1806 when '--local'
1807 $alsoLocal = true
1808 when '--prepare-only'
1809 $run = false
1810 when '--analyze'
1811 $prepare = false
1812 $run = false
1813 $analyze << arg
1814 when '--help'
1815 usage
1816 else
1817 raise "bad option: #{opt}"
1818 end
1819 }
1820
1821 # If the --dont-copy-vms option was passed, it overrides the --force-vm-copy o ption.
1822 if $dontCopyVMs
1823 $needToCopyVMs = false
1824 end
1825
1826 SUNSPIDER = BenchmarkSuite.new("SunSpider", SUNSPIDER_PATH, :arithmeticMean)
1827 ["3d-cube", "3d-morph", "3d-raytrace", "access-binary-trees",
1828 "access-fannkuch", "access-nbody", "access-nsieve",
1829 "bitops-3bit-bits-in-byte", "bitops-bits-in-byte", "bitops-bitwise-and",
1830 "bitops-nsieve-bits", "controlflow-recursive", "crypto-aes",
1831 "crypto-md5", "crypto-sha1", "date-format-tofte", "date-format-xparb",
1832 "math-cordic", "math-partial-sums", "math-spectral-norm", "regexp-dna",
1833 "string-base64", "string-fasta", "string-tagcloud",
1834 "string-unpack-code", "string-validate-input"].each {
1835 | name |
1836 SUNSPIDER.add SunSpiderBenchmark.new(name)
1837 }
1838
1839 V8 = BenchmarkSuite.new("V8", V8_PATH, :geometricMean)
1840 ["crypto", "deltablue", "earley-boyer", "raytrace",
1841 "regexp", "richards", "splay"].each {
1842 | name |
1843 V8.add V8Benchmark.new(name)
1844 }
1845
1846 KRAKEN = BenchmarkSuite.new("Kraken", KRAKEN_PATH, :arithmeticMean)
1847 ["ai-astar", "audio-beat-detection", "audio-dft", "audio-fft",
1848 "audio-oscillator", "imaging-darkroom", "imaging-desaturate",
1849 "imaging-gaussian-blur", "json-parse-financial",
1850 "json-stringify-tinderbox", "stanford-crypto-aes",
1851 "stanford-crypto-ccm", "stanford-crypto-pbkdf2",
1852 "stanford-crypto-sha256-iterative"].each {
1853 | name |
1854 KRAKEN.add KrakenBenchmark.new(name)
1855 }
1856
1857 ARGV.each {
1858 | vm |
1859 if vm =~ /([a-zA-Z0-9_ ]+):/
1860 name = $1
1861 nameKind = :given
1862 vm = $~.post_match
1863 else
1864 name = "Conf\##{$vms.length+1}"
1865 nameKind = :auto
1866 end
1867 $stderr.puts "#{name}: #{vm}" if $verbosity >= 1
1868 $vms << VM.new(Pathname.new(vm).realpath, name, nameKind, nil)
1869 }
1870
1871 if $vms.empty?
1872 quickFail("Please specify at least on configuraiton on the command line.",
1873 "Insufficient arguments")
1874 end
1875
1876 $vms.each {
1877 | vm |
1878 if vm.vmType != :jsc and $timeMode != :date
1879 $timeMode = :date
1880 $stderr.puts "Warning: using Date.now() instead of preciseTime() because # {vm} doesn't support the latter."
1881 end
1882 }
1883
1884 if FileTest.exist? BENCH_DATA_PATH
1885 cmd = "rm -rf #{BENCH_DATA_PATH}"
1886 $stderr.puts ">> #{cmd}" if $verbosity >= 2
1887 raise unless system cmd
1888 end
1889
1890 Dir.mkdir BENCH_DATA_PATH
1891
1892 if $needToCopyVMs
1893 canCopyIntoBenchPath = true
1894 $vms.each {
1895 | vm |
1896 canCopyIntoBenchPath = false unless vm.canCopyIntoBenchPath
1897 }
1898
1899 if canCopyIntoBenchPath
1900 $vms.each {
1901 | vm |
1902 $stderr.puts "Copying #{vm} into #{BENCH_DATA_PATH}..."
1903 vm.copyIntoBenchPath
1904 }
1905 $stderr.puts "All VMs are in place."
1906 else
1907 $stderr.puts "Warning: don't know how to copy some VMs into #{BENCH_DATA_P ATH}, so I won't do it."
1908 end
1909 end
1910
1911 if $measureGC and $measureGC != true
1912 found = false
1913 $vms.each {
1914 | vm |
1915 if vm.name == $measureGC
1916 found = true
1917 end
1918 }
1919 unless found
1920 $stderr.puts "Warning: --measure-gc option ignored because no VM is named #{$measureGC}"
1921 end
1922 end
1923
1924 if $outer*$inner == 1
1925 $stderr.puts "Warning: will only collect one sample per benchmark/VM. Confi dence interval calculation will fail."
1926 end
1927
1928 $stderr.puts "Using timeMode = #{$timeMode}." if $verbosity >= 1
1929
1930 $suites = []
1931
1932 if $includeSunSpider and not SUNSPIDER.empty?
1933 $suites << SUNSPIDER
1934 end
1935
1936 if $includeV8 and not V8.empty?
1937 $suites << V8
1938 end
1939
1940 if $includeKraken and not KRAKEN.empty?
1941 $suites << KRAKEN
1942 end
1943
1944 $benchmarks = []
1945 $suites.each {
1946 | suite |
1947 $benchmarks += suite.benchmarks
1948 }
1949
1950 $runPlans = []
1951 $vms.each {
1952 | vm |
1953 $benchmarks.each {
1954 | benchmark |
1955 $outer.times {
1956 | iteration |
1957 $runPlans << BenchRunPlan.new(benchmark, vm, iteration)
1958 }
1959 }
1960 }
1961
1962 $runPlans.shuffle!
1963
1964 $suitepad = $suites.collect {
1965 | suite |
1966 suite.to_s.size
1967 }.max + 1
1968
1969 $benchpad = ($benchmarks +
1970 ["<arithmetic> *", "<geometric> *", "<harmonic> *"]).collect {
1971 | benchmark |
1972 if benchmark.respond_to? :name
1973 benchmark.name.size
1974 else
1975 benchmark.size
1976 end
1977 }.max + 1
1978
1979 $vmpad = $vms.collect {
1980 | vm |
1981 vm.to_s.size
1982 }.max + 1
1983
1984 if $prepare
1985 File.open("#{BENCH_DATA_PATH}/runscript", "w") {
1986 | file |
1987 file.puts "echo \"HOSTNAME:\\c\""
1988 file.puts "hostname"
1989 file.puts "echo"
1990 file.puts "echo \"HARDWARE:\\c\""
1991 file.puts "/usr/sbin/sysctl hw.model"
1992 file.puts "echo"
1993 file.puts "set -e"
1994 $script = file
1995 $runPlans.each_with_index {
1996 | plan, idx |
1997 if $verbosity == 0 and not $silent
1998 text1 = lpad(idx.to_s,$runPlans.size.to_s.size)+"/"+$runPlans.size.to_ s
1999 text2 = plan.benchmark.to_s+"/"+plan.vm.to_s
2000 file.puts("echo "+("\r#{text1} #{rpad(text2,$suitepad+1+$benchpad+1+$v mpad)}".inspect)[0..-2]+"\\c\" 1>&2")
2001 file.puts("echo "+("\r#{text1} #{text2}".inspect)[0..-2]+"\\c\" 1>&2")
2002 end
2003 plan.emitRunCode
2004 }
2005 if $verbosity == 0 and not $silent
2006 file.puts("echo "+("\r#{$runPlans.size}/#{$runPlans.size} #{' '*($suitep ad+1+$benchpad+1+$vmpad)}".inspect)[0..-2]+"\\c\" 1>&2")
2007 file.puts("echo "+("\r#{$runPlans.size}/#{$runPlans.size}".inspect)+" 1> &2")
2008 end
2009 }
2010 end
2011
2012 if $run
2013 unless $remoteHosts.empty?
2014 $stderr.puts "Packaging benchmarking directory for remote hosts..." if $ve rbosity==0
2015 Dir.chdir(TEMP_PATH) {
2016 cmd = "tar -czf payload.tar.gz benchdata"
2017 $stderr.puts ">> #{cmd}" if $verbosity>=2
2018 raise unless system(cmd)
2019 }
2020
2021 def grokHost(host)
2022 if host =~ /:([0-9]+)$/
2023 "-p " + $1 + " " + $~.pre_match.inspect
2024 else
2025 host.inspect
2026 end
2027 end
2028
2029 def sshRead(host, command)
2030 cmd = "ssh #{$sshOptions.collect{|x| x.inspect}.join(' ')} #{grokHost(ho st)} #{command.inspect}"
2031 $stderr.puts ">> #{cmd}" if $verbosity>=2
2032 result = ""
2033 IO.popen(cmd, "r") {
2034 | inp |
2035 inp.each_line {
2036 | line |
2037 $stderr.puts "#{host}: #{line}" if $verbosity>=2
2038 result += line
2039 }
2040 }
2041 raise "#{$?}" unless $?.success?
2042 result
2043 end
2044
2045 def sshWrite(host, command, data)
2046 cmd = "ssh #{$sshOptions.collect{|x| x.inspect}.join(' ')} #{grokHost(ho st)} #{command.inspect}"
2047 $stderr.puts ">> #{cmd}" if $verbosity>=2
2048 IO.popen(cmd, "w") {
2049 | outp |
2050 outp.write(data)
2051 }
2052 raise "#{$?}" unless $?.success?
2053 end
2054
2055 $remoteHosts.each {
2056 | host |
2057 $stderr.puts "Sending benchmark payload to #{host}..." if $verbosity==0
2058
2059 remoteTempPath = JSON::parse(sshRead(host, "cat ~/.bencher"))["tempPath" ]
2060 raise unless remoteTempPath
2061
2062 sshWrite(host, "cd #{remoteTempPath.inspect} && rm -rf benchdata && tar -xz", IO::read("#{TEMP_PATH}/payload.tar.gz"))
2063
2064 $stderr.puts "Running on #{host}..." if $verbosity==0
2065
2066 parseAndDisplayResults(sshRead(host, "cd #{(remoteTempPath+'/benchdata') .inspect} && sh runscript"))
2067 }
2068 end
2069
2070 if not $remoteHosts.empty? and $alsoLocal
2071 $stderr.puts "Running locally..."
2072 end
2073
2074 if $remoteHosts.empty? or $alsoLocal
2075 parseAndDisplayResults(runAndGetResults)
2076 end
2077 end
2078
2079 $analyze.each_with_index {
2080 | filename, index |
2081 if index >= 1
2082 puts
2083 end
2084 parseAndDisplayResults(IO::read(filename))
2085 }
2086
2087 if $prepare and not $run and $analyze.empty?
2088 puts wrap("Benchmarking script and data are in #{BENCH_DATA_PATH}. You can r un "+
2089 "the benchmarks and get the results by doing:", 78)
2090 puts
2091 puts "cd #{BENCH_DATA_PATH}"
2092 puts "sh runscript > results.txt"
2093 puts
2094 puts wrap("Then you can analyze the results by running bencher with the same arguments "+
2095 "as now, but replacing --prepare-only with --analyze results.txt." , 78)
2096 end
2097 rescue => e
2098 fail(e)
2099 end
2100
2101
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698