window.evt = event;
event.preventDefault();
- start(20, function() {
+ PerfTestRunner.run(function () {
var e = window.evt;
for (var x = 0; x < kIteratonsPerTest; x++) {
e.target;
}
- }, 10);
+ });
return false;
}, false);
+2012-01-31 Ryosuke Niwa <rniwa@webkit.org>
+
+ runner.js in performance tests should define a class
+ https://bugs.webkit.org/show_bug.cgi?id=77074
+
+ Reviewed by Eric Seidel.
+
+ Wrap all functions in runner.js by PerfTestRunner and update tests that runner.js accordingly.
+ Also replace compute* functions in runner.js by more robust code from dom-perf.js.
+
+ * Bindings/event-target-wrapper.html:
+ * DOM/DOMTable.html:
+ * DOM/resources/dom-perf.js:
+ (BenchmarkSuite.prototype.RunSingle):
+ (runBenchmarkSuite):
+ * Mutation/append-child-deep.html:
+ * Mutation/append-child.html:
+ * Mutation/inner-html.html:
+ * Mutation/remove-child-deep.html:
+ * Mutation/remove-child.html:
+ * Parser/html-parser.html:
+ * Parser/html5-full-render.html:
+ * Parser/simple-url.html:
+ * Parser/tiny-innerHTML.html:
+ * Parser/url-parser.html:
+ * Parser/xml-parser.html:
+ * resources/runner.js:
+ (PerfTestRunner.log):
+ (PerfTestRunner.logInfo):
+ (PerfTestRunner.loadFile):
+ (PerfTestRunner.computeStatistics):
+ (PerfTestRunner.logStatistics):
+ (PerfTestRunner._runLoop.else):
+ (PerfTestRunner._runLoop):
+ (PerfTestRunner._runner):
+
2012-01-31 Hajime Morrita <morrita@chromium.org>
[PerformanceTests] Add landing html for Dromaeo dom-query test
<script type="text/javascript" src="../resources/runner.js"></script>
<script type="text/javascript" src="resources/dom-perf.js"></script>
<script type="text/javascript" src="resources/dom-perf/domtable.js"></script>
-<script> runBenchmarkSuite(DOMTableTest); </script>
+<script>
+runBenchmarkSuite(DOMTableTest, 10);
+// runCount = 10 since this test is very slow (~12m per run on Core i5 2.53Hz MacBookPro)
+</script>
</body>
</html>
}
}
if (!error) {
- var data = times.slice();
- var count = data.length;
-
- // Sort the data so that all seemingly
- // insignificant values such as 0.000000003 will
- // be at the beginning of the array and their
- // contribution to the mean and variance of the
- // data will not be lost because of the precision
- // of the CPU.
- data.sort(BenchmarkSuite.Math.ascend);
-
- // Since the data is now sorted, the minimum value
- // is at the beginning of the array, the median
- // value is in the middle of the array, and the
- // maximum value is at the end of the array.
- this.min = data[0];
- var middle = Math.floor(data.length / 2);
- if ((data.length % 2) !== 0)
- this.median = data[middle];
- else
- this.median = (data[middle - 1] + data[middle]) / 2;
- this.max = data[data.length - 1];
-
- // Compute the mean and variance using a
- // numerically stable algorithm.
- var sqsum = 0;
- this.mean = data[0];
- var nZeros = 0;
- for (var i = 1; i < data.length; ++i) {
- var x = data[i];
- var delta = x - this.mean;
- var sweep = i + 1.0;
- this.mean += delta / sweep;
- sqsum += delta * delta * (i / sweep);
- }
- this.sum = this.mean * count;
- this.variance = sqsum / count;
-
- this.sdev = Math.sqrt(this.variance);
- this.score = 1000 / this.mean;
+ var statistics = PerfTestRunner.computeStatistics(times);
+ this.min = statistics.min;
+ this.max = statistics.max;
+ this.median = statistics.median;
+ this.mean = statistics.mean;
+ this.sum = statistics.sum;
+ this.variance = statistics.variance;
+ this.stdev = statistics.stdev;
}
- this.toString = function() {
- var s =
- " min: " + this.min +
- " max: " + this.max +
- " mean: " + this.mean +
- " median: " + this.median +
- " sdev: " + this.sdev;
- return s;
- };
-
// Convert results to numbers. Used by the geometric mean computation.
this.valueOf = function() { return this.time; };
}
this.benchmarkContentHolder.removeChild(this.benchmarkContent);
this.benchmarkContent = this.benchmarkContentProto.cloneNode();
this.benchmarkContentHolder.appendChild(this.benchmarkContent);
- gc();
+ PerfTestRunner.gc();
try {
if (benchmark.setup) {
return this.generateDOMTree(26, 26, 4);
};
-function runBenchmarkSuite(suite) {
- startCustom(20, function () {
+function runBenchmarkSuite(suite, runCount) {
+ PerfTestRunner.run(function () {
var container = document.getElementById('container');
var content = document.getElementById('benchmark_content');
suite.benchmarkContentHolder = container;
totalMeanTime += result.mean;
}
return totalMeanTime;
- }, function () {
+ }, 1, runCount || 20, function () {
var container = document.getElementById('container');
if (container.firstChild)
container.removeChild(container.firstChild);
baseURL: "./resources/dromaeo/web/index.html",
computeScores: function (results) {
- var avg = 0, min = 0, max = 0, stdev = 0, varsum = 0;
+ var mean = 0, min = 0, max = 0, stdev = 0, varsum = 0;
for (var i = 0; i < results.length; ++i) {
var item = results[i];
- avg += item.mean;
+ mean += item.mean;
min += item.min;
max += item.max;
varsum += item.deviation * item.deviation;
return {
median: 0,
- avg: avg,
+ mean: mean,
min: min,
max: max,
stdev: Math.sqrt(varsum)
teardown: function(data) {
var scores = DRT.computeScores(data.result);
- printStatistics(scores, DRT.log);
+ PerfTestRunner.printStatistics(scores, DRT.log);
window.setTimeout(function() {
if (window.layoutTestController)
layoutTestController.notifyDone();
if (start) {
var time = Date.now() - start;
times.push(time);
- log(time);
+ PerfTestRunner.log(time);
}
if (numRuns-- >= 0) {
runAgain();
for (var i = 0; i < elems.length; ++i)
node.appendChild(elems[i]);
} else {
- logStatistics(times);
+ PerfTestRunner.logStatistics(times);
if (!observing) {
observing = true;
resetState();
- log('\n------------\n');
- log('Running ' + numRuns + ' times with observation');
+ PerfTestRunner.log('\n------------\n');
+ PerfTestRunner.log('Running ' + numRuns + ' times with observation');
setTimeout(runAgain, 0);
}
}
}
resetState();
-log('Running ' + numRuns + ' times without observation');
+PerfTestRunner.log('Running ' + numRuns + ' times without observation');
window.addEventListener('load', runAgain);
</script>
</body>
if (start) {
var time = Date.now() - start;
times.push(time);
- log(time);
+ PerfTestRunner.log(time);
}
if (numRuns-- >= 0) {
runAgain();
for (var i = 0; i < elems.length; ++i)
sandbox.appendChild(elems[i]);
} else {
- logStatistics(times);
+ PerfTestRunner.logStatistics(times);
if (!observing) {
observing = true;
resetState();
- log('\n------------\n');
- log('Running ' + numRuns + ' times with observation');
+ PerfTestRunner.log('\n------------\n');
+ PerfTestRunner.log('Running ' + numRuns + ' times with observation');
setTimeout(runAgain, 0);
}
}
}
resetState();
-log('Running ' + numRuns + ' times without observation');
+PerfTestRunner.log('Running ' + numRuns + ' times without observation');
window.addEventListener('load', runAgain);
</script>
</body>
if (start) {
var time = Date.now() - start;
times.push(time);
- log(time);
+ PerfTestRunner.log(time);
}
if (numRuns-- >= 0) {
runAgain();
for (var i = 0; i < 100; ++i)
sandbox.innerHTML = html;
} else {
- logStatistics(times);
+ PerfTestRunner.logStatistics(times);
if (!observing) {
observer.observe(sandbox, {childList: true});
observing = true;
resetState();
- log('\n------------\n');
- log('Running ' + numRuns + ' times with observation');
+ PerfTestRunner.log('\n------------\n');
+ PerfTestRunner.log('Running ' + numRuns + ' times with observation');
setTimeout(runAgain, 0);
}
}
}
resetState();
-log('Running ' + numRuns + ' times without observation');
+PerfTestRunner.log('Running ' + numRuns + ' times without observation');
window.addEventListener('load', runAgain);
</script>
</body>
if (start) {
var time = Date.now() - start;
times.push(time);
- log(time);
+ PerfTestRunner.log(time);
}
if (numRuns-- >= 0) {
runAgain();
while (node.firstChild)
node.removeChild(node.firstChild);
} else {
- logStatistics(times);
+ PerfTestRunner.logStatistics(times);
if (!observing) {
observing = true;
resetState();
- log('\n------------\n');
- log('Running ' + numRuns + ' times with observation');
+ PerfTestRunner.log('\n------------\n');
+ PerfTestRunner.log('Running ' + numRuns + ' times with observation');
setTimeout(runAgain, 0);
}
}
}
resetState();
-log('Running ' + numRuns + ' times without observation');
+PerfTestRunner.log('Running ' + numRuns + ' times without observation');
window.addEventListener('load', runAgain);
</script>
</body>
if (start) {
var time = Date.now() - start;
times.push(time);
- log(time);
+ PerfTestRunner.log(time);
}
if (numRuns-- >= 0) {
runAgain();
while (sandbox.firstChild)
sandbox.removeChild(sandbox.firstChild);
} else {
- logStatistics(times);
+ PerfTestRunner.logStatistics(times);
if (!observing) {
observer.observe(sandbox, {childList: true});
observing = true;
resetState();
- log('\n------------\n');
- log('Running ' + numRuns + ' times with observation');
+ PerfTestRunner.log('\n------------\n');
+ PerfTestRunner.log('Running ' + numRuns + ' times with observation');
setTimeout(runAgain, 0);
}
}
}
resetState();
-log('Running ' + numRuns + ' times without observation');
+PerfTestRunner.log('Running ' + numRuns + ' times without observation');
window.addEventListener('load', runAgain);
</script>
</body>
<pre id="log"></pre>
<script src="../resources/runner.js"></script>
<script>
-var spec = loadFile("resources/html5.html");
+var spec = PerfTestRunner.loadFile("resources/html5.html");
-start(10, function() {
+PerfTestRunner.run(function() {
var iframe = document.createElement("iframe");
iframe.style.display = "none"; // Prevent creation of the rendering tree, so we only test HTML parsing.
iframe.sandbox = ''; // Prevent external script loads which could cause write() to return before completing the parse.
// Running from the onload callback just makes the UI nicer as it shows the logs before starting the test.
window.onload = function() {
// Depending on the chosen chunk size, iterations can take over 60s to run on a fast machine, so we only run 2.
- start(2, function() {
+ PerfTestRunner.run(function() {
var iframe = document.createElement("iframe");
document.body.appendChild(iframe);
loadChunkedSpecIntoIframe(iframe);
document.body.removeChild(iframe);
- }, 1); // We only loop once for each run, again because this test is so slow.
+ }, 1, 2); // We only loop once for each run, again because this test is so slow.
}
</script>
<script src="../resources/runner.js"></script>
<script>
var anchor = document.createElement("a");
-start(20, function() {
+PerfTestRunner.run(function() {
for (var x = 0; x < 200000; x++) {
anchor.href = "http://www.apple.com/"
}
<pre id="log"></pre>
<script src="../resources/runner.js"></script>
<script>
-start(20, function() {
+PerfTestRunner.run(function() {
var testDiv = document.createElement("div");
testDiv.style.display = "none";
document.body.appendChild(testDiv);
<pre id="log"></pre>
<script src="../resources/runner.js"></script>
<script>
-var urls = loadFile("resources/final-url-en").split("\n");
+var urls = PerfTestRunner.loadFile("resources/final-url-en").split("\n");
var anchor = document.createElement("a");
-start(20, function() {
+PerfTestRunner.run(function() {
for (var x = 0; x < urls.length; x++) {
anchor.href = urls[x];
}
xmlArray.push('</root>')
var xmlData = xmlArray.join('');
-start(20, function() {
+PerfTestRunner.run(function() {
domParser.parseFromString(xmlData, "text/xml");
});
</script>
-function log(text) {
+
+var PerfTestRunner = {};
+
+PerfTestRunner.log = function (text) {
document.getElementById("log").innerHTML += text + "\n";
window.scrollTo(0, document.body.height);
}
-function logInfo(text) {
+PerfTestRunner.logInfo = function (text) {
if (!window.layoutTestController)
- log(text);
+ this.log(text);
}
-function loadFile(path) {
+PerfTestRunner.loadFile = function (path) {
var xhr = new XMLHttpRequest();
xhr.open("GET", path, false);
xhr.send(null);
return xhr.responseText;
}
-var runCount = -1;
-var runFunction = function() {};
-var completedRuns = -1; // Discard the any runs < 0.
-var times = [];
-
-function computeAverage(values) {
- var sum = 0;
- for (var i = 0; i < values.length; i++)
- sum += values[i];
- return sum / values.length;
-}
-
-function computeMax(values) {
- var max = values.length ? values[0] : 0;
- for (var i = 1; i < values.length; i++) {
- if (max < values[i])
- max = values[i];
+PerfTestRunner.computeStatistics = function (times) {
+ var data = times.slice();
+
+ // Add values from the smallest to the largest to avoid the loss of significance
+ data.sort();
+
+ var middle = Math.floor(data.length / 2);
+ var result = {
+ min: data[0],
+ max: data[data.length - 1],
+ median: data.length % 2 ? data[middle] : (data[middle - 1] + data[middle]) / 2,
+ };
+
+ // Compute the mean and variance using a numerically stable algorithm.
+ var squareSum = 0;
+ result.mean = data[0];
+ result.sum = data[0];
+ for (var i = 1; i < data.length; ++i) {
+ var x = data[i];
+ var delta = x - result.mean;
+ var sweep = i + 1.0;
+ result.mean += delta / sweep;
+ result.sum += x;
+ squareSum += delta * delta * (i / sweep);
}
- return max;
-}
+ result.variance = squareSum / data.length;
+ result.stdev = Math.sqrt(result.variance);
-function computeMedian(values) {
- values.sort(function(a, b) { return a - b; });
- var len = values.length;
- if (len % 2)
- return values[(len-1)/2];
- return (values[len/2-1] + values[len/2]) / 2;
+ return result;
}
-function computeMin(values) {
- var min = values.length ? values[0] : 0;
- for (var i = 1; i < values.length; i++) {
- if (min > values[i])
- min = values[i];
- }
- return min;
-}
-
-function computeStdev(values) {
- var average = computeAverage(values);
- var sumOfSquaredDeviations = 0;
- for (var i = 0; i < values.length; ++i) {
- var deviation = values[i] - average;
- sumOfSquaredDeviations += deviation * deviation;
- }
- return Math.sqrt(sumOfSquaredDeviations / values.length);
+PerfTestRunner.logStatistics = function (times) {
+ this.log("");
+ var statistics = this.computeStatistics(times);
+ this.printStatistics(statistics, this.log);
}
-function printStatistics(stats, printFunction)
-{
+PerfTestRunner.printStatistics = function (statistics, printFunction) {
printFunction("");
- printFunction("avg " + stats.avg);
- printFunction("median " + stats.median);
- printFunction("stdev " + stats.stdev);
- printFunction("min " + stats.min);
- printFunction("max " + stats.max);
+ printFunction("avg " + statistics.mean);
+ printFunction("median " + statistics.median);
+ printFunction("stdev " + statistics.stdev);
+ printFunction("min " + statistics.min);
+ printFunction("max " + statistics.max);
}
-function logStatistics(times) {
- printStatistics({
- avg: computeAverage(times),
- median: computeMedian(times),
- stdev: computeStdev(times),
- min: computeMin(times),
- max: computeMax(times)
- }, log);
-}
-
-function gc() {
+PerfTestRunner.gc = function () {
if (window.GCController)
- GCController.collect();
+ window.GCController.collect();
else {
function gcRec(n) {
if (n < 1)
}
}
-function runLoop()
-{
- if (window.completedRuns < window.runCount) {
- gc();
- window.setTimeout(run, 0);
+PerfTestRunner._runLoop = function () {
+ if (this._completedRuns < this._runCount) {
+ this.gc();
+ window.setTimeout(function () { PerfTestRunner._runner(); }, 0);
} else {
- logStatistics(times);
- window.doneFunction();
+ this.logStatistics(this._times);
+ this._doneFunction();
if (window.layoutTestController)
layoutTestController.notifyDone();
}
}
-function run() {
- if (window.customRunFunction)
- var time = window.customRunFunction();
- else {
- var start = new Date();
- for (var i = 0; i < window.loopsPerRun; ++i)
- window.runFunction();
- var time = new Date() - start;
- }
+PerfTestRunner._runner = function () {
+ var start = Date.now();
+ var totalTime = 0;
- window.completedRuns++;
- if (window.completedRuns <= 0) {
- log("Ignoring warm-up run (" + time + ")");
- } else {
- times.push(time);
- log(time);
+ for (var i = 0; i < this._loopsPerRun; ++i) {
+ var returnValue = this._runFunction.call(window);
+ if (returnValue - 0 === returnValue) {
+ if (returnValue <= 0)
+ this.log("runFunction returned a non-positive value: " + returnValue);
+ totalTime += returnValue;
+ }
}
- runLoop()
-}
-function start(runCount, runFunction, loopsPerRun, doneFunction) {
- window.runCount = runCount;
- window.runFunction = runFunction;
- window.loopsPerRun = loopsPerRun || 10;
- window.doneFunction = doneFunction || function() {};
+ // Assume totalTime can never be zero when _runFunction returns a number.
+ var time = totalTime ? totalTime : Date.now() - start;
- log("Running " + runCount + " times");
- runLoop();
+ this._completedRuns++;
+ if (this._completedRuns <= 0)
+ this.log("Ignoring warm-up run (" + time + ")");
+ else {
+ this._times.push(time);
+ this.log(time);
+ }
+ this._runLoop();
}
-function startCustom(runCount, customRunFunction, doneFunction) {
- window.runCount = runCount;
- window.customRunFunction = customRunFunction;
- window.loopsPerRun = 1;
- window.doneFunction = doneFunction || function() {};
+PerfTestRunner.run = function (runFunction, loopsPerRun, runCount, doneFunction) {
+ this._runFunction = runFunction;
+ this._loopsPerRun = loopsPerRun || 10;
+ this._runCount = runCount || 20;
+ this._doneFunction = doneFunction || function () {};
+ this._completedRuns = -1;
+ this.customRunFunction = null;
+ this._times = [];
- log("Running " + runCount + " times");
- runLoop();
+ this.log("Running " + this._runCount + " times");
+ this._runLoop();
}
if (window.layoutTestController) {