1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/v8/base.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,284 @@ 1.4 +// Copyright 2012 the V8 project authors. All rights reserved. 1.5 +// Redistribution and use in source and binary forms, with or without 1.6 +// modification, are permitted provided that the following conditions are 1.7 +// met: 1.8 +// 1.9 +// * Redistributions of source code must retain the above copyright 1.10 +// notice, this list of conditions and the following disclaimer. 1.11 +// * Redistributions in binary form must reproduce the above 1.12 +// copyright notice, this list of conditions and the following 1.13 +// disclaimer in the documentation and/or other materials provided 1.14 +// with the distribution. 1.15 +// * Neither the name of Google Inc. nor the names of its 1.16 +// contributors may be used to endorse or promote products derived 1.17 +// from this software without specific prior written permission. 1.18 +// 1.19 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.20 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.21 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.22 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.23 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.24 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.25 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.26 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.27 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.28 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.29 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.30 + 1.31 + 1.32 +// Simple framework for running the benchmark suites and 1.33 +// computing a score based on the timing measurements. 1.34 + 1.35 + 1.36 +// A benchmark has a name (string) and a function that will be run to 1.37 +// do the performance measurement. The optional setup and tearDown 1.38 +// arguments are functions that will be invoked before and after 1.39 +// running the benchmark, but the running time of these functions will 1.40 +// not be accounted for in the benchmark score. 1.41 +function Benchmark(name, run, setup, tearDown) { 1.42 + this.name = name; 1.43 + this.run = run; 1.44 + this.Setup = setup ? setup : function() { }; 1.45 + this.TearDown = tearDown ? tearDown : function() { }; 1.46 +} 1.47 + 1.48 + 1.49 +// Benchmark results hold the benchmark and the measured time used to 1.50 +// run the benchmark. The benchmark score is computed later once a 1.51 +// full benchmark suite has run to completion. 1.52 +function BenchmarkResult(benchmark, time) { 1.53 + this.benchmark = benchmark; 1.54 + this.time = time; 1.55 +} 1.56 + 1.57 + 1.58 +// Automatically convert results to numbers. Used by the geometric 1.59 +// mean computation. 1.60 +BenchmarkResult.prototype.valueOf = function() { 1.61 + return this.time; 1.62 +} 1.63 + 1.64 + 1.65 +// Suites of benchmarks consist of a name and the set of benchmarks in 1.66 +// addition to the reference timing that the final score will be based 1.67 +// on. This way, all scores are relative to a reference run and higher 1.68 +// scores implies better performance. 1.69 +function BenchmarkSuite(name, reference, benchmarks) { 1.70 + this.name = name; 1.71 + this.reference = reference; 1.72 + this.benchmarks = benchmarks; 1.73 + BenchmarkSuite.suites.push(this); 1.74 +} 1.75 + 1.76 + 1.77 +// Keep track of all declared benchmark suites. 1.78 +BenchmarkSuite.suites = []; 1.79 + 1.80 + 1.81 +// Scores are not comparable across versions. Bump the version if 1.82 +// you're making changes that will affect that scores, e.g. if you add 1.83 +// a new benchmark or change an existing one. 1.84 +BenchmarkSuite.version = '7'; 1.85 + 1.86 + 1.87 +// To make the benchmark results predictable, we replace Math.random 1.88 +// with a 100% deterministic alternative. 1.89 +Math.random = (function() { 1.90 + var seed = 49734321; 1.91 + return function() { 1.92 + // Robert Jenkins' 32 bit integer hash function. 1.93 + seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff; 1.94 + seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff; 1.95 + seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff; 1.96 + seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff; 1.97 + seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff; 1.98 + seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff; 1.99 + return (seed & 0xfffffff) / 0x10000000; 1.100 + }; 1.101 +})(); 1.102 + 1.103 + 1.104 +// Runs all registered benchmark suites and optionally yields between 1.105 +// each individual benchmark to avoid running for too long in the 1.106 +// context of browsers. Once done, the final score is reported to the 1.107 +// runner. 1.108 +BenchmarkSuite.RunSuites = function(runner) { 1.109 + var continuation = null; 1.110 + var suites = BenchmarkSuite.suites; 1.111 + var length = suites.length; 1.112 + BenchmarkSuite.scores = []; 1.113 + var index = 0; 1.114 + function RunStep() { 1.115 + while (continuation || index < length) { 1.116 + if (continuation) { 1.117 + continuation = continuation(); 1.118 + } else { 1.119 + var suite = suites[index++]; 1.120 + if (runner.NotifyStart) runner.NotifyStart(suite.name); 1.121 + continuation = suite.RunStep(runner); 1.122 + } 1.123 + if (continuation && typeof window != 'undefined' && window.setTimeout) { 1.124 + window.setTimeout(RunStep, 25); 1.125 + return; 1.126 + } 1.127 + } 1.128 + if (runner.NotifyScore) { 1.129 + var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores); 1.130 + var formatted = BenchmarkSuite.FormatScore(100 * score); 1.131 + runner.NotifyScore(formatted); 1.132 + } 1.133 + } 1.134 + RunStep(); 1.135 +} 1.136 + 1.137 + 1.138 +// Counts the total number of registered benchmarks. Useful for 1.139 +// showing progress as a percentage. 1.140 +BenchmarkSuite.CountBenchmarks = function() { 1.141 + var result = 0; 1.142 + var suites = BenchmarkSuite.suites; 1.143 + for (var i = 0; i < suites.length; i++) { 1.144 + result += suites[i].benchmarks.length; 1.145 + } 1.146 + return result; 1.147 +} 1.148 + 1.149 + 1.150 +// Computes the geometric mean of a set of numbers. 1.151 +BenchmarkSuite.GeometricMean = function(numbers) { 1.152 + var log = 0; 1.153 + for (var i = 0; i < numbers.length; i++) { 1.154 + log += Math.log(numbers[i]); 1.155 + } 1.156 + return Math.pow(Math.E, log / numbers.length); 1.157 +} 1.158 + 1.159 + 1.160 +// Converts a score value to a string with at least three significant 1.161 +// digits. 1.162 +BenchmarkSuite.FormatScore = function(value) { 1.163 + if (value > 100) { 1.164 + return value.toFixed(0); 1.165 + } else { 1.166 + return value.toPrecision(3); 1.167 + } 1.168 +} 1.169 + 1.170 +// Notifies the runner that we're done running a single benchmark in 1.171 +// the benchmark suite. This can be useful to report progress. 1.172 +BenchmarkSuite.prototype.NotifyStep = function(result) { 1.173 + this.results.push(result); 1.174 + if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name); 1.175 +} 1.176 + 1.177 + 1.178 +// Notifies the runner that we're done with running a suite and that 1.179 +// we have a result which can be reported to the user if needed. 1.180 +BenchmarkSuite.prototype.NotifyResult = function() { 1.181 + var mean = BenchmarkSuite.GeometricMean(this.results); 1.182 + var score = this.reference / mean; 1.183 + BenchmarkSuite.scores.push(score); 1.184 + if (this.runner.NotifyResult) { 1.185 + var formatted = BenchmarkSuite.FormatScore(100 * score); 1.186 + this.runner.NotifyResult(this.name, formatted); 1.187 + } 1.188 +} 1.189 + 1.190 + 1.191 +// Notifies the runner that running a benchmark resulted in an error. 1.192 +BenchmarkSuite.prototype.NotifyError = function(error) { 1.193 + if (this.runner.NotifyError) { 1.194 + this.runner.NotifyError(this.name, error); 1.195 + } 1.196 + if (this.runner.NotifyStep) { 1.197 + this.runner.NotifyStep(this.name); 1.198 + } 1.199 +} 1.200 + 1.201 + 1.202 +// Runs a single benchmark for at least a second and computes the 1.203 +// average time it takes to run a single iteration. 1.204 +BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark, data) { 1.205 + function Measure(data) { 1.206 + var elapsed = 0; 1.207 + var start = new Date(); 1.208 + for (var n = 0; elapsed < 1000; n++) { 1.209 + benchmark.run(); 1.210 + elapsed = new Date() - start; 1.211 + } 1.212 + if (data != null) { 1.213 + data.runs += n; 1.214 + data.elapsed += elapsed; 1.215 + } 1.216 + } 1.217 + 1.218 + if (data == null) { 1.219 + // Measure the benchmark once for warm up and throw the result 1.220 + // away. Return a fresh data object. 1.221 + Measure(null); 1.222 + return { runs: 0, elapsed: 0 }; 1.223 + } else { 1.224 + Measure(data); 1.225 + // If we've run too few iterations, we continue for another second. 1.226 + if (data.runs < 32) return data; 1.227 + var usec = (data.elapsed * 1000) / data.runs; 1.228 + this.NotifyStep(new BenchmarkResult(benchmark, usec)); 1.229 + return null; 1.230 + } 1.231 +} 1.232 + 1.233 + 1.234 +// This function starts running a suite, but stops between each 1.235 +// individual benchmark in the suite and returns a continuation 1.236 +// function which can be invoked to run the next benchmark. Once the 1.237 +// last benchmark has been executed, null is returned. 1.238 +BenchmarkSuite.prototype.RunStep = function(runner) { 1.239 + this.results = []; 1.240 + this.runner = runner; 1.241 + var length = this.benchmarks.length; 1.242 + var index = 0; 1.243 + var suite = this; 1.244 + var data; 1.245 + 1.246 + // Run the setup, the actual benchmark, and the tear down in three 1.247 + // separate steps to allow the framework to yield between any of the 1.248 + // steps. 1.249 + 1.250 + function RunNextSetup() { 1.251 + if (index < length) { 1.252 + try { 1.253 + suite.benchmarks[index].Setup(); 1.254 + } catch (e) { 1.255 + suite.NotifyError(e); 1.256 + return null; 1.257 + } 1.258 + return RunNextBenchmark; 1.259 + } 1.260 + suite.NotifyResult(); 1.261 + return null; 1.262 + } 1.263 + 1.264 + function RunNextBenchmark() { 1.265 + try { 1.266 + data = suite.RunSingleBenchmark(suite.benchmarks[index], data); 1.267 + } catch (e) { 1.268 + suite.NotifyError(e); 1.269 + return null; 1.270 + } 1.271 + // If data is null, we're done with this benchmark. 1.272 + return (data == null) ? RunNextTearDown : RunNextBenchmark(); 1.273 + } 1.274 + 1.275 + function RunNextTearDown() { 1.276 + try { 1.277 + suite.benchmarks[index++].TearDown(); 1.278 + } catch (e) { 1.279 + suite.NotifyError(e); 1.280 + return null; 1.281 + } 1.282 + return RunNextSetup; 1.283 + } 1.284 + 1.285 + // Start out running the setup. 1.286 + return RunNextSetup(); 1.287 +}