Benchmark: Factor benchmark into several functions run using |setTimeout|

We do this for two reasons:

  1. To avoid bowser mechanism for interrupting long-running scripts to
     kick-in (or at least to not kick-in that often).

  2. To ensure progressive rendering of results in the browser (some
     browsers do not render at all when running JavaScript code).

This does not change the benchmark suite execution speed statistically
significantly on V8.

Detailed results (benchmark suite totals):

---------------------------------
 Test #     Before       After
---------------------------------
      1   31.04 kB/s   31.18 kB/s
      2   31.26 kB/s   30.89 kB/s
      3   31.15 kB/s   31.19 kB/s
      4   30.52 kB/s   31.21 kB/s
      5   31.00 kB/s   30.73 kB/s
---------------------------------
Average   30.99 kB/s   31.04 kB/s
---------------------------------

Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.99 Safari/533.4
redux
David Majda 14 years ago
parent 647e7be1fd
commit c3b5c2131a

@ -105,6 +105,9 @@
];
$("#run").click(function() {
/* Results Table Manipulation */
var resultsTable = $("#results-table");
function appendHeading(heading) {
@ -146,6 +149,8 @@
);
}
/* AJAX */
function get(url) {
return $.ajax({
type: "GET",
@ -155,6 +160,30 @@
}).responseText;
}
/* Queue */
var Q = {
functions: [],
add: function(f) {
this.functions.push(f);
},
run: function() {
if (this.functions.length > 0) {
this.functions.shift()();
/*
* We can't use |arguments.callee| here because |this| would get
* messed-up in that case.
*/
setTimeout(function() { Q.run() }, 0);
}
}
};
/* Main */
/*
* Each input is parsed multiple times and the results are averaged. We
* do this for two reasons:
@ -165,32 +194,57 @@
*
* 2. To minimize random errors.
*/
var runCount = parseInt($("#run-count").val());
if (isNaN(runCount) || runCount <= 0) {
alert("Number of runs must be a positive integer.");
return;
}
$("#run-count, #run").attr("disabled", "disabled");
/*
* The benchmark itself is factored out into several functions (some of
* them generated), which are enqueued and run one by one using
* |setTimeout|. We do this for two reasons:
*
* 1. To avoid bowser mechanism for interrupting long-running scripts
* to kick-in (or at least to not kick-in that often).
*
* 2. To ensure progressive rendering of results in the browser (some
* browsers do not render at all when running JavaScript code).
*
* The enqueued functions share state, which is all stored in the
* properties of the |state| object.
*/
resultsTable.show();
$("#results-table tr").slice(1).remove();
var state = {};
var totalInputSize = 0;
var totalParseTime = 0;
function initialize() {
$("#run-count, #run").attr("disabled", "disabled");
for (var i = 0; i < benchmarks.length; i++) {
var benchmark = benchmarks[i];
resultsTable.show();
$("#results-table tr").slice(1).remove();
appendHeading(benchmark.title);
state.totalInputSize = 0;
state.totalParseTime = 0;
}
function benchmarkInitializer(i) {
return function() {
var benchmark = benchmarks[i];
var grammar = get("../examples/" + benchmark.id + ".pegjs");
var parser = PEG.buildParser(grammar);
appendHeading(benchmark.title);
var benchmarkInputSize = 0;
var benchmarkParseTime = 0;
var grammar = get("../examples/" + benchmark.id + ".pegjs");
state.parser = PEG.buildParser(grammar);
for (var j = 0; j < benchmark.tests.length; j++) {
state.benchmarkInputSize = 0;
state.benchmarkParseTime = 0;
};
}
function testRunner(i, j) {
return function() {
var benchmark = benchmarks[i];
var test = benchmark.tests[j];
var url = benchmark.id + "/" + test.file;
@ -199,7 +253,7 @@
var parseTime = 0;
for (var k = 0; k < runCount; k++) {
var t = (new Date).getTime();
parser.parse(input);
state.parser.parse(input);
parseTime += (new Date).getTime() - t;
}
var averageParseTime = parseTime / runCount;
@ -212,27 +266,53 @@
averageParseTime
);
benchmarkInputSize += input.length;
benchmarkParseTime += averageParseTime;
}
state.benchmarkInputSize += input.length;
state.benchmarkParseTime += averageParseTime;
};
}
function benchmarkFinalizer(i) {
return function() {
var benchmark = benchmarks[i];
appendResult(
"benchmark-total",
benchmark.title + " total",
null,
state.benchmarkInputSize,
state.benchmarkParseTime
);
state.totalInputSize += state.benchmarkInputSize;
state.totalParseTime += state.benchmarkParseTime;
};
}
function finalize() {
appendResult(
"benchmark-total",
benchmark.title + " total",
"total",
"Total",
null,
benchmarkInputSize,
benchmarkParseTime
state.totalInputSize,
state.totalParseTime
);
totalInputSize += benchmarkInputSize;
totalParseTime += benchmarkParseTime;
}
$.scrollTo("max", { axis: "y", duration: 500 });
appendResult("total", "Total", null, totalInputSize, totalParseTime);
$("#run-count, #run").removeAttr("disabled");
}
$.scrollTo("max", { axis: "y", duration: 500 });
Q.add(initialize);
for (var i = 0; i < benchmarks.length; i++) {
Q.add(benchmarkInitializer(i));
for (var j = 0; j < benchmarks[i].tests.length; j++) {
Q.add(testRunner(i, j));
}
Q.add(benchmarkFinalizer(i));
}
Q.add(finalize);
$("#run-count, #run").removeAttr("disabled");
Q.run();
});
$(document).ready(function() {

Loading…
Cancel
Save