From c9b0e7a50dd60274d8a2815330d9ec83d020dd67 Mon Sep 17 00:00:00 2001 From: Wilson Lin Date: Thu, 2 Jan 2020 01:18:38 +1100 Subject: [PATCH] Generate benchmark graphs --- README.md | 6 +- bench/bench.js | 209 ++++++++++++++++++++++++++++------------- bench/minification.png | Bin 0 -> 26285 bytes bench/package.json | 6 +- bench/speed.png | Bin 0 -> 8135 bytes 5 files changed, 153 insertions(+), 68 deletions(-) create mode 100644 bench/minification.png create mode 100644 bench/speed.png diff --git a/README.md b/README.md index 45f81ff..a4d0cb8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # hyperbuild -A fast one-pass in-place HTML minifier written in Rust with advanced whitespace handling. +A fast one-pass in-place HTML minifier written in Rust with context-aware whitespace handling. Available as: - CLI for Windows, macOS, and Linux. @@ -13,6 +13,10 @@ Available as: - No extra heap memory is allocated during processing, which increases performance. - Context-aware whitespace handling allows maximum minification while retaining wanted spaces. +## Performance + +![Chart showing speed of HTML minifiers](./bench/speed.png) ![Chart showing effectiveness of HTML minifiers](./bench/minification.png) + ## Usage ### CLI diff --git a/bench/bench.js b/bench/bench.js index 2ea2902..267344c 100644 --- a/bench/bench.js +++ b/bench/bench.js @@ -1,95 +1,174 @@ "use strict"; -const fs = require("fs"); -const path = require("path"); const benchmark = require("benchmark"); +const chartjs = require('chartjs-node'); +const fs = require("fs"); const htmlMinifier = require("html-minifier"); -const minimize = require("minimize"); const hyperbuild = require("hyperbuild"); +const minimize = require("minimize"); +const path = require("path"); -const tests_dir = path.join(__dirname, "tests"); -const tests = fs.readdirSync(tests_dir).map(name => ({ +const testsDir = path.join(__dirname, "tests"); +const tests = fs.readdirSync(testsDir).map(name => ({ name, - content: fs.readFileSync(path.join(tests_dir, name), "utf8"), + content: fs.readFileSync(path.join(testsDir, name), "utf8"), })); +const programs = { + 'hyperbuild-nodejs': content => hyperbuild.minify(Buffer.from(content)), + 'html-minifier': content => htmlMinifier.minify(content, { + caseSensitive: false, + collapseBooleanAttributes: true, + collapseInlineTagWhitespace: true, + collapseWhitespace: true, + conservativeWhitespace: false, + customEventAttributes: [], + decodeEntities: true, + html5: true, + ignoreCustomComments: [], + ignoreCustomFragments: [], + includeAutoGeneratedTags: true, + keepClosingSlash: false, + minifyCSS: false, + minifyJS: false, + minifyURLs: false, + preserveLineBreaks: false, + preventAttributesEscaping: false, + processConditionalComments: true, + processScripts: [], + removeAttributeQuotes: true, + removeComments: true, + removeEmptyAttributes: false, + removeEmptyElements: false, + removeOptionalTags: true, + removeRedundantAttributes: true, + removeScriptTypeAttributes: true, + removeStyleLinkTypeAttributes: true, + removeTagWhitespace: true, + sortAttributes: true, + sortClassName: true, + trimCustomFragments: false, + useShortDoctype: true, + }).length, + 'minimize': content => new minimize().parse(content).length, +}; + +const colours = [ + { + backgroundColor: '#9ad0f5', + borderColor: '#47aaec', + }, + { + backgroundColor: '#ffb0c1', + borderColor: '#ff87a1', + }, + { + backgroundColor: '#a4dfdf', + borderColor: '#4bc0c0', + }, +]; +const renderChart = async (file, cfg) => { + const chart = new chartjs(450, 300); + await chart.drawChart({ + ...cfg, + options: { + scales: { + xAxes: [{ + barPercentage: 0.5, + gridLines: { + color: '#ccc', + }, + ticks: { + fontColor: '#222', + }, + }], + yAxes: [{ + gridLines: { + color: '#666', + }, + ticks: { + fontColor: '#222', + }, + }], + }, + legend: { + labels: { + fontFamily: 'Ubuntu, sans-serif', + fontColor: '#000', + }, + }, + }, + }); + await chart.writeImageToFile('image/png', path.join(__dirname, `${file}.png`)); +}; + const sizes = {}; const setSize = (program, test, result) => { - console.log(`Received result for ${program} - ${test}`); - if (!sizes[test]) { sizes[test] = { original: { - result: tests.find(t => t.name === test).content.length, + absolute: tests.find(t => t.name === test).content.length, + relative: 1, }, }; } - const original = sizes[test].original.result; + const original = sizes[test].original.absolute; sizes[test][program] = { - result: result, - difference: `${((result - original) / original * 100).toFixed(2)}%`, + absolute: result, + relative: result / original, }; }; -const htmlMinifierSettings = { - caseSensitive: false, - collapseBooleanAttributes: true, - collapseInlineTagWhitespace: true, - collapseWhitespace: true, - conservativeWhitespace: false, - customEventAttributes: [], - decodeEntities: true, - html5: true, - ignoreCustomComments: [], - ignoreCustomFragments: [], - includeAutoGeneratedTags: true, - keepClosingSlash: false, - minifyCSS: false, - minifyJS: false, - minifyURLs: false, - preserveLineBreaks: false, - preventAttributesEscaping: false, - processConditionalComments: true, - processScripts: [], - removeAttributeQuotes: true, - removeComments: true, - removeEmptyAttributes: false, - removeEmptyElements: false, - removeOptionalTags: true, - removeRedundantAttributes: true, - removeScriptTypeAttributes: true, - removeStyleLinkTypeAttributes: true, - removeTagWhitespace: true, - sortAttributes: true, - sortClassName: true, - trimCustomFragments: false, - useShortDoctype: true, -}; +// Run once to set sizes. +for (const t of tests) { + for (const p of Object.keys(programs)) { + setSize(p, t.name, programs[p](t.content)); + } +} -new benchmark.Suite() - .add("hyperbuild", () => { +const suite = new benchmark.Suite(); +for (const p of Object.keys(programs)) { + suite.add(p, () => { for (const t of tests) { - setSize("hyperbuild", t.name, hyperbuild.minify(Buffer.from(t.content))); + programs[p](t.content); } - }) - .add("html-minifier", () => { - for (const t of tests) { - setSize("html-minifier", t.name, htmlMinifier.minify(t.content, htmlMinifierSettings).length); - } - }) - .add("minimize", () => { - for (const t of tests) { - setSize("minimize", t.name, new minimize().parse(t.content).length); - } - }) + }); +} +suite .on('cycle', event => { console.info(event.target.toString()); }) - .on('complete', function () { - console.info(`Fastest is ${this.filter('fastest').map('name')}`); - Object.entries(sizes).forEach(([test, results]) => { - console.info(test); - console.table(results); + .on('complete', async function () { + const speedResults = this.map(b => ({ + name: b.name, + count: b.count, + ops: b.hz, + })).sort((a, b) => a.hz - b.hz); + await renderChart('speed', { + type: 'bar', + data: { + labels: speedResults.map(r => r.name), + datasets: [{ + label: 'Operations per second', + ...colours[0], + data: speedResults.map(r => r.ops), + }], + }, + }); + + const testNames = Object.keys(sizes); + const programNames = Object.keys(programs); + await renderChart('minification', { + type: 'bar', + scaleFontColor: 'red', + data: { + labels: testNames, + datasets: programNames.map((program, i) => ({ + label: program, + ...colours[i], + data: testNames.map(test => sizes[test][program].relative), + })), + }, }); }) .run({'async': true}); diff --git a/bench/minification.png b/bench/minification.png new file mode 100644 index 0000000000000000000000000000000000000000..8144403ff53d01c1ab08d766c2f04ab1193dda7b GIT binary patch literal 26285 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