Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: evanwashere/mitata
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 5331e95d027b5dd364348358ba22a351c8d973e2
Choose a base ref
...
head repository: evanwashere/mitata
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c0db24e47ac6223fe5dfa3968468f91751faaebc
Choose a head ref
  • 1 commit
  • 5 files changed
  • 1 contributor

Commits on Feb 4, 2025

  1. 1.0.34

    - add manual benchmarks
    - allow providing custom print function
    - include style information
    evanwashere committed Feb 4, 2025

    Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    c0db24e View commit details
Showing with 115 additions and 46 deletions.
  1. +1 −1 package.json
  2. +1 −1 readme.md
  3. +23 −9 src/lib.mjs
  4. +29 −10 src/main.d.mts
  5. +61 −25 src/main.mjs
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
"name": "mitata",
"type": "module",
"license": "MIT",
"version": "1.0.33",
"version": "1.0.34",
"main": "src/main.mjs",
"types": "src/main.d.mts",
"files": ["src", "license", "readme.md"],
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -135,7 +135,7 @@ Array.from(512) 1.29 µs/iter 1.30 µs ▂▆█

## universal compatibility

Out of box mitata can detect engine/runtime it's running on and fall back to using [alternative](https://github.com/evanwashere/mitata/blob/master/src/lib.mjs#L45) non-standard I/O functions. If your engine or runtime is missing support, open an issue or pr requesting for support.
Out of box mitata can detect engine/runtime it's running on and fall back to using [alternative](https://github.com/evanwashere/mitata/blob/master/src/lib.mjs#L51) non-standard I/O functions. If your engine or runtime is missing support, open an issue or pr requesting for support.

### how to use mitata with engine CLIs like d8, jsc, graaljs, spidermonkey

