diff --git a/benchmark/index.html b/benchmark/index.html
index 2733d31..3bc29a5 100644
--- a/benchmark/index.html
+++ b/benchmark/index.html
@@ -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() {