diff --git a/Makefile b/Makefile index 6f9840a..f03570b 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,8 @@ PARSER_OUT_FILE_NEW = $(LIB_DIR)/parser.js.new BROWSER_FILE_DEV = $(BROWSER_DIR)/peg-$(PEGJS_VERSION).js BROWSER_FILE_MIN = $(BROWSER_DIR)/peg-$(PEGJS_VERSION).min.js -SPEC_SERVER_FILE = $(SPEC_DIR)/server +SPEC_SERVER_FILE = $(SPEC_DIR)/server +BENCHMARK_SERVER_FILE = $(BENCHMARK_DIR)/server VERSION_FILE = VERSION @@ -108,6 +109,7 @@ lint: $(SPEC_SERVER_FILE) \ $(BENCHMARK_DIR)/*.js \ $(BENCHMARK_RUN) \ + $(BENCHMARK_SERVER_FILE) \ $(PEGJS) .PHONY: all parser browser browserclean spec benchmark lint diff --git a/benchmark/.eslintrc.json b/benchmark/.eslintrc.json new file mode 100644 index 0000000..e84df8c --- /dev/null +++ b/benchmark/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "env": { + "commonjs": true + } +} diff --git a/benchmark/README.md b/benchmark/README.md index 9b1bc1b..37bfded 100644 --- a/benchmark/README.md +++ b/benchmark/README.md @@ -39,18 +39,12 @@ All commands in the following steps need to be executed in PEG.js root directory $ npm install ``` - 3. Build browser version of PEG.js: + 3. Serve the benchmark suite using a web server: ```console - $ make browser + $ benchmark/server ``` - 4. Serve PEG.js root directory using a web server: + 4. Point your browser to the [benchmark suite](http://localhost:8000/). - ```console - $ node_modules/.bin/http-server - ``` - - 5. Point your browser to the [benchmark suite](http://localhost:8080/benchmark/index.html). - - 6. Click the **Run** button and wait for results. + 5. Click the **Run** button and wait for results. diff --git a/benchmark/benchmarks.js b/benchmark/benchmarks.js index 2eaff43..6987675 100644 --- a/benchmark/benchmarks.js +++ b/benchmark/benchmarks.js @@ -1,52 +1,42 @@ -/* global module */ - "use strict"; -(function(root, factory) { - if (typeof module !== 'undefined' && module.exports) { - module.exports = factory(); - } else { - root.benchmarks = factory(); +var benchmarks = [ + { + id: "json", + title: "JSON", + tests: [ + { file: "example1.json", title: "Example 1" }, + { file: "example2.json", title: "Example 2" }, + { file: "example3.json", title: "Example 3" }, + { file: "example4.json", title: "Example 4" }, + { file: "example5.json", title: "Example 5" } + ] + }, + { + id: "css", + title: "CSS", + tests: [ + { file: "blueprint/src/reset.css", title: "Blueprint - reset.css (source)" }, + { file: "blueprint/src/typography.css", title: "Blueprint - typography.css (source)" }, + { file: "blueprint/src/forms.css", title: "Blueprint - forms.css (source)" }, + { file: "blueprint/src/grid.css", title: "Blueprint - grid.css (source)" }, + { file: "blueprint/src/print.css", title: "Blueprint - print.css (source)" }, + // Contains syntax errors. + // { file: "blueprint/src/ie.css", title: "Blueprint - ie.css (source)" }, + { file: "blueprint/min/screen.css", title: "Blueprint - screen.css (minified)" }, + { file: "blueprint/min/print.css", title: "Blueprint - print.css (minified)" }, + // Contains syntax errors. + // { file: "blueprint/min/ie.css", title: "Blueprint - ie.css (minified)" }, + { file: "960.gs/src/reset.css", title: "960.gs - reset.css (source)" }, + { file: "960.gs/src/text.css", title: "960.gs - text.css (source)" }, + { file: "960.gs/src/960.css", title: "960.gs - 960.css (source)" }, + { file: "960.gs/src/960_24_col.css", title: "960.gs - 960_24_col.css (source)" }, + { file: "960.gs/min/reset.css", title: "960.gs - reset.css (minified)" }, + { file: "960.gs/min/text.css", title: "960.gs - text.css (minified)" }, + { file: "960.gs/min/960.css", title: "960.gs - 960.css (minified)" }, + { file: "960.gs/min/960_24_col.css", title: "960.gs - 960_24_col.css (minified)" } + ] } -}(this, function() { - - return [ - { - id: "json", - title: "JSON", - tests: [ - { file: "example1.json", title: "Example 1" }, - { file: "example2.json", title: "Example 2" }, - { file: "example3.json", title: "Example 3" }, - { file: "example4.json", title: "Example 4" }, - { file: "example5.json", title: "Example 5" } - ] - }, - { - id: "css", - title: "CSS", - tests: [ - { file: "blueprint/src/reset.css", title: "Blueprint - reset.css (source)" }, - { file: "blueprint/src/typography.css", title: "Blueprint - typography.css (source)" }, - { file: "blueprint/src/forms.css", title: "Blueprint - forms.css (source)" }, - { file: "blueprint/src/grid.css", title: "Blueprint - grid.css (source)" }, - { file: "blueprint/src/print.css", title: "Blueprint - print.css (source)" }, - // Contains syntax errors. - // { file: "blueprint/src/ie.css", title: "Blueprint - ie.css (source)" }, - { file: "blueprint/min/screen.css", title: "Blueprint - screen.css (minified)" }, - { file: "blueprint/min/print.css", title: "Blueprint - print.css (minified)" }, - // Contains syntax errors. - // { file: "blueprint/min/ie.css", title: "Blueprint - ie.css (minified)" }, - { file: "960.gs/src/reset.css", title: "960.gs - reset.css (source)" }, - { file: "960.gs/src/text.css", title: "960.gs - text.css (source)" }, - { file: "960.gs/src/960.css", title: "960.gs - 960.css (source)" }, - { file: "960.gs/src/960_24_col.css", title: "960.gs - 960_24_col.css (source)" }, - { file: "960.gs/min/reset.css", title: "960.gs - reset.css (minified)" }, - { file: "960.gs/min/text.css", title: "960.gs - text.css (minified)" }, - { file: "960.gs/min/960.css", title: "960.gs - 960.css (minified)" }, - { file: "960.gs/min/960_24_col.css", title: "960.gs - 960_24_col.css (minified)" } - ] - } - ]; +]; -})); +module.exports = benchmarks; diff --git a/benchmark/index.html b/benchmark/index.html index 60c40cb..ec6a390 100644 --- a/benchmark/index.html +++ b/benchmark/index.html @@ -33,11 +33,8 @@ - - - - + diff --git a/benchmark/index.js b/benchmark/index.js index 9d77d95..97e54e5 100644 --- a/benchmark/index.js +++ b/benchmark/index.js @@ -1,5 +1,7 @@ /* eslint-env browser, jquery */ -/* global benchmarks, Runner */ + +var benchmarks = require("./benchmarks.js"), + Runner = require("./runner.js"); $("#run").click(function() { "use strict"; diff --git a/benchmark/run b/benchmark/run index 38581d1..7896f74 100755 --- a/benchmark/run +++ b/benchmark/run @@ -6,10 +6,9 @@ "use strict"; var fs = require("fs"); -var peg = require("../lib/peg"); var benchmarks = require("./benchmarks.js"); -var Runner = require("./runner.js")(peg); +var Runner = require("./runner.js"); /* Results Table Manipulation */ diff --git a/benchmark/runner.js b/benchmark/runner.js index 6787997..5090619 100644 --- a/benchmark/runner.js +++ b/benchmark/runner.js @@ -1,131 +1,125 @@ -/* global module, setTimeout */ +/* global setTimeout */ "use strict"; -(function(root, factory) { - if (typeof module !== 'undefined' && module.exports) { - module.exports = factory; - } else { - root.Runner = factory(root.peg); - } -}(this, function(peg) { +var peg = require("../lib/peg"); - return { - run: function(benchmarks, runCount, options, callbacks) { +var Runner = { + run: function(benchmarks, runCount, options, callbacks) { - /* Queue */ + /* Queue */ - var Q = { - functions: [], + var Q = { + functions: [], - add: function(f) { - this.functions.push(f); - }, + add: function(f) { + this.functions.push(f); + }, - run: function() { - if (this.functions.length > 0) { - this.functions.shift()(); + 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); - } + /* + * We can't use |arguments.callee| here because |this| would get + * messed-up in that case. + */ + setTimeout(function() { 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. - */ - - var 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() { - var input, parseTime, averageParseTime, i, t; + /* + * 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. + */ + + var state = {}; + + function initialize() { + callbacks.start(); + + state.totalInputSize = 0; + state.totalParseTime = 0; + } - callbacks.testStart(benchmark, test); + 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; + }; + } - input = callbacks.readFile(benchmark.id + "/" + test.file); + function testRunner(benchmark, test) { + return function() { + var input, parseTime, averageParseTime, i, t; - parseTime = 0; - for (i = 0; i < runCount; i++) { - t = (new Date()).getTime(); - state.parser.parse(input); - parseTime += (new Date()).getTime() - t; - } - averageParseTime = parseTime / runCount; + callbacks.testStart(benchmark, test); - callbacks.testFinish(benchmark, test, input.length, averageParseTime); + input = callbacks.readFile(benchmark.id + "/" + test.file); - 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; - }; - } + parseTime = 0; + for (i = 0; i < runCount; i++) { + t = (new Date()).getTime(); + state.parser.parse(input); + parseTime += (new Date()).getTime() - t; + } + averageParseTime = parseTime / runCount; - function finalize() { - callbacks.finish(state.totalInputSize, state.totalParseTime); - } + callbacks.testFinish(benchmark, test, input.length, averageParseTime); - /* Main */ + state.benchmarkInputSize += input.length; + state.benchmarkParseTime += averageParseTime; + }; + } - Q.add(initialize); - benchmarks.forEach(function(benchmark) { - Q.add(benchmarkInitializer(benchmark)); - benchmark.tests.forEach(function(test) { - Q.add(testRunner(benchmark, test)); - }); - Q.add(benchmarkFinalizer(benchmark)); - }); - Q.add(finalize); + function benchmarkFinalizer(benchmark) { + return function() { + callbacks.benchmarkFinish( + benchmark, + state.benchmarkInputSize, + state.benchmarkParseTime + ); + + state.totalInputSize += state.benchmarkInputSize; + state.totalParseTime += state.benchmarkParseTime; + }; + } - Q.run(); + function finalize() { + callbacks.finish(state.totalInputSize, state.totalParseTime); } - }; -})); + /* Main */ + + Q.add(initialize); + benchmarks.forEach(function(benchmark) { + Q.add(benchmarkInitializer(benchmark)); + benchmark.tests.forEach(function(test) { + Q.add(testRunner(benchmark, test)); + }); + Q.add(benchmarkFinalizer(benchmark)); + }); + Q.add(finalize); + + Q.run(); + } +}; + +module.exports = Runner; diff --git a/benchmark/server b/benchmark/server new file mode 100755 index 0000000..865a2fe --- /dev/null +++ b/benchmark/server @@ -0,0 +1,38 @@ +#!/usr/bin/env node + +/* eslint-env node */ +/* eslint no-console: 0 */ + +/* + * Small server whose main purpose is to ensure that both the benchmarked code + * and the benchmark get passed through Babel & Browserify before they are + * served to the browser. + */ + +var express = require("express"), + logger = require("morgan"), + glob = require("glob"), + browserify = require("browserify"), + babelify = require("babelify"); + +var app = express(); + +app.use(logger("dev")); +app.use(express.static(__dirname)); +app.use("/examples", express.static(__dirname + "/../examples")); + +app.get("/bundle.js", function(req, res) { + var files = glob.sync(__dirname + "/**/*.js", { + ignore: __dirname + "/vendor/**/*" + }); + + browserify(files) + .transform(babelify, { presets: "es2015", compact: false }) + .bundle() + .pipe(res); +}); + +app.listen(8000, function() { + console.log("Benchmark server running at http://localhost:8000..."); +}); +