Files
value-graph/bench/hotpath.js
T

39 lines
1.9 KiB
JavaScript
Raw Normal View History

// Hotpath micro-benchmark: how fast is a value-graph `get` on the authorization
// hotpath? Compared against a plain Map lookup.
import { performance } from 'node:perf_hooks';
import { ValueGraph } from '../src/index.js';
function bench(name, fn, iterations = 200_000) {
for (let i = 0; i < 10_000; i++) fn(); // warmup
const t0 = performance.now();
for (let i = 0; i < iterations; i++) fn();
const ms = performance.now() - t0;
const nsPerOp = (ms * 1e6) / iterations;
const opsPerSec = Math.round((iterations / ms) * 1000);
console.log(`${name.padEnd(46)} ${nsPerOp.toFixed(0).padStart(8)} ns/op ${String(opsPerSec).padStart(10)} ops/sec`);
}
const vg = new ValueGraph();
vg.compute('balance', () => 1250);
await new Promise((res) => vg.get('u:1', 'balance', {}, (e, v) => res(v)));
const plan = vg.plan('u:1', 'balance', {}); // cached plan for the hot loop
const coldVg = new ValueGraph();
coldVg.compute('balance', () => 42);
vg.define('a', { operator: 'source', fn: () => 10 });
vg.define('b', { operator: 'source', fn: () => 20 });
vg.define('c', { operator: 'source', fn: () => 30 });
vg.define('risk', { operator: 'fusion:custom', parents: ['a', 'b', 'c'], weights: [0.6, 0.3, 0.1] });
await new Promise((res) => vg.get('u:1', 'risk', {}, (e, v) => res(v)));
const baseline = new Map([['u:1|balance|{}', 1250]]);
console.log('--- hotpath (authorization value lookup) ---');
bench('Map.get baseline', () => baseline.get('u:1|balance|{}'));
bench('vg.get cached (plan/run)', () => vg.run(plan, () => {}));
bench('vg.get cached (get + compile)', () => vg.get('u:1', 'balance', {}, () => {}));
bench('vg.get cold (fresh compute)', () => coldVg.get('x', 'balance', {}, () => {}));
bench('vg.get fusion:custom DAG', () => vg.get('u:1', 'risk', {}, () => {}));
bench('vg.query duplex {get}', () => { const q = vg.query('u:1', 'balance', {}); q.sink.write({ get: true }); q.sink.end(); });