32 changes: 23 additions & 9 deletions src/lib.mjs
Original file line number Diff line number Diff line change
@@ -20,20 +20,26 @@ export async function generator(gen, opts = {}) {
const g = gen(ctx);
const n = await g.next();

if (n.done || 'fn' !== kind(n.value)) {
if ('fn' !== kind(n.value?.bench, true)) throw new TypeError('expected benchmarkable yield from generator');
let $fn = n.value;
if (!n.value?.heap && null != n.value?.heap) opts.heap = false;
opts.concurrency ??= n.value?.concurrency ?? opts.args?.concurrency;
if (!n.value?.counters && null != n.value?.counters) opts.$counters = false;

if (n.done || 'fn' !== kind($fn)) {
$fn = n.value?.bench || n.value?.manual;
if ('fn' !== kind($fn, true)) throw new TypeError('expected benchmarkable yield from generator');

opts.params ??= {};
const params = n.value.bench.length;
const params = $fn.length;
opts.manual = !n.value.manual ? false : ('manual' !== n.value.budget ? 'real' : 'manual');

for (let o = 0; o < params; o++) {
opts.params[o] = n.value[o];
if ('fn' !== kind(n.value[o])) throw new TypeError('expected function for benchmark parameter');
}
}

opts.concurrency ??= n.value?.concurrency ?? opts.args?.concurrency;
const stats = await fn('fn' === kind(n.value) ? n.value : n.value.bench, opts);
const stats = await fn($fn, opts);
if (!(await g.next()).done) throw new TypeError('expected generator to yield once');

return {
@@ -133,6 +139,7 @@ function defaults(opts) {
opts.now ??= now;
opts.heap ??= null;
opts.params ??= {};
opts.manual ??= false;
opts.inner_gc ??= false;
opts.$counters ??= false;
opts.concurrency ??= k_concurrency;
@@ -180,6 +187,11 @@ export async function fn(fn, opts = {}) {
}
}

if (opts.manual) {
batch = false;
opts.concurrency = 1;
}

const loop = new AsyncFunction('$fn', '$gc', '$now', '$heap', '$params', '$counters', `
${!opts.$counters ? '' : 'let _hc = false;'}
${!opts.$counters ? '' : 'try { $counters.init(); _hc = true; } catch {}'}
@@ -225,27 +237,28 @@ export async function fn(fn, opts = {}) {
}
`}
${!opts.manual ? '' : 'let t2 = 0;'}
${!opts.heap ? '' : 'const h0 = $heap();'}
${!opts.$counters ? '' : 'if (_hc) try { $counters.before(); } catch {};'} const t0 = $now();
${!batch ? `
${!async ? '' : (1 >= opts.concurrency ? '' : 'await Promise.all([')}
${Array.from({ length: opts.concurrency }, (_, c) => `
${!async ? '' : (1 < opts.concurrency ? '' : 'await ')} ${(!params.length ? `
${!opts.manual ? '' : 't2 +='} ${!async ? '' : (1 < opts.concurrency ? '' : 'await')} ${(!params.length ? `
$fn()
` : `
$fn(${Array.from({ length: params.length }, (_, o) => `param_${o}_${c}`).join(', ')})
`).trim()}${!async ? ';' : (1 < opts.concurrency ? ',' : ';')}
`.trim()).join('\n')}
${!async ? '' : (1 >= opts.concurrency ? '' : ']);')}
${!async ? '' : (1 >= opts.concurrency ? '' : `]);`)}
` : `
for (let o = 0; o < ${(opts.batch_samples / opts.batch_unroll) | 0}; o++) {
${!params.length ? '' : `const param_offset = o * ${opts.batch_unroll};`}
${Array.from({ length: opts.batch_unroll }, (_, u) => `
${!async ? '' : (1 >= opts.concurrency ? '' : 'await Promise.all([')}
${Array.from({ length: opts.concurrency }, (_, c) => `
${!async ? '' : (1 < opts.concurrency ? '' : 'await ')} ${(!params.length ? `
${!async ? '' : (1 < opts.concurrency ? '' : 'await')} ${(!params.length ? `
$fn()
` : `
$fn(${Array.from({ length: params.length }, (_, o) => `param_${o}_${c}[${u === 0 ? '' : `${u} + `}param_offset]`).join(', ')})
@@ -285,7 +298,8 @@ export async function fn(fn, opts = {}) {
}
`};
const diff = t1 - t0; t += diff;
const diff = ${opts.manual ? 't2' : 't1 - t0'};
t += ${'manual' === opts.manual ? 't2' : 't1 - t0'};
samples[_] = diff ${!batch ? '' : `/ ${opts.batch_samples}`};
}
39 changes: 29 additions & 10 deletions src/main.d.mts
Original file line number Diff line number Diff line change
@@ -88,22 +88,28 @@ export function boxplot(f: () => Promise<any>): Promise<void>;
export function barplot(f: () => Promise<any>): Promise<void>;
export function group(name: string, f: () => Promise<any>): Promise<void>;

export function run(opts?: { throw?: boolean; filter?: RegExp; colors?: boolean; format?: 'json' | 'quiet' | 'mitata' | 'markdown' | { mitata: { name?: number | 'fixed' | 'longest' } }; }): Promise<{ context: ctx, benchmarks: trial[] }>;
export function run(opts?: {
throw?: boolean;
filter?: RegExp;
colors?: boolean;
print?: (s: string) => any;
observe?: (t: trial) => trial;

format?:
'json'
| 'quiet'
| 'mitata'
| 'markdown'
| { json: { debug?: boolean, samples?: boolean } }
| { mitata: { name?: number | 'fixed' | 'longest' } }
}): Promise<{ context: ctx, benchmarks: trial[] }>;

export const flags: {
compact: number;
baseline: number;
};

interface trial {
runs: run[];
alias: string;
baseline: boolean;
args: Record<string, any[]>;
kind: 'args' | 'static' | 'multi-args';
}

type run = ({
type Run = ({
stats: stats;
error: undefined;
} | {
@@ -114,6 +120,19 @@ type run = ({
args: Record<string, any>;
}

interface trial {
runs: Run[];
alias: string;
baseline: boolean;
args: Record<string, any[]>;
kind: 'args' | 'static' | 'multi-args';

style: {
compact: boolean;
highlight: false | string;
};
}

export class B {
constructor(name: string, fn: () => any);
constructor(name: string, gen: (state: k_state) => Gen);
Loading