2014-12-14 17:00:02 +00:00

184 lines
4.4 KiB
JavaScript

/*
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
* Code distributed by Google as part of the polymer project is also
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/
(function(global) {
'use strict';
function now() {
return global.performance && typeof performance.now == 'function' ?
performance.now() : Date.now();
}
function checkpoint() {
if (global.Platform &&
typeof Platform.performMicrotaskCheckpoint == 'function') {
Platform.performMicrotaskCheckpoint();
}
}
// TODO(rafaelw): Add simple Promise polyfill for IE.
var TESTING_TICKS = 400;
var TICKS_PER_FRAME = 16;
var MAX_RUNS = 50;
function Benchmark(testingTicks, ticksPerFrame, maxRuns) {
this.testingTicks = testingTicks || TESTING_TICKS;
this.ticksPerFrame = ticksPerFrame || TICKS_PER_FRAME;
this.maxRuns = maxRuns || 50;
this.average = 0;
}
Benchmark.prototype = {
// Abstract API
setup: function(variation) {},
test: function() {
throw Error('Not test function found');
},
cleanup: function() {},
runOne: function(variation) {
this.setup(variation);
var before = now();
this.test(variation);
var self = this;
return Promise.resolve().then(function() {
checkpoint();
var after = now();
self.cleanup(variation);
return after - before;
});
},
runMany: function(count, variation) {
var self = this;
return new Promise(function(fulfill) {
var total = 0;
function next(time) {
if (!count) {
fulfill(total);
return;
}
self.runOne(variation).then(function(time) {
count--;
total += time;
next();
});
}
requestAnimationFrame(next);
});
},
runVariation: function(variation, reportFn) {
var self = this;
reportFn = reportFn || function() {}
return new Promise(function(fulfill) {
self.runMany(3, variation).then(function(time) {
return time/3;
}).then(function(estimate) {
var runsPerFrame = Math.ceil(self.ticksPerFrame / estimate);
var frames = Math.ceil(self.testingTicks / self.ticksPerFrame);
var maxFrames = Math.ceil(self.maxRuns / runsPerFrame);
frames = Math.min(frames, maxFrames);
var count = 0;
var total = 0;
function next() {
if (!frames) {
self.average = total / count;
self.dispose();
fulfill(self.average);
return;
}
self.runMany(runsPerFrame, variation).then(function(time) {
frames--;
total += time;
count += runsPerFrame;
reportFn(variation, count);
next();
});
}
next();
});
});
},
run: function(variations, reportFn) {
if (!Array.isArray(variations)) {
return this.runVariation(variations, reportFn);
}
var self = this;
variations = variations.slice();
return new Promise(function(fulfill) {
var results = [];
function next() {
if (!variations.length) {
fulfill(results);
return;
}
var variation = variations.shift();
self.runVariation(variation, reportFn).then(function(time) {
results.push(time);
next();
});
}
next();
});
}
};
function all(benchmarks, variations, statusFn) {
return new Promise(function(fulfill) {
var results = [];
var current;
function next() {
current = benchmarks.shift();
if (!current) {
fulfill(results);
return;
}
function update(variation, runs) {
statusFn(current, variation, runs);
}
current.run(variations, update).then(function(time) {
results.push(time);
next();
});
}
next();
});
}
global.Benchmark = Benchmark;
global.Benchmark.all = all;
})(this);