3 # Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
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.
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.
36 $stderr.puts "It does not appear that you have the 'json' package installed. Try running 'sudo gem install json'."
40 SCRIPT_PATH = Pathname.new(__FILE__).realpath
42 raise unless SCRIPT_PATH.dirname.basename.to_s == "Scripts"
43 raise unless SCRIPT_PATH.dirname.dirname.basename.to_s == "Tools"
45 OPENSOURCE_PATH = SCRIPT_PATH.dirname.dirname.dirname
47 SUNSPIDER_PATH = OPENSOURCE_PATH + "PerformanceTests" + "SunSpider" + "tests" + "sunspider-1.0"
48 LONGSPIDER_PATH = OPENSOURCE_PATH + "PerformanceTests" + "LongSpider"
49 V8_PATH = OPENSOURCE_PATH + "PerformanceTests" + "SunSpider" + "tests" + "v8-v6"
50 JSREGRESS_PATH = OPENSOURCE_PATH + "LayoutTests" + "js" + "regress" + "script-tests"
51 OCTANE_WRAPPER_PATH = OPENSOURCE_PATH + "PerformanceTests" + "Octane" + "wrappers"
53 TEMP_PATH = OPENSOURCE_PATH + "BenchmarkTemp"
56 raise unless TEMP_PATH.directory?
61 BENCH_DATA_PATH = TEMP_PATH + "benchdata"
63 IBR_LOOKUP=[0.00615583, 0.0975, 0.22852, 0.341628, 0.430741, 0.500526, 0.555933,
64 0.600706, 0.637513, 0.668244, 0.694254, 0.716537, 0.735827, 0.752684,
65 0.767535, 0.780716, 0.792492, 0.803074, 0.812634, 0.821313, 0.829227,
66 0.836472, 0.843129, 0.849267, 0.854943, 0.860209, 0.865107, 0.869674,
67 0.873942, 0.877941, 0.881693, 0.885223, 0.888548, 0.891686, 0.894652,
68 0.897461, 0.900124, 0.902652, 0.905056, 0.907343, 0.909524, 0.911604,
69 0.91359, 0.91549, 0.917308, 0.919049, 0.920718, 0.92232, 0.923859, 0.925338,
70 0.926761, 0.92813, 0.929449, 0.930721, 0.931948, 0.933132, 0.934275, 0.93538,
71 0.936449, 0.937483, 0.938483, 0.939452, 0.940392, 0.941302, 0.942185,
72 0.943042, 0.943874, 0.944682, 0.945467, 0.94623, 0.946972, 0.947694,
73 0.948396, 0.94908, 0.949746, 0.950395, 0.951027, 0.951643, 0.952244,
74 0.952831, 0.953403, 0.953961, 0.954506, 0.955039, 0.955559, 0.956067,
75 0.956563, 0.957049, 0.957524, 0.957988, 0.958443, 0.958887, 0.959323,
76 0.959749, 0.960166, 0.960575, 0.960975, 0.961368, 0.961752, 0.962129,
77 0.962499, 0.962861, 0.963217, 0.963566, 0.963908, 0.964244, 0.964574,
78 0.964897, 0.965215, 0.965527, 0.965834, 0.966135, 0.966431, 0.966722,
79 0.967007, 0.967288, 0.967564, 0.967836, 0.968103, 0.968366, 0.968624,
80 0.968878, 0.969128, 0.969374, 0.969617, 0.969855, 0.97009, 0.970321,
81 0.970548, 0.970772, 0.970993, 0.97121, 0.971425, 0.971636, 0.971843,
82 0.972048, 0.97225, 0.972449, 0.972645, 0.972839, 0.973029, 0.973217,
83 0.973403, 0.973586, 0.973766, 0.973944, 0.97412, 0.974293, 0.974464,
84 0.974632, 0.974799, 0.974963, 0.975125, 0.975285, 0.975443, 0.975599,
85 0.975753, 0.975905, 0.976055, 0.976204, 0.97635, 0.976495, 0.976638,
86 0.976779, 0.976918, 0.977056, 0.977193, 0.977327, 0.97746, 0.977592,
87 0.977722, 0.97785, 0.977977, 0.978103, 0.978227, 0.978349, 0.978471,
88 0.978591, 0.978709, 0.978827, 0.978943, 0.979058, 0.979171, 0.979283,
89 0.979395, 0.979504, 0.979613, 0.979721, 0.979827, 0.979933, 0.980037,
90 0.98014, 0.980242, 0.980343, 0.980443, 0.980543, 0.980641, 0.980738,
91 0.980834, 0.980929, 0.981023, 0.981116, 0.981209, 0.9813, 0.981391, 0.981481,
92 0.981569, 0.981657, 0.981745, 0.981831, 0.981916, 0.982001, 0.982085,
93 0.982168, 0.982251, 0.982332, 0.982413, 0.982493, 0.982573, 0.982651,
94 0.982729, 0.982807, 0.982883, 0.982959, 0.983034, 0.983109, 0.983183,
95 0.983256, 0.983329, 0.983401, 0.983472, 0.983543, 0.983613, 0.983683,
96 0.983752, 0.98382, 0.983888, 0.983956, 0.984022, 0.984089, 0.984154,
97 0.984219, 0.984284, 0.984348, 0.984411, 0.984474, 0.984537, 0.984599,
98 0.98466, 0.984721, 0.984782, 0.984842, 0.984902, 0.984961, 0.985019,
99 0.985077, 0.985135, 0.985193, 0.985249, 0.985306, 0.985362, 0.985417,
100 0.985472, 0.985527, 0.985582, 0.985635, 0.985689, 0.985742, 0.985795,
101 0.985847, 0.985899, 0.985951, 0.986002, 0.986053, 0.986103, 0.986153,
102 0.986203, 0.986252, 0.986301, 0.98635, 0.986398, 0.986446, 0.986494,
103 0.986541, 0.986588, 0.986635, 0.986681, 0.986727, 0.986773, 0.986818,
104 0.986863, 0.986908, 0.986953, 0.986997, 0.987041, 0.987084, 0.987128,
105 0.987171, 0.987213, 0.987256, 0.987298, 0.98734, 0.987381, 0.987423,
106 0.987464, 0.987504, 0.987545, 0.987585, 0.987625, 0.987665, 0.987704,
107 0.987744, 0.987783, 0.987821, 0.98786, 0.987898, 0.987936, 0.987974,
108 0.988011, 0.988049, 0.988086, 0.988123, 0.988159, 0.988196, 0.988232,
109 0.988268, 0.988303, 0.988339, 0.988374, 0.988409, 0.988444, 0.988479,
110 0.988513, 0.988547, 0.988582, 0.988615, 0.988649, 0.988682, 0.988716,
111 0.988749, 0.988782, 0.988814, 0.988847, 0.988879, 0.988911, 0.988943,
112 0.988975, 0.989006, 0.989038, 0.989069, 0.9891, 0.989131, 0.989161, 0.989192,
113 0.989222, 0.989252, 0.989282, 0.989312, 0.989342, 0.989371, 0.989401,
114 0.98943, 0.989459, 0.989488, 0.989516, 0.989545, 0.989573, 0.989602, 0.98963,
115 0.989658, 0.989685, 0.989713, 0.98974, 0.989768, 0.989795, 0.989822,
116 0.989849, 0.989876, 0.989902, 0.989929, 0.989955, 0.989981, 0.990007,
117 0.990033, 0.990059, 0.990085, 0.99011, 0.990136, 0.990161, 0.990186,
118 0.990211, 0.990236, 0.990261, 0.990285, 0.99031, 0.990334, 0.990358,
119 0.990383, 0.990407, 0.99043, 0.990454, 0.990478, 0.990501, 0.990525,
120 0.990548, 0.990571, 0.990594, 0.990617, 0.99064, 0.990663, 0.990686,
121 0.990708, 0.990731, 0.990753, 0.990775, 0.990797, 0.990819, 0.990841,
122 0.990863, 0.990885, 0.990906, 0.990928, 0.990949, 0.99097, 0.990991,
123 0.991013, 0.991034, 0.991054, 0.991075, 0.991096, 0.991116, 0.991137,
124 0.991157, 0.991178, 0.991198, 0.991218, 0.991238, 0.991258, 0.991278,
125 0.991298, 0.991317, 0.991337, 0.991356, 0.991376, 0.991395, 0.991414,
126 0.991433, 0.991452, 0.991471, 0.99149, 0.991509, 0.991528, 0.991547,
127 0.991565, 0.991584, 0.991602, 0.99162, 0.991639, 0.991657, 0.991675,
128 0.991693, 0.991711, 0.991729, 0.991746, 0.991764, 0.991782, 0.991799,
129 0.991817, 0.991834, 0.991851, 0.991869, 0.991886, 0.991903, 0.99192,
130 0.991937, 0.991954, 0.991971, 0.991987, 0.992004, 0.992021, 0.992037,
131 0.992054, 0.99207, 0.992086, 0.992103, 0.992119, 0.992135, 0.992151,
132 0.992167, 0.992183, 0.992199, 0.992215, 0.99223, 0.992246, 0.992262,
133 0.992277, 0.992293, 0.992308, 0.992324, 0.992339, 0.992354, 0.992369,
134 0.992384, 0.9924, 0.992415, 0.992429, 0.992444, 0.992459, 0.992474, 0.992489,
135 0.992503, 0.992518, 0.992533, 0.992547, 0.992561, 0.992576, 0.99259,
136 0.992604, 0.992619, 0.992633, 0.992647, 0.992661, 0.992675, 0.992689,
137 0.992703, 0.992717, 0.99273, 0.992744, 0.992758, 0.992771, 0.992785,
138 0.992798, 0.992812, 0.992825, 0.992839, 0.992852, 0.992865, 0.992879,
139 0.992892, 0.992905, 0.992918, 0.992931, 0.992944, 0.992957, 0.99297,
140 0.992983, 0.992995, 0.993008, 0.993021, 0.993034, 0.993046, 0.993059,
141 0.993071, 0.993084, 0.993096, 0.993109, 0.993121, 0.993133, 0.993145,
142 0.993158, 0.99317, 0.993182, 0.993194, 0.993206, 0.993218, 0.99323, 0.993242,
143 0.993254, 0.993266, 0.993277, 0.993289, 0.993301, 0.993312, 0.993324,
144 0.993336, 0.993347, 0.993359, 0.99337, 0.993382, 0.993393, 0.993404,
145 0.993416, 0.993427, 0.993438, 0.993449, 0.99346, 0.993472, 0.993483,
146 0.993494, 0.993505, 0.993516, 0.993527, 0.993538, 0.993548, 0.993559,
147 0.99357, 0.993581, 0.993591, 0.993602, 0.993613, 0.993623, 0.993634,
148 0.993644, 0.993655, 0.993665, 0.993676, 0.993686, 0.993697, 0.993707,
149 0.993717, 0.993727, 0.993738, 0.993748, 0.993758, 0.993768, 0.993778,
150 0.993788, 0.993798, 0.993808, 0.993818, 0.993828, 0.993838, 0.993848,
151 0.993858, 0.993868, 0.993877, 0.993887, 0.993897, 0.993907, 0.993916,
152 0.993926, 0.993935, 0.993945, 0.993954, 0.993964, 0.993973, 0.993983,
153 0.993992, 0.994002, 0.994011, 0.99402, 0.99403, 0.994039, 0.994048, 0.994057,
154 0.994067, 0.994076, 0.994085, 0.994094, 0.994103, 0.994112, 0.994121,
155 0.99413, 0.994139, 0.994148, 0.994157, 0.994166, 0.994175, 0.994183,
156 0.994192, 0.994201, 0.99421, 0.994218, 0.994227, 0.994236, 0.994244,
157 0.994253, 0.994262, 0.99427, 0.994279, 0.994287, 0.994296, 0.994304,
158 0.994313, 0.994321, 0.994329, 0.994338, 0.994346, 0.994354, 0.994363,
159 0.994371, 0.994379, 0.994387, 0.994395, 0.994404, 0.994412, 0.99442,
160 0.994428, 0.994436, 0.994444, 0.994452, 0.99446, 0.994468, 0.994476,
161 0.994484, 0.994492, 0.9945, 0.994508, 0.994516, 0.994523, 0.994531, 0.994539,
162 0.994547, 0.994554, 0.994562, 0.99457, 0.994577, 0.994585, 0.994593, 0.9946,
163 0.994608, 0.994615, 0.994623, 0.994631, 0.994638, 0.994645, 0.994653,
164 0.99466, 0.994668, 0.994675, 0.994683, 0.99469, 0.994697, 0.994705, 0.994712,
165 0.994719, 0.994726, 0.994734, 0.994741, 0.994748, 0.994755, 0.994762,
166 0.994769, 0.994777, 0.994784, 0.994791, 0.994798, 0.994805, 0.994812,
167 0.994819, 0.994826, 0.994833, 0.99484, 0.994847, 0.994854, 0.99486, 0.994867,
168 0.994874, 0.994881, 0.994888, 0.994895, 0.994901, 0.994908, 0.994915,
169 0.994922, 0.994928, 0.994935, 0.994942, 0.994948, 0.994955, 0.994962,
170 0.994968, 0.994975, 0.994981, 0.994988, 0.994994, 0.995001, 0.995007,
171 0.995014, 0.99502, 0.995027, 0.995033, 0.99504, 0.995046, 0.995052, 0.995059,
172 0.995065, 0.995071, 0.995078, 0.995084, 0.99509, 0.995097, 0.995103,
173 0.995109, 0.995115, 0.995121, 0.995128, 0.995134, 0.99514, 0.995146,
174 0.995152, 0.995158, 0.995164, 0.995171, 0.995177, 0.995183, 0.995189,
175 0.995195, 0.995201, 0.995207, 0.995213, 0.995219, 0.995225, 0.995231,
176 0.995236, 0.995242, 0.995248, 0.995254, 0.99526, 0.995266, 0.995272,
177 0.995277, 0.995283, 0.995289, 0.995295, 0.995301, 0.995306, 0.995312,
178 0.995318, 0.995323, 0.995329, 0.995335, 0.99534, 0.995346, 0.995352,
179 0.995357, 0.995363, 0.995369, 0.995374, 0.99538, 0.995385, 0.995391,
180 0.995396, 0.995402, 0.995407, 0.995413, 0.995418, 0.995424, 0.995429,
181 0.995435, 0.99544, 0.995445, 0.995451, 0.995456, 0.995462, 0.995467,
182 0.995472, 0.995478, 0.995483, 0.995488, 0.995493, 0.995499, 0.995504,
183 0.995509, 0.995515, 0.99552, 0.995525, 0.99553, 0.995535, 0.995541, 0.995546,
184 0.995551, 0.995556, 0.995561, 0.995566, 0.995571, 0.995577, 0.995582,
185 0.995587, 0.995592, 0.995597, 0.995602, 0.995607, 0.995612, 0.995617,
186 0.995622, 0.995627, 0.995632, 0.995637, 0.995642, 0.995647, 0.995652,
187 0.995657, 0.995661, 0.995666, 0.995671, 0.995676, 0.995681, 0.995686,
188 0.995691, 0.995695, 0.9957, 0.995705, 0.99571, 0.995715, 0.995719, 0.995724,
189 0.995729, 0.995734, 0.995738, 0.995743, 0.995748, 0.995753, 0.995757,
190 0.995762, 0.995767, 0.995771, 0.995776, 0.995781, 0.995785, 0.99579,
191 0.995794, 0.995799, 0.995804, 0.995808, 0.995813, 0.995817, 0.995822,
192 0.995826, 0.995831, 0.995835, 0.99584, 0.995844, 0.995849, 0.995853,
193 0.995858, 0.995862, 0.995867, 0.995871, 0.995876, 0.99588, 0.995885,
194 0.995889, 0.995893, 0.995898, 0.995902, 0.995906, 0.995911, 0.995915,
195 0.99592, 0.995924, 0.995928, 0.995932, 0.995937, 0.995941, 0.995945, 0.99595,
196 0.995954, 0.995958, 0.995962, 0.995967, 0.995971, 0.995975, 0.995979,
197 0.995984, 0.995988, 0.995992, 0.995996, 0.996, 0.996004, 0.996009, 0.996013,
198 0.996017, 0.996021, 0.996025, 0.996029, 0.996033, 0.996037, 0.996041,
199 0.996046, 0.99605, 0.996054, 0.996058, 0.996062, 0.996066, 0.99607, 0.996074,
200 0.996078, 0.996082, 0.996086, 0.99609, 0.996094, 0.996098, 0.996102,
201 0.996106, 0.99611, 0.996114, 0.996117, 0.996121, 0.996125, 0.996129,
202 0.996133, 0.996137, 0.996141, 0.996145, 0.996149, 0.996152, 0.996156,
205 # Run-time configuration parameters (can be set with command-line options)
212 $includeSunSpider=true
213 $includeLongSpider=true
217 $includeJSRegress=true
218 $includeAsmBench=true
220 $includeBrowsermarkJS=false
221 $includeBrowsermarkDOM=false
223 $includeCompressionBench = true
225 $benchmarkPattern=nil
227 $timeMode=:preciseTime
236 $needToCopyVMs = false
240 $sunSpiderWarmup = true
241 $configPath = Pathname.new(ENV["HOME"]) + ".run-jsc-benchmarks"
247 # Helpful functions and classes
250 puts "Use the --help option to get basic usage information."
255 puts "run-jsc-benchmarks [options] <vm1> [<vm2> ...]"
257 puts "Runs one or more JavaScript runtimes against SunSpider, V8, and/or Kraken"
258 puts "benchmarks, and reports detailed statistics. What makes run-jsc-benchmarks"
259 puts "special is that each benchmark/VM configuration is run in a single VM invocation,"
260 puts "and the invocations are run in random order. This minimizes systematics due to"
261 puts "one benchmark polluting the running time of another. The fine-grained"
262 puts "interleaving of VM invocations further minimizes systematics due to changes in"
263 puts "the performance or behavior of your machine."
265 puts "Run-jsc-benchmarks is highly configurable. You can compare as many VMs as you"
266 puts "like. You can change the amount of warm-up iterations, number of iterations"
267 puts "executed per VM invocation, and the number of VM invocations per benchmark."
269 puts "The <vm> should be either a path to a JavaScript runtime executable (such as"
270 puts "jsc), or a string of the form <name>:<path>, where the <path> is the path to"
271 puts "the executable and <name> is the name that you would like to give the"
272 puts "configuration for the purposeof reporting. If no name is given, a generic name"
273 puts "of the form Conf#<n> will be ascribed to the configuration automatically."
275 puts "It's also possible to specify per-VM environment variables. For example, you"
276 puts "might specify a VM like Foo:JSC_useJIT=false:/path/to/jsc, in which case the"
277 puts "harness will set the JSC_useJIT environment variable to false just before running"
278 puts "the given VM. Note that the harness will not unset the environment variable, so"
279 puts "you must ensure that your other VMs will use the opposite setting"
280 puts "(JSC_useJIT=true in this case)."
283 puts "--rerun <n> Set the number of iterations of the benchmark that"
284 puts " contribute to the measured run time. Default is #{$rerun}."
285 puts "--inner <n> Set the number of inner (per-runtime-invocation)"
286 puts " iterations. Default is #{$inner}."
287 puts "--outer <n> Set the number of runtime invocations for each benchmark."
288 puts " Default is #{$outer}."
289 puts "--warmup <n> Set the number of warm-up runs per invocation. Default"
290 puts " is #{$warmup}. This has a different effect on different kinds"
291 puts " benchmarks. Some benchmarks have no notion of warm-up."
292 puts "--no-ss-warmup Disable SunSpider-based warm-up runs."
293 puts "--quantum <n> Set the duration in milliseconds for which an iteration of"
294 puts " a throughput benchmark should be run. Default is #{$quantum}."
295 puts "--timing-mode Set the way that time is measured. Possible values"
296 puts " are 'preciseTime' and 'date'. Default is 'preciseTime'."
297 puts "--force-vm-kind Turn off auto-detection of VM kind, and assume that it is"
298 puts " the one specified. Valid arguments are 'jsc', "
299 puts " 'DumpRenderTree', or 'WebKitTestRunner'."
300 puts "--force-vm-copy Force VM builds to be copied to the working directory."
301 puts " This may reduce pathologies resulting from path names."
302 puts "--dont-copy-vms Don't copy VMs even when doing a remote benchmarking run;"
303 puts " instead assume that they are already there."
304 puts "--sunspider Only run SunSpider."
305 puts "--v8-spider Only run V8."
306 puts "--kraken Only run Kraken."
307 puts "--js-bench Only run JSBench."
308 puts "--js-regress Only run JSRegress."
309 puts "--dsp Only run DSP."
310 puts "--asm-bench Only run AsmBench."
311 puts "--browsermark-js Only run browsermark-js."
312 puts "--browsermark-dom Only run browsermark-dom."
313 puts "--octane Only run Octane."
314 puts "--compression-bench Only run compression bench"
315 puts " The default is to run all benchmarks. The above options can"
316 puts " be combined to run any subset (so --sunspider --dsp will run"
317 puts " both SunSpider and DSP)."
318 puts "--benchmarks Only run benchmarks matching the given regular expression."
319 puts "--measure-gc Turn off manual calls to gc(), so that GC time is measured."
320 puts " Works best with large values of --inner. You can also say"
321 puts " --measure-gc <conf>, which turns this on for one"
322 puts " configuration only."
323 puts "--verbose or -v Print more stuff."
324 puts "--brief Print only the final result for each VM."
325 puts "--silent Don't print progress. This might slightly reduce some"
326 puts " performance perturbation."
327 puts "--remote <sshhosts> Perform performance measurements remotely, on the given"
328 puts " SSH host(s). Easiest way to use this is to specify the SSH"
329 puts " user@host string. However, you can also supply a comma-"
330 puts " separated list of SSH hosts. Alternatively, you can use this"
331 puts " option multiple times to specify multiple hosts. This"
332 puts " automatically copies the WebKit release builds of the VMs"
333 puts " you specified to all of the hosts."
334 puts "--ssh-options Pass additional options to SSH."
335 puts "--local Also do a local benchmark run even when doing --remote."
336 puts "--vms Use a JSON file to specify which VMs to run, as opposed to"
337 puts " specifying them on the command line."
338 puts "--prepare-only Only prepare the runscript (a shell script that"
339 puts " invokes the VMs to run benchmarks) but don't run it."
340 puts "--analyze Only read the output of the runscript but don't do anything"
341 puts " else. This requires passing the same arguments that you"
342 puts " passed when running --prepare-only."
343 puts "--output-name Base of the filenames to put results into. Will write a file"
344 puts " called <base>_report.txt and <base>.json. By default this"
345 puts " name is automatically synthesized from the machine name,"
346 puts " date, set of benchmarks run, and set of configurations."
347 puts "--environment JSON file that specifies the environment variables that should"
348 puts " be used for particular VMs and benchmarks."
349 puts "--config <path> Specify the path of the configuration file. Defaults to"
350 puts " ~/.run-jsc-benchmarks"
351 puts "--help or -h Display this message."
354 puts "run-jsc-benchmarks TipOfTree:/Volumes/Data/pizlo/OpenSource/WebKitBuild/Release/jsc MyChanges:/Volumes/Data/pizlo/secondary/OpenSource/WebKitBuild/Release/jsc"
359 if reason.respond_to? :backtrace
360 puts "FAILED: #{reason.inspect}"
362 puts reason.backtrace.join("\n")
364 puts "FAILED: #{reason.inspect}"
370 $stderr.puts "#{$0}: #{r1}"
375 def intArg(argName,arg,min,max)
377 unless result.to_s == arg
378 quickFail("Expected an integer value for #{argName}, but got #{arg}.",
379 "Invalid argument for command-line option")
381 if min and result<min
382 quickFail("Argument for #{argName} cannot be smaller than #{min}.",
383 "Invalid argument for command-line option")
385 if max and result>max
386 quickFail("Argument for #{argName} cannot be greater than #{max}.",
387 "Invalid argument for command-line option")
392 def computeMean(array)
401 def computeGeometricMean(array)
405 sum += Math.log(value)
407 Math.exp(sum * (1.0/array.length))
410 def computeHarmonicMean(array)
411 1.0 / computeMean(array.collect{ | value | 1.0 / value })
414 def computeStdDev(array)
422 mean=computeMean(array)
426 sum += (value-mean)**2
428 Math.sqrt(sum/(array.length-1))
437 size.downto(1) { |n| push delete_at(rand(n)) }
442 def inverseBetaRegularized(n)
446 def numToStr(num, decimalShift)
447 ("%." + (4 + decimalShift).to_s + "f") % (num.to_f)
468 attr_reader :amountFaster
470 def initialize(amountFaster)
471 @amountFaster = amountFaster
479 " might be #{numToStr(@amountFaster, 0)}x faster"
483 if @amountFaster < 1.01
492 attr_reader :amountFaster
494 def initialize(amountFaster)
495 @amountFaster = amountFaster
503 "^ definitely #{numToStr(@amountFaster, 0)}x faster"
512 attr_reader :amountSlower
514 def initialize(amountSlower)
515 @amountSlower = amountSlower
523 "! definitely #{numToStr(@amountSlower, 0)}x slower"
532 attr_reader :amountSlower
534 def initialize(amountSlower)
535 @amountSlower = amountSlower
543 "? might be #{numToStr(@amountSlower, 0)}x slower"
547 if @amountSlower < 1.01
555 def jsonSanitize(value)
556 if value.is_a? Fixnum
558 elsif value.is_a? Float
559 if value.nan? or value.infinite?
564 elsif value.is_a? Array
565 value.map{|v| jsonSanitize(v)}
569 raise "Unrecognized value #{value.inspect}"
579 if not value or not @array
581 elsif value.is_a? Float
582 if value.nan? or value.infinite?
587 elsif value.is_a? Stats
589 elsif value.respond_to? :each
608 # TODO: We're probably still not handling this case correctly.
609 not @array or @array.empty?
654 stdDev/Math.sqrt(size)
657 # Computes a 95% Student's t distribution confidence interval
663 Math.sqrt(size-1.0)*stdErr*Math.sqrt(-1.0+1.0/inverseBetaRegularized(size-1))
676 computeGeometricMean(array)
680 computeHarmonicMean(array)
684 return CantSay.new unless ok? and other.ok?
686 if upper < other.lower
687 Faster.new(other.mean/mean)
688 elsif lower > other.upper
689 Slower.new(mean/other.mean)
690 elsif mean > other.mean
691 MayBeSlower.new(mean/other.mean)
693 NoChange.new(other.mean/mean)
698 "size = #{size}, mean = #{mean}, stdDev = #{stdDev}, stdErr = #{stdErr}, confInt = #{confInt}"
703 {"data"=>jsonSanitize(@array), "mean"=>jsonSanitize(mean), "confInt"=>jsonSanitize(confInt)}
710 def doublePuts(out1,out2,msg)
711 out1.puts "#{out2.path}: #{msg}" if $verbosity>=3
715 class Benchfile < File
718 attr_reader :filename, :basename
721 @basename, @filename = Benchfile.uniqueFilename(name)
722 super(@filename, "w")
725 def self.uniqueFilename(name)
727 basename = name[0] + @@counter.to_s + name[1]
729 basename = name + @@counter.to_s
731 filename = BENCH_DATA_PATH + basename
733 raise "Benchfile #{filename} already exists" if FileTest.exist?(filename)
737 def self.create(name)
738 file = Benchfile.new(name)
746 def ensureFile(key, filename)
747 unless $dataFiles[key]
748 $dataFiles[key] = Benchfile.create(key) {
750 doublePuts($stderr,outp,IO::read(filename))
756 # Helper for files that cannot be renamed.
758 def ensureAbsoluteFile(filename, basedir=nil)
759 return if $absoluteFiles[filename]
760 filename = Pathname.new(filename)
762 directory = Pathname.new('')
763 if basedir and filename.dirname != basedir
764 remainingPath = filename.dirname
765 while remainingPath != basedir
766 directory = remainingPath.basename + directory
767 remainingPath = remainingPath.dirname
769 if not $absoluteFiles[directory]
770 cmd = "mkdir -p #{Shellwords.shellescape((BENCH_DATA_PATH + directory).to_s)}"
771 $stderr.puts ">> #{cmd}" if $verbosity >= 2
772 raise unless system(cmd)
773 intermediateDirectory = Pathname.new(directory)
774 while intermediateDirectory.basename.to_s != "."
775 $absoluteFiles[intermediateDirectory] = true
776 intermediateDirectory = intermediateDirectory.dirname
781 cmd = "cp #{Shellwords.shellescape(filename.to_s)} #{Shellwords.shellescape((BENCH_DATA_PATH + directory + filename.basename).to_s)}"
782 $stderr.puts ">> #{cmd}" if $verbosity >= 2
783 raise unless system(cmd)
784 $absoluteFiles[filename] = true
787 # Helper for large benchmarks with lots of files and directories.
788 def ensureBenchmarkFiles(rootdir)
789 toProcess = [rootdir]
790 while not toProcess.empty?
791 currdir = toProcess.pop
792 Dir.foreach(currdir.to_s) {
794 path = currdir + filename
795 next if filename.match(/^\./)
796 toProcess.push(path) if File.directory?(path.to_s)
797 ensureAbsoluteFile(path, rootdir) if File.file?(path.to_s)
803 attr_reader :js, :html
804 def initialize(js, html)
810 def loadCommandForFile(key, filename)
811 file = ensureFile(key, filename)
812 JSCommand.new("load(#{file.inspect});", "<script src=#{file.inspect}></script>")
815 def simpleCommand(command)
816 JSCommand.new(command, "<script type=\"text/javascript\">#{command}</script>")
819 # Benchmark that consists of a single file and must be loaded in its own global object each
821 class SingleFileTimedBenchmarkParameters
822 attr_reader :benchPath
824 def initialize(benchPath)
825 @benchPath = benchPath
829 :singleFileTimedBenchmark
833 # Benchmark that consists of one or more data files that should be loaded globally, followed
834 # by a command to run the benchmark.
835 class MultiFileTimedBenchmarkParameters
836 attr_reader :dataPaths, :command
838 def initialize(dataPaths, command)
839 @dataPaths = dataPaths
844 :multiFileTimedBenchmark
848 # Benchmark that consists of one or more data files that should be loaded globally, followed
849 # by a command to run a short tick of the benchmark. The benchmark should be run for as many
850 # ticks as possible, for one quantum (quantum is 1000ms by default).
851 class ThroughputBenchmarkParameters
852 attr_reader :dataPaths, :setUpCommand, :command, :tearDownCommand, :doWarmup, :deterministic, :minimumIterations
854 def initialize(dataPaths, setUpCommand, command, tearDownCommand, doWarmup, deterministic, minimumIterations)
855 @dataPaths = dataPaths
856 @setUpCommand = setUpCommand
858 @tearDownCommand = tearDownCommand
860 @deterministic = deterministic
861 @minimumIterations = minimumIterations
869 # Benchmark that can only run in DumpRenderTree or WebKitTestRunner, that has its own callback for reporting
870 # results. Other than that it's just like SingleFileTimedBenchmark.
871 class SingleFileTimedCallbackBenchmarkParameters
872 attr_reader :callbackDecl, :benchPath
874 def initialize(callbackDecl, benchPath)
875 @callbackDecl = callbackDecl
876 @benchPath = benchPath
880 :singleFileTimedCallbackBenchmark
884 def emitTimerFunctionCode(file)
887 doublePuts($stderr,file,"function __bencher_curTimeMS() {")
888 doublePuts($stderr,file," return preciseTime()*1000")
889 doublePuts($stderr,file,"}")
891 doublePuts($stderr,file,"function __bencher_curTimeMS() {")
892 doublePuts($stderr,file," return Date.now()")
893 doublePuts($stderr,file,"}")
899 def emitBenchRunCodeFile(name, plan, benchParams)
902 Benchfile.create("bencher") {
904 emitTimerFunctionCode(file)
906 if benchParams.kind == :multiFileTimedBenchmark
907 benchParams.dataPaths.each {
909 doublePuts($stderr,file,"load(#{path.inspect});")
911 doublePuts($stderr,file,"gc();")
912 doublePuts($stderr,file,"for (var __bencher_index = 0; __bencher_index < #{$warmup+$inner}; ++__bencher_index) {")
913 doublePuts($stderr,file," var __before = __bencher_curTimeMS();")
915 doublePuts($stderr,file," #{benchParams.command.js}")
917 doublePuts($stderr,file," var __after = __bencher_curTimeMS();")
918 doublePuts($stderr,file," if (__bencher_index >= #{$warmup}) print(\"#{name}: #{plan.vm}: #{plan.iteration}: \" + (__bencher_index - #{$warmup}) + \": Time: \"+(__after-__before));");
919 doublePuts($stderr,file," gc();") unless plan.vm.shouldMeasureGC
920 doublePuts($stderr,file,"}")
921 elsif benchParams.kind == :throughputBenchmark
922 emitTimerFunctionCode(file)
923 benchParams.dataPaths.each {
925 doublePuts($stderr,file,"load(#{path.inspect});")
927 doublePuts($stderr,file,"#{benchParams.setUpCommand.js}")
928 if benchParams.doWarmup
933 doublePuts($stderr,file,"for (var __bencher_index = 0; __bencher_index < #{warmup + $inner}; __bencher_index++) {")
934 doublePuts($stderr,file," var __before = __bencher_curTimeMS();")
935 doublePuts($stderr,file," var __after = __before;")
936 doublePuts($stderr,file," var __runs = 0;")
937 doublePuts($stderr,file," var __expected = #{$quantum};")
938 doublePuts($stderr,file," while (true) {")
940 doublePuts($stderr,file," #{benchParams.command.js}")
942 doublePuts($stderr,file," __runs++;")
943 doublePuts($stderr,file," __after = __bencher_curTimeMS();")
944 if benchParams.deterministic
945 doublePuts($stderr,file," if (true) {")
947 doublePuts($stderr,file," if (__after - __before >= __expected) {")
949 doublePuts($stderr,file," if (__runs >= #{benchParams.minimumIterations} || __bencher_index < #{warmup})")
950 doublePuts($stderr,file," break;")
951 doublePuts($stderr,file," __expected += #{$quantum}")
952 doublePuts($stderr,file," }")
953 doublePuts($stderr,file," }")
954 doublePuts($stderr,file," if (__bencher_index >= #{warmup}) print(\"#{name}: #{plan.vm}: #{plan.iteration}: \" + (__bencher_index - #{warmup}) + \": Time: \"+((__after-__before)/__runs));")
955 doublePuts($stderr,file,"}")
956 doublePuts($stderr,file,"#{benchParams.tearDownCommand.js}")
958 raise unless benchParams.kind == :singleFileTimedBenchmark
959 doublePuts($stderr,file,"function __bencher_run(__bencher_what) {")
960 doublePuts($stderr,file," var __bencher_before = __bencher_curTimeMS();")
962 doublePuts($stderr,file," run(__bencher_what);")
964 doublePuts($stderr,file," var __bencher_after = __bencher_curTimeMS();")
965 doublePuts($stderr,file," return __bencher_after - __bencher_before;")
966 doublePuts($stderr,file,"}")
968 doublePuts($stderr,file,"__bencher_run(#{benchParams.benchPath.inspect})")
969 doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC
973 doublePuts($stderr,file,"print(\"#{name}: #{plan.vm}: #{plan.iteration}: #{innerIndex}: Time: \"+__bencher_run(#{benchParams.benchPath.inspect}));")
974 doublePuts($stderr,file,"gc();") unless plan.vm.shouldMeasureGC
978 when :dumpRenderTree, :webkitTestRunner
981 curTime = "(testRunner.preciseTime()*1000)"
983 curTime = "(Date.now())"
988 mainCode = Benchfile.create("bencher") {
990 doublePuts($stderr,file,"__bencher_count = 0;")
991 doublePuts($stderr,file,"function __bencher_doNext(result) {")
992 doublePuts($stderr,file," if (__bencher_count >= #{$warmup})")
993 doublePuts($stderr,file," debug(\"#{name}: #{plan.vm}: #{plan.iteration}: \" + (__bencher_count - #{$warmup}) + \": Time: \" + result);")
994 doublePuts($stderr,file," __bencher_count++;")
995 doublePuts($stderr,file," if (__bencher_count < #{$inner+$warmup})")
996 doublePuts($stderr,file," __bencher_runImpl(__bencher_doNext);")
997 doublePuts($stderr,file," else")
998 doublePuts($stderr,file," quit();")
999 doublePuts($stderr,file,"}")
1000 doublePuts($stderr,file,"__bencher_runImpl(__bencher_doNext);")
1003 cssCode = Benchfile.create("bencher-css") {
1005 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 white-space: pre-wrap;\n font-family: monospace;\n}")
1008 preCode = Benchfile.create("bencher-pre") {
1010 doublePuts($stderr,file,"if (window.testRunner) {")
1011 doublePuts($stderr,file," testRunner.dumpAsText(window.enablePixelTesting);")
1012 doublePuts($stderr,file," testRunner.waitUntilDone();")
1013 doublePuts($stderr,file,"}")
1014 doublePuts($stderr,file,"")
1015 doublePuts($stderr,file,"function debug(msg)")
1016 doublePuts($stderr,file,"{")
1017 doublePuts($stderr,file," var span = document.createElement(\"span\");")
1018 doublePuts($stderr,file," document.getElementById(\"console\").appendChild(span); // insert it first so XHTML knows the namespace")
1019 doublePuts($stderr,file," span.innerHTML = msg + '<br />';")
1020 doublePuts($stderr,file,"}")
1021 doublePuts($stderr,file,"")
1022 doublePuts($stderr,file,"function quit() {")
1023 doublePuts($stderr,file," testRunner.notifyDone();")
1024 doublePuts($stderr,file,"}")
1025 doublePuts($stderr,file,"")
1026 doublePuts($stderr,file,"__bencher_continuation=null;")
1027 doublePuts($stderr,file,"")
1028 doublePuts($stderr,file,"function reportResult(result) {")
1029 doublePuts($stderr,file," __bencher_continuation(result);")
1030 doublePuts($stderr,file,"}")
1031 if benchParams.kind == :singleFileTimedCallbackBenchmark
1032 doublePuts($stderr,file,"")
1033 doublePuts($stderr,file,benchParams.callbackDecl)
1035 doublePuts($stderr,file,"")
1036 doublePuts($stderr,file,"function __bencher_runImpl(continuation) {")
1037 doublePuts($stderr,file," function doit() {")
1038 doublePuts($stderr,file," document.getElementById(\"frameparent\").innerHTML = \"\";")
1039 doublePuts($stderr,file," document.getElementById(\"frameparent\").innerHTML = \"<iframe id='testframe'>\";")
1040 doublePuts($stderr,file," var testFrame = document.getElementById(\"testframe\");")
1041 doublePuts($stderr,file," testFrame.contentDocument.open();")
1042 doublePuts($stderr,file," testFrame.contentDocument.write(\"<!DOCTYPE html>\\n<head></head><body><div id=\\\"console\\\"></div>\");")
1043 if benchParams.kind == :throughputBenchmark or benchParams.kind == :multiFileTimedBenchmark
1044 benchParams.dataPaths.each {
1046 doublePuts($stderr,file," testFrame.contentDocument.write(\"<script src=#{path.inspect.inspect[1..-2]}></script>\");")
1049 if benchParams.kind == :throughputBenchmark
1050 if benchParams.doWarmup
1055 doublePuts($stderr,file," testFrame.contentDocument.write(\"<script type=\\\"text/javascript\\\">\");")
1056 doublePuts($stderr,file," testFrame.contentDocument.write(\"#{benchParams.setUpCommand.js}\");")
1057 doublePuts($stderr,file," testFrame.contentDocument.write(\"var __bencher_before = #{curTime};\");")
1058 doublePuts($stderr,file," testFrame.contentDocument.write(\"var __bencher_after = __bencher_before;\");")
1059 doublePuts($stderr,file," testFrame.contentDocument.write(\"var __bencher_expected = #{$quantum};\");")
1060 doublePuts($stderr,file," testFrame.contentDocument.write(\"var __bencher_runs = 0;\");")
1061 doublePuts($stderr,file," testFrame.contentDocument.write(\"while (true) {\");")
1062 doublePuts($stderr,file," testFrame.contentDocument.write(\" #{benchParams.command.js}\");")
1063 doublePuts($stderr,file," testFrame.contentDocument.write(\" __bencher_runs++;\");")
1064 doublePuts($stderr,file," testFrame.contentDocument.write(\" __bencher_after = #{curTime};\");")
1065 if benchParams.deterministic
1066 doublePuts($stderr,file," testFrame.contentDocument.write(\" if (true) {\");")
1068 doublePuts($stderr,file," testFrame.contentDocument.write(\" if (__bencher_after - __bencher_before >= __bencher_expected) {\");")
1070 doublePuts($stderr,file," testFrame.contentDocument.write(\" if (__bencher_runs >= #{benchParams.minimumIterations} || window.parent.__bencher_count < #{warmup})\");")
1071 doublePuts($stderr,file," testFrame.contentDocument.write(\" break;\");")
1072 doublePuts($stderr,file," testFrame.contentDocument.write(\" __bencher_expected += #{$quantum}\");")
1073 doublePuts($stderr,file," testFrame.contentDocument.write(\" }\");")
1074 doublePuts($stderr,file," testFrame.contentDocument.write(\"}\");")
1075 doublePuts($stderr,file," testFrame.contentDocument.write(\"#{benchParams.tearDownCommand.js}\");")
1076 doublePuts($stderr,file," testFrame.contentDocument.write(\"window.parent.reportResult((__bencher_after - __bencher_before) / __bencher_runs);\");")
1077 doublePuts($stderr,file," testFrame.contentDocument.write(\"</script>\");")
1079 doublePuts($stderr,file," testFrame.contentDocument.write(\"<script type=\\\"text/javascript\\\">var __bencher_before = #{curTime};</script>\");")
1080 if benchParams.kind == :multiFileTimedBenchmark
1081 doublePuts($stderr,file," testFrame.contentDocument.write(#{benchParams.command.html.inspect});")
1083 doublePuts($stderr,file," testFrame.contentDocument.write(\"<script src=#{benchParams.benchPath.inspect.inspect[1..-2]}></script>\");")
1085 unless benchParams.kind == :singleFileTimedCallbackBenchmark
1086 doublePuts($stderr,file," testFrame.contentDocument.write(\"<script type=\\\"text/javascript\\\">window.parent.reportResult(#{curTime} - __bencher_before);</script>\");")
1089 doublePuts($stderr,file," testFrame.contentDocument.write(\"</body></html>\");")
1090 doublePuts($stderr,file," testFrame.contentDocument.close();")
1091 doublePuts($stderr,file," }")
1092 doublePuts($stderr,file," __bencher_continuation = continuation;")
1093 doublePuts($stderr,file," window.setTimeout(doit, 10);")
1094 doublePuts($stderr,file,"}")
1097 Benchfile.create(["bencher-htmldoc",".html"]) {
1099 doublePuts($stderr,file,"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n<html><head><link rel=\"stylesheet\" href=\"#{cssCode}\"><script src=\"#{preCode}\"></script></head><body><div id=\"console\"></div><div id=\"frameparent\"></div><script src=\"#{mainCode}\"></script></body></html>")
1106 def emitBenchRunCode(name, plan, benchParams)
1107 plan.vm.emitRunCode(emitBenchRunCodeFile(name, plan, benchParams), plan)
1111 def initialize(filename)
1112 @filename = filename
1117 $script.print "echo #{Shellwords.shellescape(text)}"
1122 $script.print " >> "
1124 $script.puts "#{Shellwords.shellescape(@filename)}"
1129 $script.puts "rm -f #{Shellwords.shellescape(text)}"
1130 $script.puts "touch #{Shellwords.shellescape(text)}"
1134 def self.open(filename)
1135 outp = FileCreator.new(filename)
1141 def emitSelfContainedBenchRunCode(name, plan, targetFile, configFile, benchmark)
1142 FileCreator.open(configFile) {
1144 outp.puts "__bencher_message = \"#{name}: #{plan.vm}: #{plan.iteration}: \";"
1145 outp.puts "__bencher_warmup = #{$warmup};"
1146 outp.puts "__bencher_inner = #{$inner};"
1147 outp.puts "__bencher_benchmark = #{benchmark.to_json};"
1150 outp.puts "__bencher_curTime = (function(){ return testRunner.preciseTime() * 1000; });"
1152 outp.puts "__bencher_curTime = (function(){ return Date.now(); });"
1158 plan.vm.emitRunCode(targetFile, plan)
1161 def planForDescription(string, plans, benchFullname, vmName, iteration)
1162 raise "Unexpected benchmark full name: #{benchFullname.inspect}, string: #{string.inspect}" unless benchFullname =~ /\//
1163 suiteName = $~.pre_match
1164 return nil if suiteName == "WARMUP"
1165 benchName = $~.post_match
1166 result = plans.select{|v| v.suite.name == suiteName and v.benchmark.name == benchName and v.vm.name == vmName and v.iteration == iteration}
1167 raise "Unexpected result dimensions: #{result.inspect}, string: #{string.inspect}" unless result.size == 1
1172 attr_reader :plan, :innerIndex, :time, :result
1174 def initialize(plan, innerIndex, time)
1176 @innerIndex = innerIndex
1184 raise unless @plan.is_a? BenchPlan
1185 raise unless @innerIndex.is_a? Integer
1186 raise unless @time.is_a? Numeric or @result == :error
1205 def self.create(plan, innerIndex, time)
1207 ParsedResult.new(plan, innerIndex, time)
1213 def self.parse(plans, string)
1214 if string =~ /([a-zA-Z0-9\/_.-]+): ([a-zA-Z0-9_#. ]+): ([0-9]+): ([0-9]+): Time: /
1217 outerIndex = $3.to_i
1218 innerIndex = $4.to_i
1219 time = $~.post_match.to_f
1220 ParsedResult.create(planForDescription(string, plans, benchFullname, vmName, outerIndex), innerIndex, time)
1221 elsif string =~ /([a-zA-Z0-9\/_.-]+): ([a-zA-Z0-9_#. ]+): ([0-9]+): ([0-9]+): CRASHED/
1224 outerIndex = $3.to_i
1225 innerIndex = $4.to_i
1226 time = $~.post_match.to_f
1227 ParsedResult.create(planForDescription(string, plans, benchFullname, vmName, outerIndex), innerIndex, :crashed)
1237 def initialize(origPath, name, nameKind, svnRevision)
1238 @origPath = origPath.to_s
1239 @path = origPath.to_s
1241 @nameKind = nameKind
1245 @vmType = $forceVMKind
1247 if @origPath =~ /DumpRenderTree$/
1248 @vmType = :dumpRenderTree
1249 elsif @origPath =~ /WebKitTestRunner$/
1250 @vmType = :webkitTestRunner
1256 @svnRevision = svnRevision
1258 # Try to detect information about the VM.
1259 if path =~ /\/WebKitBuild\/(Release|Debug)+\/([a-zA-Z]+)$/
1260 @checkoutPath = $~.pre_match
1261 # FIXME: Use some variant of this:
1262 # <bdash> def retrieve_revision
1263 # <bdash> `perl -I#{@path}/Tools/Scripts -MVCSUtils -e 'print svnRevisionForDirectory("#{@path}");'`.to_i
1267 Dir.chdir(@checkoutPath) {
1268 $stderr.puts ">> cd #{@checkoutPath} && svn info" if $verbosity>=2
1269 IO.popen("svn info", "r") {
1273 if line =~ /Revision: ([0-9]+)/
1280 $stderr.puts "Warning: running svn info for #{name} silently failed."
1283 # Failed to detect svn revision.
1284 $stderr.puts "Warning: could not get svn revision information for #{name}: #{e}"
1288 $stderr.puts "Warning: could not identify checkout location for #{name}"
1291 if @path =~ /\/Release\/([a-zA-Z]+)$/
1292 @libPath, @relativeBinPath = [$~.pre_match+"/Release"], "./#{$1}"
1293 elsif @path =~ /\/Debug\/([a-zA-Z]+)$/
1294 @libPath, @relativeBinPath = [$~.pre_match+"/Debug"], "./#{$1}"
1295 elsif @path =~ /\/Contents\/Resources\/([a-zA-Z]+)$/
1296 @libPath = [$~.pre_match + "/Contents/Resources", $~.pre_match + "/Contents/Frameworks"]
1297 elsif @path =~ /\/JavaScriptCore.framework\/Resources\/([a-zA-Z]+)$/
1298 @libPath, @relativeBinPath = [$~.pre_match], $&[1..-1]
1299 elsif @path =~ /(DumpRenderTree|webkitTestRunner|jsc)$/
1300 @libPath, @relativeBinPath = [$~.pre_match+"/"], "./#{$1}"
1304 def canCopyIntoBenchPath
1305 if @libPath and @relativeBinPath
1312 def addExtraEnv(key, val)
1313 @extraEnv[key] = val
1314 @@extraEnvSet[key] = true
1317 def copyIntoBenchPath
1318 raise unless canCopyIntoBenchPath
1319 basename, filename = Benchfile.uniqueFilename("vm")
1320 raise unless Dir.mkdir(filename)
1323 cmd = "cp -a #{Shellwords.shellescape(libPathPart)}/* #{Shellwords.shellescape(filename.to_s)}"
1324 $stderr.puts ">> #{cmd}" if $verbosity>=2
1325 raise unless system(cmd)
1327 @path = "#{basename}/#{@relativeBinPath}"
1328 @libPath = [basename]
1340 $measureGC == true or ($measureGC == name)
1375 when :dumpRenderTree, :webkitTestRunner
1382 def emitRunCode(fileToRun, plan)
1383 myLibPath = @libPath
1384 myLibPath = [] unless myLibPath
1385 @@extraEnvSet.keys.each {
1387 $script.puts "unset #{Shellwords.shellescape(key)}"
1389 $script.puts "export DYLD_LIBRARY_PATH=#{Shellwords.shellescape(myLibPath.join(':').to_s)}"
1390 $script.puts "export DYLD_FRAMEWORK_PATH=#{Shellwords.shellescape(myLibPath.join(':').to_s)}"
1391 @extraEnv.each_pair {
1393 $script.puts "export #{Shellwords.shellescape(key)}=#{Shellwords.shellescape(val)}"
1395 plan.environment.each_pair {
1397 $script.puts "export #{Shellwords.shellescape(key)}=#{Shellwords.shellescape(val)}"
1399 $script.puts "#{path} #{fileToRun} 2>&1 || {"
1400 $script.puts " echo " + Shellwords.shellescape("#{name} failed to run!") + " 1>&2"
1403 $script.puts " echo " + Shellwords.shellescape("#{plan.prefix}: #{iteration}: CRASHED")
1406 plan.environment.keys.each {
1408 $script.puts "export #{Shellwords.shellescape(key)}="
1413 class StatsAccumulator
1416 ($outer*$inner).times {
1421 def statsForIteration(outerIteration, innerIteration)
1422 @stats[outerIteration*$inner + innerIteration]
1430 result.add(yield stat)
1438 def geometricMeanStats
1445 def arithmeticMeanStats
1454 attr_accessor :benchmarkSuite
1458 benchmarkSuite.name + "/" + name
1470 raise unless weight.is_a? Fixnum
1471 raise unless weight >= 1
1480 class SunSpiderBenchmark
1483 def initialize(name)
1487 def emitRunCode(plan)
1488 emitBenchRunCode(fullname, plan, SingleFileTimedBenchmarkParameters.new(ensureFile("SunSpider-#{@name}", "#{SUNSPIDER_PATH}/#{@name}.js")))
1492 class LongSpiderBenchmark
1495 def initialize(name)
1499 def emitRunCode(plan)
1500 emitBenchRunCode(fullname, plan, SingleFileTimedBenchmarkParameters.new(ensureFile("LongSpider-#{@name}", "#{LONGSPIDER_PATH}/#{@name}.js")))
1507 def initialize(name)
1511 def emitRunCode(plan)
1512 emitBenchRunCode(fullname, plan, SingleFileTimedBenchmarkParameters.new(ensureFile("V8-#{@name}", "#{V8_PATH}/v8-#{@name}.js")))
1516 class V8RealBenchmark
1519 attr_reader :v8SuiteName
1521 def initialize(v8SuiteName, name, weight, minimumIterations)
1522 @v8SuiteName = v8SuiteName
1525 @minimumIterations = minimumIterations
1532 def emitRunCode(plan)
1533 emitBenchRunCode(fullname, plan, ThroughputBenchmarkParameters.new(["base", @v8SuiteName, "jsc-#{@name}"].collect{|v| ensureFile("V8Real-#{v}", "#{V8_REAL_PATH}/#{v}.js")}, simpleCommand("jscSetUp();"), simpleCommand("jscRun();"), simpleCommand("jscTearDown();"), true, false, @minimumIterations))
1537 class OctaneBenchmark
1540 def initialize(files, name, weight, doWarmup, deterministic, minimumIterations)
1544 @doWarmup = doWarmup
1545 @deterministic = deterministic
1546 @minimumIterations = minimumIterations
1553 def emitRunCode(plan)
1555 files += (["base"] + @files).collect {
1557 ensureFile("Octane-#{v}", "#{OCTANE_PATH}/#{v}.js")
1559 files += ["jsc-#{@name}"].collect {
1561 ensureFile("Octane-#{v}", "#{OCTANE_WRAPPER_PATH}/#{v}.js")
1563 emitBenchRunCode(fullname, plan, ThroughputBenchmarkParameters.new(files, simpleCommand("jscSetUp();"), simpleCommand("jscRun();"), simpleCommand("jscTearDown();"), @doWarmup, @deterministic, @minimumIterations))
1567 class KrakenBenchmark
1570 def initialize(name)
1574 def emitRunCode(plan)
1575 emitBenchRunCode(fullname, plan, MultiFileTimedBenchmarkParameters.new([ensureFile("KrakenData-#{@name}", "#{KRAKEN_PATH}/#{@name}-data.js")], loadCommandForFile("Kraken-#{@name}", "#{KRAKEN_PATH}/#{@name}.js")))
1579 class JSBenchBenchmark
1582 attr_reader :jsBenchMode
1584 def initialize(name, jsBenchMode)
1586 @jsBenchMode = jsBenchMode
1589 def emitRunCode(plan)
1590 callbackDecl = "function JSBNG_handleResult(result) {\n"
1591 callbackDecl += " if (result.error) {\n"
1592 callbackDecl += " console.log(\"Did not run benchmark correctly!\");\n"
1593 callbackDecl += " quit();\n"
1594 callbackDecl += " }\n"
1595 callbackDecl += " reportResult(result.time);\n"
1596 callbackDecl += "}\n"
1597 emitBenchRunCode(fullname, plan, SingleFileTimedCallbackBenchmarkParameters.new(callbackDecl, ensureFile("JSBench-#{@name}", "#{JSBENCH_PATH}/#{@name}/#{@jsBenchMode}.js")))
1601 class JSRegressBenchmark
1604 def initialize(name)
1608 def emitRunCode(plan)
1609 emitBenchRunCode(fullname, plan, SingleFileTimedBenchmarkParameters.new(ensureFile("JSRegress-#{@name}", "#{JSREGRESS_PATH}/#{@name}.js")))
1613 class AsmBenchBenchmark
1616 def initialize(name)
1620 def emitRunCode(plan)
1621 emitBenchRunCode(fullname, plan, SingleFileTimedBenchmarkParameters.new(ensureFile("AsmBench-#{@name}", "#{ASMBENCH_PATH}/#{@name}.js")))
1626 class CompressionBenchBenchmark
1629 def initialize(files, name, model)
1632 @name = name + "-" + model if !model.empty?
1633 @name = @name.gsub(" ", "-").downcase
1637 @deterministic = true
1638 @minimumIterations = 1
1646 def emitRunCode(plan)
1647 emitBenchRunCode(fullname, plan, ThroughputBenchmarkParameters.new((["base"] + @files + ["jsc-#{@scriptName}"]).collect{|v| ensureFile("Compression-#{v}", "#{COMPRESSIONBENCH_PATH}/#{v}.js")}, simpleCommand("jscSetUp('#{@model}');"), simpleCommand("jscRun();"), simpleCommand("jscTearDown();"), @doWarmup, @deterministic, @minimumIterations))
1651 class DSPJSFiltrrBenchmark
1654 def initialize(name, filterKey)
1656 @filterKey = filterKey
1659 def emitRunCode(plan)
1660 ensureAbsoluteFile(DSPJS_FILTRR_PATH + "filtrr.js")
1661 ensureAbsoluteFile(DSPJS_FILTRR_PATH + "filtrr_back.jpg")
1662 ensureAbsoluteFile(DSPJS_FILTRR_PATH + "filtrr-jquery.min.js")
1663 ensureAbsoluteFile(DSPJS_FILTRR_PATH + "filtrr-bencher.html")
1664 emitSelfContainedBenchRunCode(fullname, plan, "filtrr-bencher.html", "bencher-config.js", @filterKey)
1668 class DSPJSVP8Benchmark
1672 @name = "route9-vp8"
1679 def emitRunCode(plan)
1680 ensureBenchmarkFiles(DSPJS_ROUTE9_PATH)
1681 emitSelfContainedBenchRunCode(fullname, plan, "route9-bencher.html", "bencher-config.js", "")
1685 class DSPStarfieldBenchmark
1696 def emitRunCode(plan)
1697 ensureBenchmarkFiles(DSPJS_STARFIELD_PATH)
1698 emitSelfContainedBenchRunCode(fullname, plan, "starfield-bencher.html", "bencher-config.js", "")
1702 class DSPJSJSLinuxBenchmark
1705 @name = "bellard-jslinux"
1712 def emitRunCode(plan)
1713 ensureBenchmarkFiles(DSPJS_JSLINUX_PATH)
1714 emitSelfContainedBenchRunCode(fullname, plan, "jslinux-bencher.html", "bencher-config.js", "")
1718 class DSPJSQuake3Benchmark
1722 @name = "zynaps-quake3"
1729 def emitRunCode(plan)
1730 ensureBenchmarkFiles(DSPJS_QUAKE3_PATH)
1731 emitSelfContainedBenchRunCode(fullname, plan, "quake-bencher.html", "bencher-config.js", "")
1735 class DSPJSMandelbrotBenchmark
1739 @name = "zynaps-mandelbrot"
1746 def emitRunCode(plan)
1747 ensureBenchmarkFiles(DSPJS_MANDELBROT_PATH)
1748 emitSelfContainedBenchRunCode(fullname, plan, "mandelbrot-bencher.html", "bencher-config.js", "")
1752 class DSPJSAmmoJSASMBenchmark
1756 @name = "ammojs-asm-js"
1763 def emitRunCode(plan)
1764 ensureBenchmarkFiles(DSPJS_AMMOJS_ASMJS_PATH)
1765 emitSelfContainedBenchRunCode(fullname, plan, "ammo-asmjs-bencher.html", "bencher-config.js", "")
1769 class DSPJSAmmoJSRegularBenchmark
1773 @name = "ammojs-regular-js"
1780 def emitRunCode(plan)
1781 ensureBenchmarkFiles(DSPJS_AMMOJS_REGULAR_PATH)
1782 emitSelfContainedBenchRunCode(fullname, plan, "ammo-regular-bencher.html", "bencher-config.js", "")
1786 class BrowsermarkJSBenchmark
1789 def initialize(name)
1793 def emitRunCode(plan)
1794 emitBenchRunCode(fullname, plan, ThroughputBenchmarkParameters.new([ensureFile(name, "#{BROWSERMARK_JS_PATH}/#{name}/test.js"), ensureFile("browsermark-bencher", "#{BROWSERMARK_JS_PATH}/browsermark-bencher.js")], simpleCommand("jscSetUp();"), simpleCommand("jscRun();"), simpleCommand("jscTearDown();"), true, 32))
1798 class BrowsermarkDOMBenchmark
1801 def initialize(name)
1805 def emitRunCode(plan)
1806 ensureBenchmarkFiles(BROWSERMARK_PATH)
1807 emitSelfContainedBenchRunCode(fullname, plan, "tests/benchmarks/dom/#{name}/index.html", "bencher-config.js", name)
1811 class BenchmarkSuite
1812 def initialize(name, preferredMean, decimalShift)
1814 @preferredMean = preferredMean
1817 @decimalShift = decimalShift
1832 def addIgnoringPattern(benchmark)
1833 benchmark.benchmarkSuite = self
1834 @benchmarks << benchmark
1838 if not $benchmarkPattern or "#{@name}/#{benchmark.name}" =~ $benchmarkPattern
1839 addIgnoringPattern(benchmark)
1843 def addSubSuite(subSuite)
1844 @subSuites << subSuite
1851 def benchmarkForName(name)
1852 result = @benchmarks.select{|v| v.name == name}
1853 raise unless result.length == 1
1857 def hasBenchmark(benchmark)
1858 array = @benchmarks.select{|v| v == benchmark}
1859 raise unless array.length == 1 or array.length == 0
1871 def suitesWithBenchmark(benchmark)
1875 if subSuite.hasBenchmark(benchmark)
1887 @benchmarks.delete_if {
1897 def computeMean(stat)
1899 (stat.send @preferredMean) * (10 ** decimalShift)
1907 def initialize(benchmark, vm, iteration)
1908 @benchmark = benchmark
1910 @iteration = iteration
1912 if $environment.has_key?(vm.name)
1913 if $environment[vm.name].has_key?(benchmark.benchmarkSuite.name)
1914 if $environment[vm.name][benchmark.benchmarkSuite.name].has_key?(benchmark.name)
1915 @environment = $environment[vm.name][benchmark.benchmarkSuite.name][benchmark.name]
1926 @benchmark.benchmarkSuite
1942 "#{@benchmark.fullname}: #{vm.name}: #{iteration}"
1946 @benchmark.emitRunCode(self)
1950 benchmark.to_s + "/" + vm.to_s
1955 def initialize(benchmark, suiteOnVM, subSuitesOnVM)
1956 @benchmark = benchmark
1957 @suiteOnVM = suiteOnVM
1958 @subSuitesOnVM = subSuitesOnVM
1963 "#{@benchmark} on #{@suiteOnVM.vm}"
1979 @benchmark.benchmarkSuite
1994 def parseResult(result)
1995 raise "VM mismatch; I've got #{vm} and they've got #{result.vm}" unless result.vm == vm
1996 raise unless result.benchmark == @benchmark
1997 @stats.add(result.time)
2001 class NamedStatsAccumulator < StatsAccumulator
2002 def initialize(name)
2012 class SuiteOnVM < StatsAccumulator
2013 def initialize(vm, vmStats, suite)
2019 raise unless @vm.is_a? VM
2020 raise unless @vmStats.is_a? StatsAccumulator
2021 raise unless @suite.is_a? BenchmarkSuite
2025 "#{@suite} on #{@vm}"
2041 raise unless @vmStats
2046 class SubSuiteOnVM < StatsAccumulator
2047 def initialize(vm, suite)
2051 raise unless @vm.is_a? VM
2052 raise unless @suite.is_a? BenchmarkSuite
2056 "#{@suite} on #{@vm}"
2073 def initialize(benchmarkOnVM, iteration)
2074 @benchmarkOnVM = benchmarkOnVM
2075 @iteration = iteration
2079 "#{@benchmarkOnVM} \##{@iteration+1}"
2087 @benchmarkOnVM.benchmark
2091 @benchmarkOnVM.suite
2102 def parseResult(result)
2103 raise unless result.plan == self
2104 @benchmarkOnVM.parseResult(result)
2105 benchmark.weight.times {
2106 @benchmarkOnVM.vmStats.statsForIteration(@iteration, result.innerIndex).add(result.time)
2107 @benchmarkOnVM.suiteOnVM.statsForIteration(@iteration, result.innerIndex).add(result.time)
2108 @benchmarkOnVM.subSuitesOnVM.each {
2110 subSuite.statsForIteration(@iteration, result.innerIndex).add(result.time)
2125 while str.length < chars
2131 def center(str,chars)
2132 while str.length<chars
2141 def statsToStr(stats, decimalShift)
2143 lpad(center("ERROR", 10+10+2), 12+10+2)
2144 elsif $inner*$outer == 1
2145 string = numToStr(stats.mean, decimalShift)
2146 raise unless string =~ /\./
2148 right = $~.post_match
2149 lpad(left, 13 - decimalShift) + "." + rpad(right, 10 + decimalShift)
2151 lpad(numToStr(stats.mean, decimalShift), 12) + "+-" + rpad(numToStr(stats.confInt, decimalShift), 10)
2163 def wrap(str, columns)
2166 curLine = array.shift
2169 if (curLine + " " + curStr).size > columns
2170 result += curLine + "\n"
2173 curLine += " " + curStr
2176 result + curLine + "\n"
2179 def runAndGetResults
2181 Dir.chdir(BENCH_DATA_PATH) {
2182 $stderr.puts ">> sh ./runscript" if $verbosity >= 2
2183 raise "Script did not complete correctly: #{$?}" unless system("sh ./runscript > runlog")
2184 results = IO::read("runlog")
2186 raise unless results
2190 def parseAndDisplayResults(results)
2194 vmStatses << NamedStatsAccumulator.new(vm.name)
2198 suitesOnVMsForSuite = {}
2199 subSuitesOnVMsForSubSuite = {}
2202 suitesOnVMsForSuite[suite] = []
2203 suite.subSuites.each {
2205 subSuitesOnVMsForSubSuite[subSuite] = []
2208 suitesOnVMsForVM = {}
2211 suitesOnVMsForVM[vm] = []
2214 benchmarksOnVMs = []
2215 benchmarksOnVMsForBenchmark = {}
2218 benchmarksOnVMsForBenchmark[benchmark] = []
2221 $vms.each_with_index {
2223 vmStats = vmStatses[vmIndex]
2226 suiteOnVM = SuiteOnVM.new(vm, vmStats, suite)
2227 subSuitesOnVM = suite.subSuites.map {
2229 result = SubSuiteOnVM.new(vm, subSuite)
2230 subSuitesOnVMsForSubSuite[subSuite] << result
2233 suitesOnVMs << suiteOnVM
2234 suitesOnVMsForSuite[suite] << suiteOnVM
2235 suitesOnVMsForVM[vm] << suiteOnVM
2236 suite.benchmarks.each {
2238 subSuitesOnVMForThisBenchmark = []
2239 subSuitesOnVM.each {
2241 if subSuiteOnVM.suite.hasBenchmark(benchmark)
2242 subSuitesOnVMForThisBenchmark << subSuiteOnVM
2245 benchmarkOnVM = BenchmarkOnVM.new(benchmark, suiteOnVM, subSuitesOnVMForThisBenchmark)
2246 benchmarksOnVMs << benchmarkOnVM
2247 benchmarksOnVMsForBenchmark[benchmark] << benchmarkOnVM
2253 benchmarksOnVMs.each {
2257 plans << BenchPlan.new(benchmarkOnVM, iteration)
2266 if line =~ /HOSTNAME:([^.]+)/
2268 elsif line =~ /HARDWARE:hw\.model: /
2269 hwmodel = $~.post_match.chomp
2271 result = ParsedResult.parse(plans, line)
2273 result.plan.parseResult(result)
2278 # Compute the geomean of the preferred means of results on a SuiteOnVM
2287 curResult = Stats.new
2288 suitesOnVMsForVM[vm].each {
2290 # For a given iteration, suite, and VM, compute the suite's preferred mean
2291 # over the data collected for all benchmarks in that suite. We'll have one
2292 # sample per benchmark. For example on V8 this will be the geomean of 1
2293 # sample for crypto, 1 sample for deltablue, and so on, and 1 sample for
2295 curResult.add(suiteOnVM.suite.computeMean(suiteOnVM.statsForIteration(outerIndex, innerIndex)))
2298 # curResult now holds 1 sample for each of the means computed in the above
2299 # loop. Compute the geomean over this, and store it.
2301 result.add(curResult.geometricMean)
2308 # $overallResults will have a Stats for each VM. That Stats object will hold
2309 # $inner*$outer geomeans, allowing us to compute the arithmetic mean and
2310 # confidence interval of the geomeans of preferred means. Convoluted, but
2311 # useful and probably sound.
2312 overallResults << result
2316 benchmarksOnVMs.each {
2318 $stderr.puts "#{benchmarkOnVM}: #{benchmarkOnVM.stats}"
2321 $vms.each_with_index {
2323 vmStats = vmStatses[vmIndex]
2324 $stderr.puts "#{vm} (arithmeticMean): #{vmStats.arithmeticMeanStats}"
2325 $stderr.puts "#{vm} (geometricMean): #{vmStats.geometricMeanStats}"
2330 reportName = $outputName
2339 text = $vms.collect {
2360 "%04d%02d%02d_%02d%02d" %
2361 [ time.year, time.month, time.day,
2362 time.hour, time.min ]
2367 puts "Generating benchmark report at #{Dir.pwd}/#{reportName}_report.txt"
2368 puts "And raw data at #{Dir.pwd}/#{reportName}.json"
2374 outp = File.open(reportName + "_report.txt","w")
2376 $stderr.puts "Error: could not save report to #{reportName}_report.txt: #{e}"
2382 result += " " if $allSuites.size > 1
2383 result += rpad("", $benchpad + $weightpad)
2388 result += " "+NoChange.new(0).shortForm
2390 result += lpad(center($vms[index].name, 10+10+2), 12+10+2)
2394 result += center("#{$vms[-1].name} v. #{$vms[0].name}",26)
2395 elsif $vms.size >= 2
2404 elsif list.size == 2
2405 "#{list[0]} and #{list[1]}"
2407 "#{list[0..-2].join(', ')}, and #{list[-1]}"
2411 json["vms"] = $vms.collect{|v| v.name}
2413 json["runlog"] = results
2415 columns = [createVMsString.size, 78].max
2417 outp.print "Benchmark report for "
2418 outp.print andJoin($suites)
2420 outp.print " on #{hostname}"
2423 outp.print " (#{hwmodel})"
2428 outp.puts "VMs tested:"
2431 outp.print "\"#{vm.name}\" at #{vm.origPath}"
2433 outp.print " (r#{vm.svnRevision})"
2436 vm.extraEnv.each_pair {
2438 outp.puts " export #{key}=#{val}"
2444 outp.puts wrap("Collected #{$outer*$inner} sample#{plural($outer*$inner)} per benchmark/VM, "+
2445 "with #{$outer} VM invocation#{plural($outer)} per benchmark."+
2446 (if $rerun > 1 then (" Ran #{$rerun} benchmark iterations, and measured the "+
2447 "total time of those iterations, for each sample.")
2449 (if $measureGC == true then (" No manual garbage collection invocations were "+
2451 elsif $measureGC then (" Emitted a call to gc() between sample measurements for "+
2452 "all VMs except #{$measureGC}.")
2453 else (" Emitted a call to gc() between sample measurements.") end)+
2454 (if $warmup == 0 then (" Did not include any warm-up iterations; measurements "+
2455 "began with the very first iteration.")
2456 else (" Used #{$warmup*$rerun} benchmark iteration#{plural($warmup*$rerun)} per VM "+
2457 "invocation for warm-up.") end)+
2459 when :preciseTime then (" Used the jsc-specific preciseTime() function to get "+
2460 "microsecond-level timing.")
2461 when :date then (" Used the portable Date.now() method to get millisecond-"+
2464 " Reporting benchmark execution times with 95% confidence "+
2465 "intervals in milliseconds.",
2471 outp.puts createVMsString
2474 def summaryStats(outp, json, accumulators, name, decimalShift, &proc)
2476 outp.print " " if $allSuites.size > 1
2477 outp.print rpad(name, $benchpad + $weightpad)
2479 accumulators.size.times {
2482 outp.print " "+accumulators[index].stats(&proc).compareTo(accumulators[index-1].stats(&proc)).shortForm
2484 outp.print statsToStr(accumulators[index].stats(&proc), decimalShift)
2485 resultingJson[accumulators[index].reportingName] = accumulators[index].stats(&proc).jsonMap
2487 if accumulators.size>=2
2488 outp.print(" "+accumulators[-1].stats(&proc).compareTo(accumulators[0].stats(&proc)).longForm)
2491 json[name] = resultingJson
2494 def allSummaryStats(outp, json, accumulators, preferredMean, decimalShift)
2495 meanLabel = '<' + preferredMean.to_s.sub(/Mean$/, '') + '>'
2496 summaryStats(outp, json, accumulators, meanLabel, decimalShift) {
2498 stat.send(preferredMean)
2506 suite.subSuites.each {
2508 subSuiteJsons[subSuite] = {}
2512 if $allSuites.size > 1
2513 outp.puts(andJoin(suite.suites.map{|v| v.name}) + ":")
2517 suite.benchmarks.each {
2520 outp.print " " if $allSuites.size > 1
2521 outp.print rpad(benchmark.name, $benchpad) + rpad(benchmark.weightString, $weightpad)
2522 if benchmark.name.size > $benchNameClip
2524 outp.print " " if $allSuites.size > 1
2525 outp.print((" " * $benchpad) + (" " * $weightpad))
2528 myConfigs = benchmarksOnVMsForBenchmark[benchmark]
2529 myConfigs.size.times {
2532 outp.print " "+myConfigs[index].stats.compareTo(myConfigs[index-1].stats).shortForm
2534 outp.print statsToStr(myConfigs[index].stats, suite.decimalShift)
2535 benchmarkJson[myConfigs[index].vm.name] = myConfigs[index].stats.jsonMap
2538 outp.print(" "+myConfigs[-1].stats.compareTo(myConfigs[0].stats).to_s)
2541 suiteJson[benchmark.name] = benchmarkJson
2542 suite.subSuites.each {
2544 if subSuite.hasBenchmark(benchmark)
2545 subSuiteJsons[subSuite][benchmark.name] = benchmarkJson
2550 unless suite.subSuites.empty?
2551 suite.subSuites.each {
2553 outp.puts "#{subSuite.name}:"
2554 allSummaryStats(outp, subSuiteJsons[subSuite], subSuitesOnVMsForSubSuite[subSuite], subSuite.preferredMean, subSuite.decimalShift)
2557 outp.puts "#{suite.name} including #{andJoin(suite.subSuites.map{|v| v.name})}:"
2559 allSummaryStats(outp, suiteJson, suitesOnVMsForSuite[suite], suite.preferredMean, suite.decimalShift)
2560 outp.puts if $allSuites.size > 1
2562 json["suites"][suite.name] = suiteJson
2563 suite.subSuites.each {
2565 json["suites"][subSuite.name] = subSuiteJsons[subSuite]
2572 scaledResultJson = {}
2576 outp.puts "Geomean of preferred means:"
2578 outp.print rpad("<scaled-result>", $benchpad + $weightpad)
2583 outp.print " "+overallResults[index].compareTo(overallResults[index-1]).shortForm
2585 outp.print statsToStr(overallResults[index], 0)
2586 scaledResultJson[$vms[index].name] = overallResults[index].jsonMap
2588 if overallResults.size>=2
2589 outp.print(" "+overallResults[-1].compareTo(overallResults[0]).longForm)
2593 json["<scaled-result>"] = scaledResultJson
2601 if outp != $stdout and not $brief
2603 File.open(reportName + "_report.txt") {
2610 puts(overallResults.collect{|stats| stats.mean}.join("\t"))
2611 puts(overallResults.collect{|stats| stats.confInt}.join("\t"))
2614 File.open(reportName + ".json", "w") {
2616 outp.puts json.to_json
2621 $sawBenchOptions = false
2623 def resetBenchOptionsIfNecessary
2624 unless $sawBenchOptions
2625 $includeSunSpider = false
2626 $includeLongSpider = false
2628 $includeKraken = false
2629 $includeJSBench = false
2630 $includeJSRegress = false
2631 $includeAsmBench = false
2632 $includeDSPJS = false
2633 $includeBrowsermarkJS = false
2634 $includeBrowsermarkDOM = false
2635 $includeOctane = false
2636 $includeCompressionBench = false
2637 $sawBenchOptions = true
2641 GetoptLong.new(['--rerun', GetoptLong::REQUIRED_ARGUMENT],
2642 ['--inner', GetoptLong::REQUIRED_ARGUMENT],
2643 ['--outer', GetoptLong::REQUIRED_ARGUMENT],
2644 ['--warmup', GetoptLong::REQUIRED_ARGUMENT],
2645 ['--no-ss-warmup', GetoptLong::NO_ARGUMENT],
2646 ['--quantum', GetoptLong::REQUIRED_ARGUMENT],
2647 ['--minimum', GetoptLong::REQUIRED_ARGUMENT],
2648 ['--timing-mode', GetoptLong::REQUIRED_ARGUMENT],
2649 ['--sunspider', GetoptLong::NO_ARGUMENT],
2650 ['--longspider', GetoptLong::NO_ARGUMENT],
2651 ['--v8-spider', GetoptLong::NO_ARGUMENT],
2652 ['--kraken', GetoptLong::NO_ARGUMENT],
2653 ['--js-bench', GetoptLong::NO_ARGUMENT],
2654 ['--js-regress', GetoptLong::NO_ARGUMENT],
2655 ['--asm-bench', GetoptLong::NO_ARGUMENT],
2656 ['--dsp', GetoptLong::NO_ARGUMENT],
2657 ['--browsermark-js', GetoptLong::NO_ARGUMENT],
2658 ['--browsermark-dom', GetoptLong::NO_ARGUMENT],
2659 ['--octane', GetoptLong::NO_ARGUMENT],
2660 ['--compression-bench', GetoptLong::NO_ARGUMENT],
2661 ['--benchmarks', GetoptLong::REQUIRED_ARGUMENT],
2662 ['--measure-gc', GetoptLong::OPTIONAL_ARGUMENT],
2663 ['--force-vm-kind', GetoptLong::REQUIRED_ARGUMENT],
2664 ['--force-vm-copy', GetoptLong::NO_ARGUMENT],
2665 ['--dont-copy-vms', GetoptLong::NO_ARGUMENT],
2666 ['--verbose', '-v', GetoptLong::NO_ARGUMENT],
2667 ['--brief', GetoptLong::NO_ARGUMENT],
2668 ['--silent', GetoptLong::NO_ARGUMENT],
2669 ['--remote', GetoptLong::REQUIRED_ARGUMENT],
2670 ['--local', GetoptLong::NO_ARGUMENT],
2671 ['--ssh-options', GetoptLong::REQUIRED_ARGUMENT],
2672 ['--slave', GetoptLong::NO_ARGUMENT],
2673 ['--prepare-only', GetoptLong::NO_ARGUMENT],
2674 ['--analyze', GetoptLong::REQUIRED_ARGUMENT],
2675 ['--vms', GetoptLong::REQUIRED_ARGUMENT],
2676 ['--output-name', GetoptLong::REQUIRED_ARGUMENT],
2677 ['--environment', GetoptLong::REQUIRED_ARGUMENT],
2678 ['--config', GetoptLong::REQUIRED_ARGUMENT],
2679 ['--help', '-h', GetoptLong::NO_ARGUMENT]).each {
2683 $rerun = intArg(opt,arg,1,nil)
2685 $inner = intArg(opt,arg,1,nil)
2687 $outer = intArg(opt,arg,1,nil)
2689 $warmup = intArg(opt,arg,0,nil)
2690 when '--no-ss-warmup'
2691 $sunSpiderWarmup = false
2693 $quantum = intArg(opt,arg,1,nil)
2695 $minimum = intArg(opt,arg,1,nil)
2696 when '--timing-mode'
2697 if arg.upcase == "PRECISETIME"
2698 $timeMode = :preciseTime
2699 elsif arg.upcase == "DATE"
2701 elsif arg.upcase == "AUTO"
2704 quickFail("Expected either 'preciseTime', 'date', or 'auto' for --time-mode, but got '#{arg}'.",
2705 "Invalid argument for command-line option")
2707 when '--force-vm-kind'
2708 if arg.upcase == "JSC"
2710 elsif arg.upcase == "DUMPRENDERTREE"
2711 $forceVMKind = :dumpRenderTree
2712 elsif arg.upcase == "WEBKITTESTRUNNER"
2713 $forceVMKind = :webkitTestRunner
2714 elsif arg.upcase == "AUTO"
2717 quickFail("Expected 'jsc', 'DumpRenderTree', or 'WebKitTestRunner' for --force-vm-kind, but got '#{arg}'.",
2718 "Invalid argument for command-line option")
2720 when '--force-vm-copy'
2721 $needToCopyVMs = true
2722 when '--dont-copy-vms'
2725 resetBenchOptionsIfNecessary
2726 $includeSunSpider = true
2728 resetBenchOptionsIfNecessary
2729 $includeLongSpider = true
2731 resetBenchOptionsIfNecessary
2734 resetBenchOptionsIfNecessary
2735 $includeKraken = true
2737 resetBenchOptionsIfNecessary
2738 $includeJSBench = true
2740 resetBenchOptionsIfNecessary
2741 $includeJSRegress = true
2743 resetBenchOptionsIfNecessary
2744 $includeAsmBench = true
2746 resetBenchOptionsIfNecessary
2747 $includeDSPJS = true
2748 when '--browsermark-js'
2749 resetBenchOptionsIfNecessary
2750 $includeBrowsermarkJS = true
2751 when '--browsermark-dom'
2752 resetBenchOptionsIfNecessary
2753 $includeBrowsermarkDOM = true
2755 resetBenchOptionsIfNecessary
2756 $includeOctane = true
2757 when '--compression-bench'
2758 resetBenchOptionsIfNecessary
2759 $includeCompressionBench = true
2761 $benchmarkPattern = Regexp.new(arg)
2775 $remoteHosts += arg.split(',')
2776 $needToCopyVMs = true
2777 when '--ssh-options'
2781 when '--prepare-only'
2787 when '--output-name'
2790 JSON::parse(IO::read(arg)).each {
2792 path = Pathname.new(vmDescription["path"]).realpath
2793 if vmDescription["name"]
2794 name = vmDescription["name"]
2797 name = "Conf\##{$vms.length+1}"
2800 vm = VM.new(path, name, nameKind, nil)
2801 if vmDescription["env"]
2802 vmDescription["env"].each_pair {
2804 vm.addExtraEnv(key, val)
2809 when '--environment'
2810 $environment = JSON::parse(IO::read(arg))
2812 $configPath = Pathname.new(arg)
2816 raise "bad option: #{opt}"
2820 # Figure out the configuration
2821 if $configPath.file?
2822 config = JSON::parse(IO::read($configPath.to_s))
2826 OCTANE_PATH = config["OctanePath"]
2827 BROWSERMARK_PATH = config["BrowserMarkPath"]
2828 BROWSERMARK_JS_PATH = config["BrowserMarkJSPath"]
2829 BROWSERMARK_DOM_PATH = config["BrowserMarkDOMPath"]
2830 ASMBENCH_PATH = config["AsmBenchPath"]
2831 COMPRESSIONBENCH_PATH = config["CompressionBenchPath"]
2832 DSPJS_FILTRR_PATH = config["DSPJSFiltrrPath"]
2833 DSPJS_ROUTE9_PATH = config["DSPJSRoute9Path"]
2834 DSPJS_STARFIELD_PATH = config["DSPJSStarfieldPath"]
2835 DSPJS_QUAKE3_PATH = config["DSPJSQuake3Path"]
2836 DSPJS_MANDELBROT_PATH = config["DSPJSMandelbrotPath"]
2837 DSPJS_JSLINUX_PATH = config["DSPJSLinuxPath"]
2838 DSPJS_AMMOJS_ASMJS_PATH = config["DSPJSAmmoJSAsmJSPath"]
2839 DSPJS_AMMOJS_REGULAR_PATH = config["DSPJSAmmoJSRegularPath"]
2840 JSBENCH_PATH = config["JSBenchPath"]
2841 KRAKEN_PATH = config["KrakenPath"]
2843 # If the --dont-copy-vms option was passed, it overrides the --force-vm-copy option.
2845 $needToCopyVMs = false
2850 if vm =~ /([a-zA-Z0-9_ ]+):/
2855 name = "Conf\##{$vms.length+1}"
2859 while vm =~ /([a-zA-Z0-9_]+)=([a-zA-Z0-9_:]+):/
2863 $stderr.puts "#{name}: #{vm}" if $verbosity >= 1
2864 vm = VM.new(Pathname.new(vm).realpath, name, nameKind, nil)
2867 vm.addExtraEnv(pair[0], pair[1])
2873 quickFail("Please specify at least on configuraiton on the command line.",
2874 "Insufficient arguments")
2879 if vm.vmType == :jsc
2884 SUNSPIDER = BenchmarkSuite.new("SunSpider", :arithmeticMean, 0)
2885 WARMUP = BenchmarkSuite.new("WARMUP", :arithmeticMean, 0)
2886 ["3d-cube", "3d-morph", "3d-raytrace", "access-binary-trees",
2887 "access-fannkuch", "access-nbody", "access-nsieve",
2888 "bitops-3bit-bits-in-byte", "bitops-bits-in-byte", "bitops-bitwise-and",
2889 "bitops-nsieve-bits", "controlflow-recursive", "crypto-aes",
2890 "crypto-md5", "crypto-sha1", "date-format-tofte", "date-format-xparb",
2891 "math-cordic", "math-partial-sums", "math-spectral-norm", "regexp-dna",
2892 "string-base64", "string-fasta", "string-tagcloud",
2893 "string-unpack-code", "string-validate-input"].each {
2895 SUNSPIDER.add SunSpiderBenchmark.new(name)
2896 WARMUP.addIgnoringPattern SunSpiderBenchmark.new(name)
2899 LONGSPIDER = BenchmarkSuite.new("LongSpider", :geometricMean, 0)
2900 ["3d-cube", "3d-morph", "3d-raytrace", "access-binary-trees",
2901 "access-fannkuch", "access-nbody", "access-nsieve",
2902 "bitops-3bit-bits-in-byte", "bitops-bits-in-byte", "bitops-nsieve-bits",
2903 "controlflow-recursive", "crypto-aes", "crypto-md5", "crypto-sha1",
2904 "date-format-tofte", "date-format-xparb", "math-cordic",
2905 "math-partial-sums", "math-spectral-norm", "string-base64",
2906 "string-fasta", "string-tagcloud"].each {
2908 LONGSPIDER.add LongSpiderBenchmark.new(name)
2911 V8 = BenchmarkSuite.new("V8Spider", :geometricMean, 0)
2912 ["crypto", "deltablue", "earley-boyer", "raytrace",
2913 "regexp", "richards", "splay"].each {
2915 V8.add V8Benchmark.new(name)
2918 OCTANE = BenchmarkSuite.new("Octane", :geometricMean, 1)
2919 [[["crypto"], "encrypt", 1, true, false, 32],
2920 [["crypto"], "decrypt", 1, true, false, 32],
2921 [["deltablue"], "deltablue", 2, true, false, 32],
2922 [["earley-boyer"], "earley", 1, true, false, 32],
2923 [["earley-boyer"], "boyer", 1, true, false, 32],
2924 [["navier-stokes"], "navier-stokes", 2, true, false, 16],
2925 [["raytrace"], "raytrace", 2, true, false, 32],
2926 [["richards"], "richards", 2, true, false, 32],
2927 [["splay"], "splay", 2, true, false, 32],
2928 [["regexp"], "regexp", 2, false, false, 16],
2929 [["pdfjs"], "pdfjs", 2, false, false, 4],
2930 [["mandreel"], "mandreel", 2, false, false, 4],
2931 [["gbemu-part1", "gbemu-part2"], "gbemu", 2, false, false, 4],
2932 [["code-load"], "closure", 1, false, false, 16],
2933 [["code-load"], "jquery", 1, false, false, 16],
2934 [["box2d"], "box2d", 2, false, false, 8],
2935 [["zlib", "zlib-data"], "zlib", 2, false, true, 3],
2936 [["typescript", "typescript-input", "typescript-compiler"], "typescript", 2, false, true, 1]].each {
2938 OCTANE.add OctaneBenchmark.new(*args)
2941 KRAKEN = BenchmarkSuite.new("Kraken", :arithmeticMean, -1)
2942 ["ai-astar", "audio-beat-detection", "audio-dft", "audio-fft",
2943 "audio-oscillator", "imaging-darkroom", "imaging-desaturate",
2944 "imaging-gaussian-blur", "json-parse-financial",
2945 "json-stringify-tinderbox", "stanford-crypto-aes",
2946 "stanford-crypto-ccm", "stanford-crypto-pbkdf2",
2947 "stanford-crypto-sha256-iterative"].each {
2949 KRAKEN.add KrakenBenchmark.new(name)
2952 JSBENCH = BenchmarkSuite.new("JSBench", :arithmeticMean, 0)
2953 [["amazon", "urm"], ["facebook", "urem"], ["google", "urem"], ["twitter", "urem"],
2954 ["yahoo", "urem"]].each {
2956 JSBENCH.add JSBenchBenchmark.new(*nameAndMode)
2959 JSREGRESS = BenchmarkSuite.new("JSRegress", :geometricMean, 0)
2960 Dir.foreach(JSREGRESS_PATH) {
2962 if filename =~ /\.js$/
2964 JSREGRESS.add JSRegressBenchmark.new(name)
2968 ASMBENCH = BenchmarkSuite.new("AsmBench", :geometricMean, 0)
2970 Dir.foreach(ASMBENCH_PATH) {
2972 if filename =~ /\.js$/
2974 ASMBENCH.add AsmBenchBenchmark.new(name)
2979 COMPRESSIONBENCH = BenchmarkSuite.new("CompressionBench", :geometricMean, 0)
2980 [[["huffman", "compression-data"], "huffman", ""],
2981 [["arithmetic", "compression-data"], "arithmetic", "Simple"],
2982 [["arithmetic", "compression-data"], "arithmetic", "Precise"],
2983 [["arithmetic", "compression-data"], "arithmetic", "Complex Precise"],
2984 [["arithmetic", "compression-data"], "arithmetic", "Precise Order 0"],
2985 [["arithmetic", "compression-data"], "arithmetic", "Precise Order 1"],
2986 [["arithmetic", "compression-data"], "arithmetic", "Precise Order 2"],
2987 [["arithmetic", "compression-data"], "arithmetic", "Simple Order 1"],
2988 [["arithmetic", "compression-data"], "arithmetic", "Simple Order 2"],
2989 [["lz-string", "compression-data"], "lz-string", ""]
2992 COMPRESSIONBENCH.add CompressionBenchBenchmark.new(*args)
2995 DSPJS = BenchmarkSuite.new("DSP", :geometricMean, 0)
2996 DSPJS.add DSPJSFiltrrBenchmark.new("filtrr-posterize-tint", "e2")
2997 DSPJS.add DSPJSFiltrrBenchmark.new("filtrr-tint-contrast-sat-bright", "e5")
2998 DSPJS.add DSPJSFiltrrBenchmark.new("filtrr-tint-sat-adj-contr-mult", "e7")
2999 DSPJS.add DSPJSFiltrrBenchmark.new("filtrr-blur-overlay-sat-contr", "e8")
3000 DSPJS.add DSPJSFiltrrBenchmark.new("filtrr-sat-blur-mult-sharpen-contr", "e9")
3001 DSPJS.add DSPJSFiltrrBenchmark.new("filtrr-sepia-bias", "e10")
3002 DSPJS.add DSPJSVP8Benchmark.new
3003 DSPJS.add DSPStarfieldBenchmark.new
3004 DSPJS.add DSPJSJSLinuxBenchmark.new
3005 DSPJS.add DSPJSQuake3Benchmark.new
3006 DSPJS.add DSPJSMandelbrotBenchmark.new
3007 DSPJS.add DSPJSAmmoJSASMBenchmark.new
3008 DSPJS.add DSPJSAmmoJSRegularBenchmark.new
3010 BROWSERMARK_JS = BenchmarkSuite.new("BrowsermarkJS", :geometricMean, 1)
3011 ["array_blur", "array_weighted", "string_chat", "string_filter", "string_weighted"].each {
3013 BROWSERMARK_JS.add BrowsermarkJSBenchmark.new(name)
3016 BROWSERMARK_DOM = BenchmarkSuite.new("BrowsermarkDOM", :geometricMean, 1)
3017 ["advanced_search", "create_source", "dynamic_create", "search"].each {
3019 BROWSERMARK_DOM.add BrowsermarkDOMBenchmark.new(name)
3024 if $includeSunSpider and not SUNSPIDER.empty?
3025 $suites << SUNSPIDER
3028 if $includeLongSpider and not LONGSPIDER.empty?
3029 $suites << LONGSPIDER
3032 if $includeV8 and not V8.empty?
3036 if $includeOctane and not OCTANE.empty?
3040 $stderr.puts "Warning: refusing to run Octane because \"OctanePath\" isn't set in #{$configPath}."
3044 if $includeKraken and not KRAKEN.empty?
3048 $stderr.puts "Warning: refusing to run Kraken because \"KrakenPath\" isn't set in #{$configPath}."
3052 if $includeJSBench and not JSBENCH.empty?
3057 $stderr.puts "Warning: refusing to run JSBench because \"JSBenchPath\" isn't set in #{$configPath}"
3060 $stderr.puts "Warning: refusing to run JSBench because not all VMs are DumpRenderTree or WebKitTestRunner."
3064 if $includeJSRegress and not JSREGRESS.empty?
3065 $suites << JSREGRESS
3068 if $includeAsmBench and not ASMBENCH.empty?
3072 $stderr.puts "Warning: refusing to run AsmBench because \"AsmBenchPath\" isn't set in #{$configPath}."
3076 if $includeDSPJS and not DSPJS.empty?
3078 if DSPJS_FILTRR_PATH and DSPJS_ROUTE9_PATH and DSPJS_STARFIELD_PATH and DSPJS_QUAKE3_PATH and DSPJS_MANDELBROT_PATH and DSPJS_JSLINUX_PATH and DSPJS_AMMOJS_ASMJS_PATH and DSPJS_AMMOJS_REGULAR_PATH
3081 $stderr.puts "Warning: refusing to run DSPJS because one of the following isn't set in #{$configPath}: \"DSPJSFiltrrPath\", \"DSPJSRoute9Path\", \"DSPJSStarfieldPath\", \"DSPJSQuake3Path\", \"DSPJSMandelbrotPath\", \"DSPJSLinuxPath\", \"DSPJSAmmoJSAsmJSPath\", \"DSPJSAmmoJSRegularPath\"."
3084 $stderr.puts "Warning: refusing to run DSPJS because not all VMs are DumpRenderTree or WebKitTestRunner."
3088 if $includeBrowsermarkJS and not BROWSERMARK_JS.empty?
3089 if BROWSERMARK_PATH and BROWSERMARK_JS_PATH
3090 $suites << BROWSERMARK_JS
3092 $stderr.puts "Warning: refusing to run Browsermark-JS because one of the following isn't set in #{$configPath}: \"BrowserMarkPath\" or \"BrowserMarkJSPath\"."
3096 if $includeBrowsermarkDOM and not BROWSERMARK_DOM.empty?
3098 if BROWSERMARK_PATH and BROWSERMARK_JS_PATH and BROWSERMARK_DOM_PATH
3099 $suites << BROWSERMARK_DOM
3101 $stderr.puts "Warning: refusing to run Browsermark-DOM because one of the following isn't set in #{$configPath}: \"BrowserMarkPath\", \"BrowserMarkJSPath\", or \"BrowserMarkDOMPath\"."
3104 $stderr.puts "Warning: refusing to run Browsermark-DOM because not all VMs are DumpRenderTree or WebKitTestRunner."
3108 if $includeCompressionBench and not COMPRESSIONBENCH.empty?
3109 if COMPRESSIONBENCH_PATH
3110 $suites << COMPRESSIONBENCH
3112 $stderr.puts "Warning: refusing to run CompressionBench because \"CompressionBenchPath\" isn't set in #{$configPath}"
3116 $allSuites = $suites.map{|v| v.suites}.flatten(1)
3121 $benchmarks += suite.benchmarks
3124 if $suites.empty? or $benchmarks.empty?
3125 $stderr.puts "No benchmarks found. Bailing out."
3129 if $outer*$inner == 1
3130 $stderr.puts "Warning: will only collect one sample per benchmark/VM. Confidence interval calculation will fail."
3133 $stderr.puts "Using timeMode = #{$timeMode}." if $verbosity >= 1
3142 $runPlans << BenchRunPlan.new(benchmark, vm, iteration)
3153 WARMUP.benchmarks.each {
3155 warmupPlans << BenchRunPlan.new(benchmark, vm, 0)
3159 $runPlans = warmupPlans.shuffle + $runPlans
3162 $suitepad = $suites.collect {
3167 $planpad = $runPlans.collect {
3172 maxBenchNameLength =
3173 ($benchmarks + ["<arithmetic> *", "<geometric> *", "<harmonic> *"]).collect {
3175 if benchmark.respond_to? :name
3182 $benchpad = [maxBenchNameLength, $benchNameClip].min + 1
3184 $weightpad = $benchmarks.collect {
3186 benchmark.weightString.size
3189 $vmpad = $vms.collect {
3194 $analyze.each_with_index {
3199 parseAndDisplayResults(IO::read(filename))
3202 if not $prepare and not $run
3206 if FileTest.exist? BENCH_DATA_PATH
3207 cmd = "rm -rf #{BENCH_DATA_PATH}"
3208 $stderr.puts ">> #{cmd}" if $verbosity >= 2
3209 raise unless system cmd
3212 Dir.mkdir BENCH_DATA_PATH
3215 canCopyIntoBenchPath = true
3218 canCopyIntoBenchPath = false unless vm.canCopyIntoBenchPath
3221 if canCopyIntoBenchPath
3224 $stderr.puts "Copying #{vm} into #{BENCH_DATA_PATH}..."
3225 vm.copyIntoBenchPath
3227 $stderr.puts "All VMs are in place."
3229 $stderr.puts "Warning: don't know how to copy some VMs into #{BENCH_DATA_PATH}, so I won't do it."
3233 if $measureGC and $measureGC != true
3237 if vm.name == $measureGC
3242 $stderr.puts "Warning: --measure-gc option ignored because no VM is named #{$measureGC}"
3247 File.open("#{BENCH_DATA_PATH}/runscript", "w") {
3249 file.puts "echo \"HOSTNAME:\\c\""
3250 file.puts "hostname"
3252 file.puts "echo \"HARDWARE:\\c\""
3253 file.puts "/usr/sbin/sysctl hw.model"
3257 $runPlans.each_with_index {
3259 if $verbosity == 0 and not $silent
3260 text1 = lpad(idx.to_s,$runPlans.size.to_s.size)+"/"+$runPlans.size.to_s
3262 file.puts("echo " + Shellwords.shellescape("\r#{text1} #{rpad(text2,$planpad)}") + "\"\\c\" 1>&2")
3263 file.puts("echo " + Shellwords.shellescape("\r#{text1} #{text2}") + "\"\\c\" 1>&2")
3267 if $verbosity == 0 and not $silent
3268 file.puts("echo " + Shellwords.shellescape("\r#{$runPlans.size}/#{$runPlans.size} #{' '*($suitepad+1+$benchpad+1+$vmpad)}") + "\"\\c\" 1>&2")
3269 file.puts("echo " + Shellwords.shellescape("\r#{$runPlans.size}/#{$runPlans.size}") + " 1>&2")
3275 unless $remoteHosts.empty?
3276 $stderr.puts "Packaging benchmarking directory for remote hosts..." if $verbosity==0
3277 Dir.chdir(TEMP_PATH) {
3278 cmd = "tar -czf payload.tar.gz benchdata"
3279 $stderr.puts ">> #{cmd}" if $verbosity>=2
3280 raise unless system(cmd)
3284 if host =~ /:([0-9]+)$/
3285 "-p " + $1 + " " + Shellwords.shellescape($~.pre_match)
3287 Shellwords.shellescape(host)
3291 def sshRead(host, command)
3292 cmd = "ssh #{$sshOptions.collect{|x| Shellwords.shellescape(x)}.join(' ')} #{grokHost(host)} #{Shellwords.shellescape(command)}"
3293 $stderr.puts ">> #{cmd}" if $verbosity>=2
3295 IO.popen(cmd, "r") {
3299 $stderr.puts "#{host}: #{line}" if $verbosity>=2
3303 raise "#{$?}" unless $?.success?
3307 def sshWrite(host, command, data)
3308 cmd = "ssh #{$sshOptions.collect{|x| Shellwords.shellescape(x)}.join(' ')} #{grokHost(host)} #{Shellwords.shellescape(command)}"
3309 $stderr.puts ">> #{cmd}" if $verbosity>=2
3310 IO.popen(cmd, "w") {
3314 raise "#{$?}" unless $?.success?
3319 $stderr.puts "Sending benchmark payload to #{host}..." if $verbosity==0
3321 remoteTempPath = JSON::parse(sshRead(host, "cat ~/.bencher"))["tempPath"]
3322 raise unless remoteTempPath
3324 sshWrite(host, "cd #{Shellwords.shellescape(remoteTempPath)} && rm -rf benchdata && tar -xz", IO::read("#{TEMP_PATH}/payload.tar.gz"))
3326 $stderr.puts "Running on #{host}..." if $verbosity==0
3328 parseAndDisplayResults(sshRead(host, "cd #{Shellwords.shellescape(remoteTempPath + '/benchdata')} && sh runscript"))
3332 if not $remoteHosts.empty? and $alsoLocal
3333 $stderr.puts "Running locally..."
3336 if $remoteHosts.empty? or $alsoLocal
3337 parseAndDisplayResults(runAndGetResults)
3341 if $prepare and not $run and $analyze.empty?
3342 puts wrap("Benchmarking script and data are in #{BENCH_DATA_PATH}. You can run "+
3343 "the benchmarks and get the results by doing:", 78)
3345 puts "cd #{BENCH_DATA_PATH}"
3346 puts "sh runscript > results.txt"
3348 puts wrap("Then you can analyze the results by running bencher with the same arguments "+
3349 "as now, but replacing --prepare-only with --analyze results.txt.", 78)