Skip to content

Commit c715328

Browse files
committed
wasm: Add benchmark script
1 parent 8ac65d9 commit c715328

File tree

8 files changed

+3720
-38
lines changed

8 files changed

+3720
-38
lines changed

packages/wasm/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"ava": "^6.2.0",
2929
"esbuild": "^0.25.5",
3030
"liquid-html-parser": "link:@shopify/liquid-html-parser",
31+
"mitata": "^1.0.34",
3132
"wabt": "1.0.37-nightly.20250428"
3233
},
3334
"peerDependencies": {

packages/wasm/scripts/bench.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import {readFileSync} from 'node:fs';
2+
import {dirname, join} from 'node:path';
3+
import {fileURLToPath} from 'node:url';
4+
import {run, bench, group, summary} from 'mitata';
5+
import * as ohm from 'ohm-js';
6+
7+
import es5js from '../../../examples/ecmascript/index.js';
8+
import {makeEs5Matcher, wasmMatcherForGrammar} from '../test/_helpers.js';
9+
10+
const __dirname = dirname(fileURLToPath(import.meta.url));
11+
const datadir = join(__dirname, '../test/data');
12+
13+
const inputs = {
14+
bookReview: readFileSync(join(datadir, '_book-review.liquid'), 'utf-8'),
15+
featuredProduct: readFileSync(join(datadir, '_featured-product.liquid'), 'utf-8'),
16+
footer: readFileSync(join(datadir, '_footer.liquid'), 'utf-8'),
17+
html5shiv: readFileSync(join(datadir, '_html5shiv-3.7.3.js'), 'utf-8'),
18+
underscore: readFileSync(join(datadir, '_underscore-1.8.3.js'), 'utf-8')
19+
};
20+
21+
const es5Matcher = await makeEs5Matcher();
22+
23+
function matchWithInput(m, input) {
24+
m.setInput(input);
25+
return m.match();
26+
}
27+
28+
const liquid = ohm.grammars(readFileSync(join(datadir, '_liquid-html.ohm'), 'utf8'));
29+
const liquidMatcher = await wasmMatcherForGrammar(liquid.LiquidHTML);
30+
31+
group('ES5: html5shiv', () => {
32+
summary(() => {
33+
bench('Wasm', () => {
34+
matchWithInput(es5Matcher, inputs.html5shiv);
35+
});
36+
bench('JS', () => {
37+
es5js.grammar.match(inputs.html5shiv);
38+
});
39+
});
40+
});
41+
42+
group('ES5: underscore', () => {
43+
summary(() => {
44+
bench('Wasm', () => {
45+
matchWithInput(es5Matcher, inputs.underscore);
46+
});
47+
bench('JS', () => {
48+
es5js.grammar.match(inputs.underscore);
49+
});
50+
});
51+
});
52+
53+
group('LiquidHTML: book-review.liquid', () => {
54+
summary(() => {
55+
bench('Wasm', () => {
56+
matchWithInput(liquidMatcher, inputs.bookReview);
57+
});
58+
bench('JS', () => {
59+
liquid.LiquidHTML.match(inputs.bookReview);
60+
});
61+
});
62+
});
63+
64+
group('LiquidHTML: featured-product.liquid', () => {
65+
summary(() => {
66+
bench('Wasm', () => {
67+
matchWithInput(liquidMatcher, inputs.featuredProduct);
68+
});
69+
bench('JS', () => {
70+
liquid.LiquidHTML.match(inputs.featuredProduct);
71+
});
72+
});
73+
});
74+
75+
group('LiquidHTML: footer.liquid', () => {
76+
summary(() => {
77+
bench('Wasm', () => {
78+
matchWithInput(liquidMatcher, inputs.footer);
79+
});
80+
bench('JS', () => {
81+
liquid.LiquidHTML.match(inputs.footer);
82+
});
83+
});
84+
});
85+
86+
await run();

packages/wasm/test/_helpers.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
/* global process */
22

33
import {WasmMatcher} from '@ohm-js/miniohm-js';
4+
import * as ohm from 'ohm-js';
45

56
import {Compiler} from '../src/index.js';
7+
import es5fac from './data/_es5.js';
68

79
const DEBUG = process.env.OHM_DEBUG === '1';
810

@@ -29,3 +31,35 @@ export async function wasmMatcherForGrammar(grammar) {
2931
}
3032
return m._instantiate(bytes, debugImports);
3133
}
34+
35+
function ES5Matcher(rules) {
36+
// `rules` is an object with the raw rule bodies.
37+
// The WasmMatcher constructor requires a grammar object, so we create
38+
// one and manually add the rules in.
39+
const g = ohm.grammar('ES5 { start = }');
40+
for (const key of Object.keys(rules)) {
41+
g.rules[key] = {
42+
body: rules[key],
43+
formals: [],
44+
description: key,
45+
primitive: false,
46+
};
47+
}
48+
// Since this is called with `new`, we can't use `await` here.
49+
return wasmMatcherForGrammar(g);
50+
}
51+
52+
export async function makeEs5Matcher() {
53+
return es5fac({
54+
Terminal: ohm.pexprs.Terminal,
55+
RuleApplication: ohm.pexprs.Apply,
56+
Sequence: ohm.pexprs.Seq,
57+
Choice: ohm.pexprs.Alt,
58+
Repetition: ohm.pexprs.Star,
59+
Not: ohm.pexprs.Not,
60+
Range: ohm.pexprs.Range,
61+
any: ohm.pexprs.any,
62+
end: ohm.pexprs.end,
63+
Matcher: ES5Matcher,
64+
});
65+
}

0 commit comments

Comments
 (0)