[JAEGER] Add instrumentation for v8-deltablue.

This commit is contained in:
David Anderson 2010-08-02 10:49:14 -07:00
parent b4effc041b
commit b0e3e8c7ff

View File

@ -1,3 +1,269 @@
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Simple framework for running the benchmark suites and
// computing a score based on the timing measurements.
// A benchmark has a name (string) and a function that will be run to
// do the performance measurement. The optional setup and tearDown
// arguments are functions that will be invoked before and after
// running the benchmark, but the running time of these functions will
// not be accounted for in the benchmark score.
function Benchmark(name, run, setup, tearDown) {
this.name = name;
this.run = run;
this.Setup = setup ? setup : function() { };
this.TearDown = tearDown ? tearDown : function() { };
}
// Benchmark results hold the benchmark and the measured time used to
// run the benchmark. The benchmark score is computed later once a
// full benchmark suite has run to completion.
function BenchmarkResult(benchmark, time) {
this.benchmark = benchmark;
this.time = time;
}
// Automatically convert results to numbers. Used by the geometric
// mean computation.
BenchmarkResult.prototype.valueOf = function() {
return this.time;
}
// Suites of benchmarks consist of a name and the set of benchmarks in
// addition to the reference timing that the final score will be based
// on. This way, all scores are relative to a reference run and higher
// scores implies better performance.
function BenchmarkSuite(name, reference, benchmarks) {
this.name = name;
this.reference = reference;
this.benchmarks = benchmarks;
BenchmarkSuite.suites.push(this);
}
// Keep track of all declared benchmark suites.
BenchmarkSuite.suites = [];
// Scores are not comparable across versions. Bump the version if
// you're making changes that will affect that scores, e.g. if you add
// a new benchmark or change an existing one.
BenchmarkSuite.version = '5';
// To make the benchmark results predictable, we replace Math.random
// with a 100% deterministic alternative.
Math.random = (function() {
var seed = 49734321;
return function() {
// Robert Jenkins' 32 bit integer hash function.
seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff;
seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
return (seed & 0xfffffff) / 0x10000000;
};
})();
// Runs all registered benchmark suites and optionally yields between
// each individual benchmark to avoid running for too long in the
// context of browsers. Once done, the final score is reported to the
// runner.
BenchmarkSuite.RunSuites = function(runner) {
var continuation = null;
var suites = BenchmarkSuite.suites;
var length = suites.length;
BenchmarkSuite.scores = [];
var index = 0;
function RunStep() {
while (continuation || index < length) {
if (continuation) {
continuation = continuation();
} else {
var suite = suites[index++];
if (runner.NotifyStart) runner.NotifyStart(suite.name);
continuation = suite.RunStep(runner);
}
if (continuation && typeof window != 'undefined' && window.setTimeout) {
window.setTimeout(RunStep, 25);
return;
}
}
if (runner.NotifyScore) {
var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores);
var formatted = BenchmarkSuite.FormatScore(100 * score);
runner.NotifyScore(formatted);
}
}
RunStep();
}
// Counts the total number of registered benchmarks. Useful for
// showing progress as a percentage.
BenchmarkSuite.CountBenchmarks = function() {
var result = 0;
var suites = BenchmarkSuite.suites;
for (var i = 0; i < suites.length; i++) {
result += suites[i].benchmarks.length;
}
return result;
}
// Computes the geometric mean of a set of numbers.
BenchmarkSuite.GeometricMean = function(numbers) {
var log = 0;
for (var i = 0; i < numbers.length; i++) {
log += Math.log(numbers[i]);
}
return Math.pow(Math.E, log / numbers.length);
}
// Converts a score value to a string with at least three significant
// digits.
BenchmarkSuite.FormatScore = function(value) {
if (value > 100) {
return value.toFixed(0);
} else {
return value.toPrecision(3);
}
}
// Notifies the runner that we're done running a single benchmark in
// the benchmark suite. This can be useful to report progress.
BenchmarkSuite.prototype.NotifyStep = function(result) {
this.results.push(result);
if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name);
}
// Notifies the runner that we're done with running a suite and that
// we have a result which can be reported to the user if needed.
BenchmarkSuite.prototype.NotifyResult = function() {
var mean = BenchmarkSuite.GeometricMean(this.results);
var score = this.reference / mean;
BenchmarkSuite.scores.push(score);
if (this.runner.NotifyResult) {
var formatted = BenchmarkSuite.FormatScore(100 * score);
this.runner.NotifyResult(this.name, formatted);
}
}
// Notifies the runner that running a benchmark resulted in an error.
BenchmarkSuite.prototype.NotifyError = function(error) {
if (this.runner.NotifyError) {
this.runner.NotifyError(this.name, error);
}
if (this.runner.NotifyStep) {
this.runner.NotifyStep(this.name);
}
}
// Runs a single benchmark for at least a second and computes the
// average time it takes to run a single iteration.
BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark) {
var elapsed = 0;
var start = new Date();
for (var n = 0; elapsed < 50; n++) {
benchmark.run();
elapsed = new Date() - start;
}
var usec = (elapsed * 1000) / n;
this.NotifyStep(new BenchmarkResult(benchmark, usec));
}
// This function starts running a suite, but stops between each
// individual benchmark in the suite and returns a continuation
// function which can be invoked to run the next benchmark. Once the
// last benchmark has been executed, null is returned.
BenchmarkSuite.prototype.RunStep = function(runner) {
this.results = [];
this.runner = runner;
var length = this.benchmarks.length;
var index = 0;
var suite = this;
// Run the setup, the actual benchmark, and the tear down in three
// separate steps to allow the framework to yield between any of the
// steps.
function RunNextSetup() {
if (index < length) {
try {
suite.benchmarks[index].Setup();
} catch (e) {
suite.NotifyError(e);
return null;
}
return RunNextBenchmark;
}
suite.NotifyResult();
return null;
}
function RunNextBenchmark() {
try {
suite.RunSingleBenchmark(suite.benchmarks[index]);
} catch (e) {
suite.NotifyError(e);
return null;
}
return RunNextTearDown;
}
function RunNextTearDown() {
try {
suite.benchmarks[index++].TearDown();
} catch (e) {
suite.NotifyError(e);
return null;
}
return RunNextSetup;
}
// Start out running the setup.
return RunNextSetup();
}
// Copyright 2008 Google Inc. All Rights Reserved.
// Copyright 1996 John Maloney and Mario Wolczko.
@ -75,6 +341,7 @@ OrderedCollection.prototype.removeFirst = function () {
OrderedCollection.prototype.remove = function (elm) {
var index = 0, skipped = 0;
/* BEGIN LOOP */
for (var i = 0; i < this.elms.length; i++) {
var value = this.elms[i];
if (value != elm) {
@ -84,8 +351,11 @@ OrderedCollection.prototype.remove = function (elm) {
skipped++;
}
}
/* END LOOP */
/* BEGIN LOOP */
for (var i = 0; i < skipped; i++)
this.elms.pop();
/* END LOOP */
}
/* --- *
@ -588,8 +858,10 @@ function Planner() {
Planner.prototype.incrementalAdd = function (c) {
var mark = this.newMark();
var overridden = c.satisfy(mark);
/* BEGIN LOOP */
while (overridden != null)
overridden = overridden.satisfy(mark);
/* END LOOP */
}
/**
@ -609,14 +881,18 @@ Planner.prototype.incrementalRemove = function (c) {
c.removeFromGraph();
var unsatisfied = this.removePropagateFrom(out);
var strength = Strength.REQUIRED;
/* BEGIN LOOP */
do {
/* BEGIN LOOP */
for (var i = 0; i < unsatisfied.size(); i++) {
var u = unsatisfied.at(i);
if (u.strength == strength)
this.incrementalAdd(u);
}
/* END LOOP */
strength = strength.nextWeaker();
} while (strength != Strength.WEAKEST);
/* END LOOP */
}
/**
@ -649,6 +925,7 @@ Planner.prototype.makePlan = function (sources) {
var mark = this.newMark();
var plan = new Plan();
var todo = sources;
/* BEGIN LOOP */
while (todo.size() > 0) {
var c = todo.removeFirst();
if (c.output().mark != mark && c.inputsKnown(mark)) {
@ -657,6 +934,7 @@ Planner.prototype.makePlan = function (sources) {
this.addConstraintsConsumingTo(c.output(), todo);
}
}
/* END LOOP */
return plan;
}
@ -666,12 +944,14 @@ Planner.prototype.makePlan = function (sources) {
*/
Planner.prototype.extractPlanFromConstraints = function (constraints) {
var sources = new OrderedCollection();
/* BEGIN LOOP */
for (var i = 0; i < constraints.size(); i++) {
var c = constraints.at(i);
if (c.isInput() && c.isSatisfied())
// not in plan already and eligible for inclusion
sources.add(c);
}
/* END LOOP */
return this.makePlan(sources);
}
@ -691,6 +971,7 @@ Planner.prototype.extractPlanFromConstraints = function (constraints) {
Planner.prototype.addPropagate = function (c, mark) {
var todo = new OrderedCollection();
todo.add(c);
/* BEGIN LOOP */
while (todo.size() > 0) {
var d = todo.removeFirst();
if (d.output().mark == mark) {
@ -700,6 +981,7 @@ Planner.prototype.addPropagate = function (c, mark) {
d.recalculate();
this.addConstraintsConsumingTo(d.output(), todo);
}
/* END LOOP */
return true;
}
@ -716,14 +998,18 @@ Planner.prototype.removePropagateFrom = function (out) {
var unsatisfied = new OrderedCollection();
var todo = new OrderedCollection();
todo.add(out);
/* BEGIN LOOP */
while (todo.size() > 0) {
var v = todo.removeFirst();
/* BEGIN LOOP */
for (var i = 0; i < v.constraints.size(); i++) {
var c = v.constraints.at(i);
if (!c.isSatisfied())
unsatisfied.add(c);
}
/* END LOOP */
var determining = v.determinedBy;
/* BEGIN LOOP */
for (var i = 0; i < v.constraints.size(); i++) {
var next = v.constraints.at(i);
if (next != determining && next.isSatisfied()) {
@ -731,18 +1017,22 @@ Planner.prototype.removePropagateFrom = function (out) {
todo.add(next.output());
}
}
/* END LOOP */
}
/* END LOOP */
return unsatisfied;
}
Planner.prototype.addConstraintsConsumingTo = function (v, coll) {
var determining = v.determinedBy;
var cc = v.constraints;
/* BEGIN LOOP */
for (var i = 0; i < cc.size(); i++) {
var c = cc.at(i);
if (c != determining && c.isSatisfied())
coll.add(c);
}
/* END LOOP */
}
/* --- *
@ -771,10 +1061,12 @@ Plan.prototype.constraintAt = function (index) {
}
Plan.prototype.execute = function () {
/* BEGIN LOOP */
for (var i = 0; i < this.size(); i++) {
var c = this.constraintAt(i);
c.execute();
}
/* END LOOP */
}
/* --- *
@ -799,6 +1091,7 @@ function chainTest(n) {
var prev = null, first = null, last = null;
// Build chain of n equality constraints
/* BEGIN LOOP */
for (var i = 0; i <= n; i++) {
var name = "v" + i;
var v = new Variable(name);
@ -808,18 +1101,21 @@ function chainTest(n) {
if (i == n) last = v;
prev = v;
}
/* END LOOP */
new StayConstraint(last, Strength.STRONG_DEFAULT);
var edit = new EditConstraint(first, Strength.PREFERRED);
var edits = new OrderedCollection();
edits.add(edit);
var plan = planner.extractPlanFromConstraints(edits);
/* BEGIN LOOP */
for (var i = 0; i < 100; i++) {
first.value = i;
plan.execute();
if (last.value != i)
alert("Chain test failed.");
}
/* END LOOP */
}
/**
@ -835,6 +1131,7 @@ function projectionTest(n) {
var src = null, dst = null;
var dests = new OrderedCollection();
/* BEGIN LOOP */
for (var i = 0; i < n; i++) {
src = new Variable("src" + i, i);
dst = new Variable("dst" + i, i);
@ -842,21 +1139,26 @@ function projectionTest(n) {
new StayConstraint(src, Strength.NORMAL);
new ScaleConstraint(src, scale, offset, dst, Strength.REQUIRED);
}
/* END LOOP */
change(src, 17);
if (dst.value != 1170) alert("Projection 1 failed");
change(dst, 1050);
if (src.value != 5) alert("Projection 2 failed");
change(scale, 5);
/* BEGIN LOOP */
for (var i = 0; i < n - 1; i++) {
if (dests.at(i).value != i * 5 + 1000)
alert("Projection 3 failed");
}
/* END LOOP */
change(offset, 2000);
/* BEGIN LOOP */
for (var i = 0; i < n - 1; i++) {
if (dests.at(i).value != i * 5 + 2000)
alert("Projection 4 failed");
}
/* END LOOP */
}
function change(v, newValue) {
@ -864,10 +1166,12 @@ function change(v, newValue) {
var edits = new OrderedCollection();
edits.add(edit);
var plan = planner.extractPlanFromConstraints(edits);
/* BEGIN LOOP */
for (var i = 0; i < 10; i++) {
v.value = newValue;
plan.execute();
}
/* END LOOP */
edit.destroyConstraint();
}
@ -878,3 +1182,15 @@ function deltaBlue() {
chainTest(100);
projectionTest(100);
}
function PrintResult(name, result) {
}
function PrintScore(score) {
}
BenchmarkSuite.RunSuites({ NotifyResult: PrintResult,
NotifyScore: PrintScore });