"use strict"; /* global setTimeout */ let peg = require("../../lib/peg"); let Runner = { run(benchmarks, runCount, options, callbacks) { // Queue let Q = { functions: [], add(f) { this.functions.push(f); }, run() { 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(() => { Q.run(); }, 0); } } }; // 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. let state = {}; function initialize() { callbacks.start(); state.totalInputSize = 0; state.totalParseTime = 0; } function benchmarkInitializer(benchmark) { return function() { callbacks.benchmarkStart(benchmark); state.parser = peg.generate( callbacks.readFile("../../examples/" + benchmark.id + ".pegjs"), options ); state.benchmarkInputSize = 0; state.benchmarkParseTime = 0; }; } function testRunner(benchmark, test) { return function() { callbacks.testStart(benchmark, test); let input = callbacks.readFile(benchmark.id + "/" + test.file); let parseTime = 0; for (let i = 0; i < runCount; i++) { let t = (new Date()).getTime(); state.parser.parse(input); parseTime += (new Date()).getTime() - t; } let averageParseTime = parseTime / runCount; callbacks.testFinish(benchmark, test, input.length, averageParseTime); state.benchmarkInputSize += input.length; state.benchmarkParseTime += averageParseTime; }; } function benchmarkFinalizer(benchmark) { return function() { callbacks.benchmarkFinish( benchmark, state.benchmarkInputSize, state.benchmarkParseTime ); state.totalInputSize += state.benchmarkInputSize; state.totalParseTime += state.benchmarkParseTime; }; } function finalize() { callbacks.finish(state.totalInputSize, state.totalParseTime); } // Main Q.add(initialize); benchmarks.forEach(benchmark => { Q.add(benchmarkInitializer(benchmark)); benchmark.tests.forEach(test => { Q.add(testRunner(benchmark, test)); }); Q.add(benchmarkFinalizer(benchmark)); }); Q.add(finalize); Q.run(); } }; module.exports = Runner;