Improve bench

This commit is contained in:
Wilson Lin 2021-08-09 19:24:43 +10:00
parent 2e4015de40
commit 7d5ba5033b
6 changed files with 67 additions and 98 deletions

View File

@ -19,8 +19,7 @@ A Rust HTML minifier meticulously optimised for speed and effectiveness, with bi
Comparison with [html-minfier](https://github.com/kangax/html-minifier) and [minimize](https://github.com/Swaagie/minimize), run on the top web pages. [See the breakdown here.](./bench)
<img width="415" alt="Chart showing speed of HTML minifiers" src="https://wilsonl.in/minify-html/bench/0.6.1/core/average-speeds.png">
<img width="415" alt="Chart showing compression of HTML minifiers" src="https://wilsonl.in/minify-html/bench/0.6.1/core/average-sizes.png">
<img width="415" alt="Chart showing speed of HTML minifiers" src="https://wilsonl.in/minify-html/bench/0.6.1/core/average-speeds.png"><img width="415" alt="Chart showing compression of HTML minifiers" src="https://wilsonl.in/minify-html/bench/0.6.1/core/average-sizes.png">
The [onepass](https://github.com/wilsonzlin/minify-html/tree/master/rust/onepass) variant is even more optimised for speed. See its [README](https://github.com/wilsonzlin/minify-html/tree/master/rust/onepass) for more details.

View File

@ -6,12 +6,7 @@ It also contains a set of common web pages as tests for benchmarking.
## Comparison
The [Node.js version of minify-html](../nodejs) is tested against [html-minfier](https://github.com/kangax/html-minifier) and [minimize](https://github.com/Swaagie/minimize) in two dimensions:
- Speed as operations per second.
- Minified file size compared to the original.
[Benchmark.js](https://benchmarkjs.com) is used to determine speed. Each minifier is run against each file in the [tests](./tests) folder, which are HTML pages fetched from popular websites:
Each minifier is run against each file in the [inputs](./inputs) folder, which are HTML pages fetched from popular websites:
|File name|URL|
|---|---|
@ -35,37 +30,14 @@ For more information on how the tests are fetched, see [fetch.js](./fetch.js).
On this [project's README](../README.md), average graphs are shown. Graphs showing per-test results are shown below:
<img width="435" alt="Chart showing speed of HTML minifiers per test" src="https://wilsonl.in/minify-html/bench/0.6.1/core/speeds.png"> <img width="435" alt="Chart showing effectiveness of HTML minifiers per test" src="https://wilsonl.in/minify-html/bench/0.6.1/core/sizes.png">
<img width="435" alt="Chart showing speed of HTML minifiers per test" src="https://wilsonl.in/minify-html/bench/0.6.1/core/speeds.png"><img width="435" alt="Chart showing effectiveness of HTML minifiers per test" src="https://wilsonl.in/minify-html/bench/0.6.1/core/sizes.png">
Since speed depends on the input, speed charts show performance relative to the Node.js minify-html as a percentage.
The settings used for each minifier can be found in [minifiers.js](./minifiers.js). Some settings to note:
- `conservativeCollapse` is enabled for html-minifier as otherwise some whitespace would be unsafely removed with side effects. minify-html can safely remove whitespace with context if configured properly.
Results depend on the input, so charts show performance relative to minify-html as a percentage.
## Running
Make sure to install the dependencies listed in [package.json](./package.json) by running `npm i` or `yarn`.
Run [build](./build) to build the minifiers.
Run [build.sh](./build.sh) to build @minify-html/js with the local minify-html.
Run [sizes.js](sizes.js) to run each HTML minifier against each test and record the minified size results. This will also output the minified files in `min` if inspection of minified outputs is necessary. [compare.sh](./compare.sh) is a useful script for viewing a character-by-character diff between the minified outputs of minify-html and html-minifier for a specific test. Pass the test's file name as the first argument.
Run [speeds.js](./speeds.js) to benchmark the performance of each HTML minifier against each test and record the op/s results.
Run [run](./run) to benchmark the performance of each HTML minifier against each test and record the op/s results.
Run [graph.js](./graph.js) to render graphs from recorded speed and size results in the `results` folder.
## minify-html-bench
The [minify-html-bench](./minify-html-bench) folder contains a Rust executable subproject that runs the local minify-html on all tests for many iterations to calculate speed as operations per second.
This can be useful for profiling the core code or checking the performance of minify-html in other languages with native bindings.
It takes two arguments:
- `--tests`: path to the folder containing tests to use as inputs.
- `--iterations`: how many iterations to run per test.
The results will be written to stdout as a JSON object, where properties are the test file names and values are the operations per second.
Profiling minify-html can be done on Linux by using [profile.sh](./profile.sh), which uses `perf`. The generated report can be used using `perf report`.

View File

@ -1,7 +1,7 @@
const results = require("./results");
const fs = require("fs/promises");
const https = require("https");
const path = require("path");
const fs = require("fs/promises");
const results = require("./results");
const GRAPHS_DIR = path.join(__dirname, "graphs");
const SPEEDS_GRAPH = path.join(GRAPHS_DIR, "speeds.png");
@ -10,7 +10,6 @@ const AVERAGE_SPEEDS_GRAPH = path.join(GRAPHS_DIR, "average-speeds.png");
const AVERAGE_SIZES_GRAPH = path.join(GRAPHS_DIR, "average-sizes.png");
const speedColours = {
"@minify-html/js": "#2e61bd",
"minify-html": "#2e61bd",
"minify-html-onepass": "#222",
};
@ -21,12 +20,57 @@ const sizeColours = {
};
const defaultSizeColour = "rgb(188, 188, 188)";
const averageChartOptions = (label) => ({
options: {
legend: {
display: false,
},
scales: {
xAxes: [
{
barPercentage: 0.5,
gridLines: {
display: false,
},
ticks: {
fontColor: "#555",
fontSize: 20,
},
},
],
yAxes: [
{
type: "linear",
scaleLabel: {
display: true,
fontColor: '#222',
fontSize: 24,
fontStyle: "bold",
labelString: label,
padding: 12,
},
position: "left",
ticks: {
callback: "$$$_____REPLACE_WITH_TICK_CALLBACK_____$$$",
fontColor: "#222",
fontSize: 20,
},
gridLines: {
color: "#eee",
},
},
],
},
},
});
const breakdownChartOptions = (title) => ({
options: {
legend: {
display: true,
labels: {
fontColor: "#000",
fontSize: 20,
},
},
title: {
@ -64,52 +108,6 @@ const breakdownChartOptions = (title) => ({
},
});
const axisLabel = (fontColor, labelString) => ({
display: true,
fontColor,
fontSize: 24,
fontStyle: "bold",
labelString,
padding: 12,
});
const averageChartOptions = (label) => ({
options: {
legend: {
display: false,
},
scales: {
xAxes: [
{
barPercentage: 0.5,
gridLines: {
display: false,
},
ticks: {
fontColor: "#555",
fontSize: 16,
},
},
],
yAxes: [
{
type: "linear",
scaleLabel: axisLabel("#222", label),
position: "left",
ticks: {
callback: "$$$_____REPLACE_WITH_TICK_CALLBACK_____$$$",
fontColor: "#222",
fontSize: 16,
},
gridLines: {
color: "#eee",
},
},
],
},
},
});
const renderChart = (cfg, width, height) =>
new Promise((resolve, reject) => {
const req = https.request("https://quickchart.io/chart", {
@ -147,9 +145,7 @@ const renderChart = (cfg, width, height) =>
await fs.mkdir(GRAPHS_DIR, { recursive: true });
const res = results.calculate();
const speedMinifiers = [...res.minifiers].sort(
(a, b) => res.minifierAvgOps[a] - res.minifierAvgOps[b]
);
const speedMinifiers = ["html-minifier", "minimize", "minify-html", "minify-html-onepass"];
const sizeMinifiers = ["minimize", "html-minifier", "minify-html"];
const inputs = Object.keys(res.inputSizes).sort();
@ -159,7 +155,7 @@ const renderChart = (cfg, width, height) =>
{
type: "bar",
data: {
labels: speedMinifiers.map((m) => m.replace(" (", "\n(")),
labels: speedMinifiers,
datasets: [
{
backgroundColor: speedMinifiers.map(
@ -184,7 +180,7 @@ const renderChart = (cfg, width, height) =>
{
type: "bar",
data: {
labels: sizeMinifiers.map((m) => m.replace(" (", "\n(")),
labels: sizeMinifiers,
datasets: [
{
backgroundColor: sizeMinifiers.map(
@ -212,14 +208,14 @@ const renderChart = (cfg, width, height) =>
label: minifier,
data: inputs.map(
(input) =>
res.perInputOps[minifier][input] / res.maxInputOps[input]
res.perInputOps[minifier][input] / res.perInputOps['minify-html'][input]
),
})),
},
...breakdownChartOptions("Operations per second (higher is better)"),
...breakdownChartOptions("Operations per second, relative to minify-html"),
},
900,
1000
800,
1280
)
);
@ -232,13 +228,13 @@ const renderChart = (cfg, width, height) =>
labels: inputs,
datasets: sizeMinifiers.map((minifier) => ({
label: minifier,
data: inputs.map((input) => res.perInputReduction[minifier][input]),
data: inputs.map((input) => res.perInputReduction[minifier][input] / res.perInputReduction['minify-html'][input]),
})),
},
...breakdownChartOptions("Size reduction (higher is better)"),
...breakdownChartOptions("Size reduction, relative to minify-html"),
},
900,
1000
800,
1280
)
);
})();

1
debug/diff/README.md Normal file
View File

@ -0,0 +1 @@
[compare.sh](./compare.sh) is a useful script for viewing a character-by-character diff between the minified outputs of minify-html and html-minifier for a specific test. Pass the test's file name as the first argument.

1
debug/prof/README.md Normal file
View File

@ -0,0 +1 @@
Profiling minify-html can be done on Linux by using [profile.sh](./profile.sh), which uses `perf`. The generated report can be used using `perf report`.

View File

@ -8,7 +8,7 @@ An HTML minifier that provides the functionality of [minify-html](https://github
## Performance
<img alt="Chart showing speed of HTML minifiers" src="https://wilsonl.in/minify-html/bench/0.6.1/core/average-speeds.png">
<img width="600" alt="Chart showing speed of HTML minifiers" src="https://wilsonl.in/minify-html/bench/0.6.1/core/average-speeds.png">
## Usage