Create microbenchmark for mozjexl and optimize
Categories
(Core :: JavaScript Engine, task, P3)
Tracking
()
People
(Reporter: mgaudet, Unassigned)
References
(Blocks 3 open bugs)
Details
One of the tasks happening in applink startup is executing JEXL expressions, https://github.com/mozilla/mozjexl
https://share.firefox.dev/40yRs8y suggests ~70ms in the parent process.
mozjexl is in tree; we could write a microbenchmark to investigate if we could speed it up.
The most important step being that we need to get some insight into the JEXL expressions being executed.
A basic outline is:
/**
* Quick performance test for mozjexl
* Run with: ./mach run -m mozjexl-perf-quick.js from the firefox root.
*/
import { mozjexl } from './toolkit/components/utils/mozjexl.sys.mjs';
const jexl = new mozjexl.Jexl();
// Add test transforms
jexl.addTransform('upper', str => str.toUpperCase());
jexl.addTransform('length', val => val.length);
// Test data
const context = {
simple: 42,
nested: { value: 100 },
employees: [
{ name: 'Alice', age: 30, salary: 70000 },
{ name: 'Bob', age: 35, salary: 80000 },
{ name: 'Charlie', age: 25, salary: 60000 },
{ name: 'David', age: 40, salary: 90000 },
{ name: 'Eve', age: 28, salary: 65000 }
]
};
// Test cases
const tests = [
{ name: 'Simple arithmetic', expr: '2 + 3 * 4' },
{ name: 'Variable access', expr: 'simple' },
{ name: 'Nested access', expr: 'nested.value' },
{ name: 'Array filter', expr: 'employees[.age > 30]' },
{ name: 'Transform', expr: '"hello"|upper' },
{ name: 'Complex', expr: 'employees[.age > 30]|length > 1' }
];
// Run tests
async function runTests() {
print('mozjexl Quick Performance Test\n');
for (const test of tests) {
// Warmup
for (let i = 0; i < 5; i++) {
await jexl.eval(test.expr, context);
}
// Measure
const times = [];
const iterations = 50;
for (let i = 0; i < iterations; i++) {
const start = dateNow();
await jexl.eval(test.expr, context);
const end = dateNow();
times.push(end - start);
}
const avg = times.reduce((a, b) => a + b) / times.length;
print(`${test.name}: ${avg.toFixed(3)}ms (${test.expr})`);
}
}
runTests().then(
() => { print('\nDone'); quit(0); },
err => { print('Error:', err); quit(1); }
);
Reporter | ||
Comment 1•27 days ago
|
||
Do you know where one could get a corpus of 'representative' jexl that you'd expect to see, so we could rig up a benchmark?
Comment 2•27 days ago
|
||
https://bug1978973.bmoattachments.org/attachment.cgi?id=9502774 is an example of what we're evaluating
Reporter | ||
Comment 3•27 days ago
|
||
Thats' great actually;
I will say, writing a microbenchmark here is awkwrd though, because basically since jexl.eval returns a promise, it's hard for this to not turn into a promises microbenchmark. T
Comment 4•27 days ago
|
||
It should be a promises microbenchmark. That's where all the time is being spent.
That being said we are also trying this approach: https://github.com/mozilla/mozjexl/commit/14f7f16f83d3629f203640c934c87d26762711bf
Comment 5•27 days ago
|
||
Here's two benchmarks:
https://mozjexl-benchmark.netlify.app/promises/benchmark.html
https://mozjexl-benchmark.netlify.app/synchronous-promises/benchmark.html
Firefox is appreciably slower at both
Comment 6•27 days ago
|
||
Here's a profile of synchronous-promises/benchmark.html
https://share.firefox.dev/4f7hghR
This has the promise overhead mostly eliminated. But mozjexl is still pretty slow. It does not seem designed to run quickly.
Comment 7•23 days ago
|
||
We should honestly consider rewriting the evaluator in moxjexl to be smarter about only awaiting when necessary.
There has not been a vendoring of mozjexl into the tree in a long time though and i believe the version in tree is different from the version on github.
Reporter | ||
Updated•22 days ago
|
Description
•