overtake 1.0.0-rc.0 → 1.0.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/build/cli.cjs +8 -8
- package/build/cli.cjs.map +1 -1
- package/build/cli.js +2 -2
- package/build/cli.js.map +1 -1
- package/build/executor.cjs.map +1 -1
- package/build/executor.js.map +1 -1
- package/build/index.cjs +228 -11
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +65 -3
- package/build/index.js +187 -1
- package/build/index.js.map +1 -1
- package/build/queue.cjs.map +1 -1
- package/build/queue.js.map +1 -1
- package/build/reporter.cjs +1 -1
- package/build/reporter.cjs.map +1 -1
- package/build/reporter.js +1 -1
- package/build/reporter.js.map +1 -1
- package/build/runner.cjs.map +1 -1
- package/build/runner.js.map +1 -1
- package/build/types.cjs.map +1 -1
- package/build/types.js.map +1 -1
- package/build/utils.cjs +2 -2
- package/build/utils.cjs.map +1 -1
- package/build/utils.js +2 -2
- package/build/utils.js.map +1 -1
- package/examples/array-copy.ts +17 -0
- package/package.json +3 -3
- package/src/cli.ts +2 -2
- package/src/index.ts +232 -3
- package/src/reporter.ts +1 -1
- package/build/__tests__/runner.d.ts +0 -1
- package/build/benchmark.cjs +0 -237
- package/build/benchmark.cjs.map +0 -1
- package/build/benchmark.d.ts +0 -64
- package/build/benchmark.js +0 -189
- package/build/benchmark.js.map +0 -1
- package/overtakes/array-copy.md +0 -80
- package/overtakes/array-delete-element.md +0 -44
- package/overtakes/async.md +0 -25
- package/overtakes/class-vs-function.md +0 -31
- package/overtakes/postgres-vs-mongo.md +0 -55
- package/src/__tests__/runner.ts +0 -34
- package/src/benchmark.ts +0 -231
package/build/index.js
CHANGED
|
@@ -1,3 +1,189 @@
|
|
|
1
|
-
|
|
1
|
+
import { cpus } from 'node:os';
|
|
2
|
+
import { createExecutor } from "./executor.js";
|
|
3
|
+
import { DEFAULT_CYCLES } from "./types.js";
|
|
4
|
+
export const DEFAULT_WORKERS = cpus().length;
|
|
5
|
+
export const AsyncFunction = (async ()=>{}).constructor;
|
|
6
|
+
export const DEFAULT_REPORT_TYPES = [
|
|
7
|
+
'ops'
|
|
8
|
+
];
|
|
9
|
+
export class MeasureContext {
|
|
10
|
+
title;
|
|
11
|
+
run;
|
|
12
|
+
pre;
|
|
13
|
+
post;
|
|
14
|
+
constructor(title, run){
|
|
15
|
+
this.title = title;
|
|
16
|
+
this.run = run;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export class Measure {
|
|
20
|
+
#ctx;
|
|
21
|
+
constructor(ctx){
|
|
22
|
+
this.#ctx = ctx;
|
|
23
|
+
}
|
|
24
|
+
pre(fn) {
|
|
25
|
+
this.#ctx.pre = fn;
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
post(fn) {
|
|
29
|
+
this.#ctx.post = fn;
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class TargetContext {
|
|
34
|
+
title;
|
|
35
|
+
setup;
|
|
36
|
+
teardown;
|
|
37
|
+
measures;
|
|
38
|
+
constructor(title, setup){
|
|
39
|
+
this.title = title;
|
|
40
|
+
this.setup = setup;
|
|
41
|
+
this.measures = [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export class Target {
|
|
45
|
+
#ctx;
|
|
46
|
+
constructor(ctx){
|
|
47
|
+
this.#ctx = ctx;
|
|
48
|
+
}
|
|
49
|
+
teardown(fn) {
|
|
50
|
+
this.#ctx.teardown = fn;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
measure(title, run) {
|
|
54
|
+
const measure = new MeasureContext(title, run);
|
|
55
|
+
this.#ctx.measures.push(measure);
|
|
56
|
+
return new Measure(measure);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export class FeedContext {
|
|
60
|
+
title;
|
|
61
|
+
fn;
|
|
62
|
+
constructor(title, fn){
|
|
63
|
+
this.title = title;
|
|
64
|
+
this.fn = fn;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export class Benchmark {
|
|
68
|
+
#targets = [];
|
|
69
|
+
#feeds = [];
|
|
70
|
+
#executed = false;
|
|
71
|
+
static create(title, fn) {
|
|
72
|
+
if (fn) {
|
|
73
|
+
return new Benchmark(title, fn);
|
|
74
|
+
} else {
|
|
75
|
+
return new Benchmark(title);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
constructor(title, fn){
|
|
79
|
+
if (fn) {
|
|
80
|
+
this.feed(title, fn);
|
|
81
|
+
} else {
|
|
82
|
+
this.feed(title);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
feed(title, fn) {
|
|
86
|
+
const self = this;
|
|
87
|
+
self.#feeds.push(fn ? new FeedContext(title, fn) : new FeedContext(title));
|
|
88
|
+
return self;
|
|
89
|
+
}
|
|
90
|
+
target(title, setup) {
|
|
91
|
+
const target = new TargetContext(title, setup);
|
|
92
|
+
this.#targets.push(target);
|
|
93
|
+
return new Target(target);
|
|
94
|
+
}
|
|
95
|
+
async execute({ workers = DEFAULT_WORKERS, warmupCycles = 20, maxCycles = DEFAULT_CYCLES, minCycles = 50, absThreshold = 1_000, relThreshold = 0.02, reportTypes = DEFAULT_REPORT_TYPES }) {
|
|
96
|
+
if (this.#executed) {
|
|
97
|
+
throw new Error("Benchmark is executed and can't be reused");
|
|
98
|
+
}
|
|
99
|
+
this.#executed = true;
|
|
100
|
+
const executor = createExecutor({
|
|
101
|
+
workers,
|
|
102
|
+
warmupCycles,
|
|
103
|
+
maxCycles,
|
|
104
|
+
minCycles,
|
|
105
|
+
absThreshold,
|
|
106
|
+
relThreshold,
|
|
107
|
+
reportTypes
|
|
108
|
+
});
|
|
109
|
+
const reports = [];
|
|
110
|
+
for (const target of this.#targets){
|
|
111
|
+
const targetReport = {
|
|
112
|
+
target: target.title,
|
|
113
|
+
measures: []
|
|
114
|
+
};
|
|
115
|
+
for (const measure of target.measures){
|
|
116
|
+
const measureReport = {
|
|
117
|
+
measure: measure.title,
|
|
118
|
+
feeds: []
|
|
119
|
+
};
|
|
120
|
+
for (const feed of this.#feeds){
|
|
121
|
+
const data = await feed.fn?.();
|
|
122
|
+
executor.push({
|
|
123
|
+
setup: target.setup,
|
|
124
|
+
teardown: target.teardown,
|
|
125
|
+
pre: measure.pre,
|
|
126
|
+
run: measure.run,
|
|
127
|
+
post: measure.post,
|
|
128
|
+
data
|
|
129
|
+
}).then((data)=>{
|
|
130
|
+
measureReport.feeds.push({
|
|
131
|
+
feed: feed.title,
|
|
132
|
+
data
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
targetReport.measures.push(measureReport);
|
|
137
|
+
}
|
|
138
|
+
reports.push(targetReport);
|
|
139
|
+
}
|
|
140
|
+
await executor.drain();
|
|
141
|
+
executor.kill();
|
|
142
|
+
return reports;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
export const printSimpleReports = (reports)=>{
|
|
146
|
+
for (const report of reports){
|
|
147
|
+
for (const { measure, feeds } of report.measures){
|
|
148
|
+
console.group('\n', report.target, measure);
|
|
149
|
+
for (const { feed, data } of feeds){
|
|
150
|
+
const output = Object.entries(data).map(([key, report])=>`${key}: ${report.toString()}`).join('; ');
|
|
151
|
+
console.log(feed, output);
|
|
152
|
+
}
|
|
153
|
+
console.groupEnd();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
export const printTableReports = (reports)=>{
|
|
158
|
+
for (const report of reports){
|
|
159
|
+
for (const { measure, feeds } of report.measures){
|
|
160
|
+
console.log('\n', report.target, measure);
|
|
161
|
+
const table = {};
|
|
162
|
+
for (const { feed, data } of feeds){
|
|
163
|
+
table[feed] = Object.fromEntries(Object.entries(data).map(([key, report])=>[
|
|
164
|
+
key,
|
|
165
|
+
report.toString()
|
|
166
|
+
]));
|
|
167
|
+
}
|
|
168
|
+
console.table(table);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
export const printJSONReports = (reports, padding)=>{
|
|
173
|
+
const output = {};
|
|
174
|
+
for (const report of reports){
|
|
175
|
+
for (const { measure, feeds } of report.measures){
|
|
176
|
+
const row = {};
|
|
177
|
+
for (const { feed, data } of feeds){
|
|
178
|
+
row[feed] = Object.fromEntries(Object.entries(data).map(([key, report])=>[
|
|
179
|
+
key,
|
|
180
|
+
report.toString()
|
|
181
|
+
]));
|
|
182
|
+
}
|
|
183
|
+
output[`${report.target} ${measure}`] = row;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
console.log(JSON.stringify(output, null, padding));
|
|
187
|
+
};
|
|
2
188
|
|
|
3
189
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './benchmark.js'\nimport { Benchmark as _Benchmark } from './benchmark.js';\n\ndeclare global {\n const benchmark: typeof _Benchmark[\"create\"];\n}\n"],"names":[],"mappings":"AAAA,cAAc,iBAAgB"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { cpus } from 'node:os';\nimport { createExecutor, ExecutorOptions, ExecutorReport } from './executor.js';\nimport { MaybePromise, StepFn, SetupFn, TeardownFn, FeedFn, ReportType, ReportTypeList, DEFAULT_CYCLES } from './types.js';\n\ndeclare global {\n const benchmark: typeof Benchmark.create;\n}\n\nexport const DEFAULT_WORKERS = cpus().length;\n\nexport const AsyncFunction = (async () => {}).constructor;\n\nexport interface TargetReport<R extends ReportTypeList> {\n target: string;\n measures: MeasureReport<R>[];\n}\n\nexport interface MeasureReport<R extends ReportTypeList> {\n measure: string;\n feeds: FeedReport<R>[];\n}\n\nexport interface FeedReport<R extends ReportTypeList> {\n feed: string;\n data: ExecutorReport<R>;\n}\n\nexport const DEFAULT_REPORT_TYPES = ['ops'] as const;\nexport type DefaultReportTypes = (typeof DEFAULT_REPORT_TYPES)[number];\n\nexport class MeasureContext<TContext, TInput> {\n public pre?: StepFn<TContext, TInput>;\n public post?: StepFn<TContext, TInput>;\n\n constructor(\n public title: string,\n public run: StepFn<TContext, TInput>,\n ) {}\n}\n\nexport class Measure<TContext, TInput> {\n #ctx: MeasureContext<TContext, TInput>;\n\n constructor(ctx: MeasureContext<TContext, TInput>) {\n this.#ctx = ctx;\n }\n\n pre(fn: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n this.#ctx.pre = fn;\n return this;\n }\n post(fn: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n this.#ctx.post = fn;\n return this;\n }\n}\n\nexport class TargetContext<TContext, TInput> {\n public teardown?: TeardownFn<TContext>;\n public measures: MeasureContext<TContext, TInput>[] = [];\n\n constructor(\n readonly title: string,\n readonly setup?: SetupFn<MaybePromise<TContext>>,\n ) {}\n}\n\nexport class Target<TContext, TInput> {\n #ctx: TargetContext<TContext, TInput>;\n\n constructor(ctx: TargetContext<TContext, TInput>) {\n this.#ctx = ctx;\n }\n teardown(fn: TeardownFn<TContext>): Target<TContext, TInput> {\n this.#ctx.teardown = fn;\n\n return this;\n }\n measure(title: string, run: StepFn<TContext, TInput>): Measure<TContext, TInput> {\n const measure = new MeasureContext(title, run);\n this.#ctx.measures.push(measure);\n\n return new Measure(measure);\n }\n}\n\nexport class FeedContext<TInput> {\n constructor(\n readonly title: string,\n readonly fn?: FeedFn<TInput>,\n ) {}\n}\n\nexport class Benchmark<TInput> {\n #targets: TargetContext<unknown, TInput>[] = [];\n #feeds: FeedContext<TInput>[] = [];\n #executed = false;\n\n static create(title: string): Benchmark<void>;\n static create<I>(title: string, fn: FeedFn<I>): Benchmark<I>;\n static create<I>(title: string, fn?: FeedFn<I> | undefined): Benchmark<I> {\n if (fn) {\n return new Benchmark(title, fn);\n } else {\n return new Benchmark(title);\n }\n }\n\n constructor(title: string);\n constructor(title: string, fn: FeedFn<TInput>);\n constructor(title: string, fn?: FeedFn<TInput> | undefined) {\n if (fn) {\n this.feed(title, fn);\n } else {\n this.feed(title);\n }\n }\n\n feed(title: string): Benchmark<TInput | void>;\n feed<I>(title: string, fn: FeedFn<I>): Benchmark<TInput | I>;\n feed<I>(title: string, fn?: FeedFn<I> | undefined): Benchmark<TInput | I> {\n const self = this as Benchmark<TInput | I>;\n self.#feeds.push(fn ? new FeedContext(title, fn) : new FeedContext(title));\n\n return self;\n }\n\n target<TContext>(title: string): Target<void, TInput>;\n target<TContext>(title: string, setup: SetupFn<Awaited<TContext>>): Target<TContext, TInput>;\n target<TContext>(title: string, setup?: SetupFn<Awaited<TContext>> | undefined): Target<TContext, TInput> {\n const target = new TargetContext<TContext, TInput>(title, setup);\n this.#targets.push(target as TargetContext<unknown, TInput>);\n\n return new Target<TContext, TInput>(target);\n }\n\n async execute<R extends readonly ReportType[] = typeof DEFAULT_REPORT_TYPES>({\n workers = DEFAULT_WORKERS,\n warmupCycles = 20,\n maxCycles = DEFAULT_CYCLES,\n minCycles = 50,\n absThreshold = 1_000,\n relThreshold = 0.02,\n reportTypes = DEFAULT_REPORT_TYPES as unknown as R,\n }: ExecutorOptions<R>): Promise<TargetReport<R>[]> {\n if (this.#executed) {\n throw new Error(\"Benchmark is executed and can't be reused\");\n }\n this.#executed = true;\n\n const executor = createExecutor<unknown, TInput, R>({\n workers,\n warmupCycles,\n maxCycles,\n minCycles,\n absThreshold,\n relThreshold,\n reportTypes,\n });\n\n const reports: TargetReport<R>[] = [];\n for (const target of this.#targets) {\n const targetReport: TargetReport<R> = { target: target.title, measures: [] };\n for (const measure of target.measures) {\n const measureReport: MeasureReport<R> = { measure: measure.title, feeds: [] };\n for (const feed of this.#feeds) {\n const data = await feed.fn?.();\n executor\n .push<ExecutorReport<R>>({\n setup: target.setup,\n teardown: target.teardown,\n pre: measure.pre,\n run: measure.run,\n post: measure.post,\n data,\n })\n .then((data) => {\n measureReport.feeds.push({\n feed: feed.title,\n data,\n });\n });\n }\n targetReport.measures.push(measureReport);\n }\n reports.push(targetReport);\n }\n await executor.drain();\n executor.kill();\n\n return reports;\n }\n}\n\nexport const printSimpleReports = <R extends ReportTypeList>(reports: TargetReport<R>[]) => {\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n console.group('\\n', report.target, measure);\n for (const { feed, data } of feeds) {\n const output = Object.entries(data)\n .map(([key, report]) => `${key}: ${report.toString()}`)\n .join('; ');\n console.log(feed, output);\n }\n console.groupEnd();\n }\n }\n};\n\nexport const printTableReports = <R extends ReportTypeList>(reports: TargetReport<R>[]) => {\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n console.log('\\n', report.target, measure);\n const table: Record<string, unknown> = {};\n for (const { feed, data } of feeds) {\n table[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));\n }\n console.table(table);\n }\n }\n};\n\nexport const printJSONReports = <R extends ReportTypeList>(reports: TargetReport<R>[], padding?: number) => {\n const output = {} as Record<string, Record<string, Record<string, string>>>;\n for (const report of reports) {\n for (const { measure, feeds } of report.measures) {\n const row = {} as Record<string, Record<string, string>>;\n for (const { feed, data } of feeds) {\n row[feed] = Object.fromEntries(Object.entries(data).map(([key, report]) => [key, report.toString()]));\n }\n output[`${report.target} ${measure}`] = row;\n }\n }\n console.log(JSON.stringify(output, null, padding));\n};\n"],"names":["cpus","createExecutor","DEFAULT_CYCLES","DEFAULT_WORKERS","length","AsyncFunction","constructor","DEFAULT_REPORT_TYPES","MeasureContext","pre","post","title","run","Measure","ctx","fn","TargetContext","teardown","measures","setup","Target","measure","push","FeedContext","Benchmark","create","feed","self","target","execute","workers","warmupCycles","maxCycles","minCycles","absThreshold","relThreshold","reportTypes","Error","executor","reports","targetReport","measureReport","feeds","data","then","drain","kill","printSimpleReports","report","console","group","output","Object","entries","map","key","toString","join","log","groupEnd","printTableReports","table","fromEntries","printJSONReports","padding","row","JSON","stringify"],"mappings":"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"}
|
package/build/queue.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/queue.ts"],"sourcesContent":["export const createQueue = <T>(
|
|
1
|
+
{"version":3,"sources":["../src/queue.ts"],"sourcesContent":["export const createQueue = <T>(worker: (task: T) => Promise<void>, concurency: number = 1) => {\n const queue = new Set<T>();\n const processing = new Map<number, Promise<void>>();\n const iterator = queue[Symbol.iterator]();\n\n let next: () => void;\n let counter = 0;\n\n queueMicrotask(async () => {\n while (true) {\n if (concurency > 0 && processing.size === concurency) {\n await Promise.race(processing.values());\n }\n if (queue.size === 0) {\n const { promise, resolve } = Promise.withResolvers<void>();\n next = resolve;\n await promise;\n }\n const result = iterator.next();\n if (result.done) {\n break;\n }\n const id = counter++;\n const task = Promise.resolve(worker(result.value))\n .catch(() => {})\n .finally(() => {\n processing.delete(id);\n });\n processing.set(id, task);\n }\n });\n\n return {\n push: async (input: T) => {\n queue.add(input);\n\n if (queue.size === 0) {\n next?.();\n }\n },\n };\n};\n"],"names":["createQueue","worker","concurency","queue","Set","processing","Map","iterator","Symbol","next","counter","queueMicrotask","size","Promise","race","values","promise","resolve","withResolvers","result","done","id","task","value","catch","finally","delete","set","push","input","add"],"mappings":";;;;+BAAaA;;;eAAAA;;;AAAN,MAAMA,cAAc,CAAIC,QAAoCC,aAAqB,CAAC;IACvF,MAAMC,QAAQ,IAAIC;IAClB,MAAMC,aAAa,IAAIC;IACvB,MAAMC,WAAWJ,KAAK,CAACK,OAAOD,QAAQ,CAAC;IAEvC,IAAIE;IACJ,IAAIC,UAAU;IAEdC,eAAe;QACb,MAAO,KAAM;YACX,IAAIT,aAAa,KAAKG,WAAWO,IAAI,KAAKV,YAAY;gBACpD,MAAMW,QAAQC,IAAI,CAACT,WAAWU,MAAM;YACtC;YACA,IAAIZ,MAAMS,IAAI,KAAK,GAAG;gBACpB,MAAM,EAAEI,OAAO,EAAEC,OAAO,EAAE,GAAGJ,QAAQK,aAAa;gBAClDT,OAAOQ;gBACP,MAAMD;YACR;YACA,MAAMG,SAASZ,SAASE,IAAI;YAC5B,IAAIU,OAAOC,IAAI,EAAE;gBACf;YACF;YACA,MAAMC,KAAKX;YACX,MAAMY,OAAOT,QAAQI,OAAO,CAAChB,OAAOkB,OAAOI,KAAK,GAC7CC,KAAK,CAAC,KAAO,GACbC,OAAO,CAAC;gBACPpB,WAAWqB,MAAM,CAACL;YACpB;YACFhB,WAAWsB,GAAG,CAACN,IAAIC;QACrB;IACF;IAEA,OAAO;QACLM,MAAM,OAAOC;YACX1B,MAAM2B,GAAG,CAACD;YAEV,IAAI1B,MAAMS,IAAI,KAAK,GAAG;gBACpBH;YACF;QACF;IACF;AACF"}
|
package/build/queue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/queue.ts"],"sourcesContent":["export const createQueue = <T>(
|
|
1
|
+
{"version":3,"sources":["../src/queue.ts"],"sourcesContent":["export const createQueue = <T>(worker: (task: T) => Promise<void>, concurency: number = 1) => {\n const queue = new Set<T>();\n const processing = new Map<number, Promise<void>>();\n const iterator = queue[Symbol.iterator]();\n\n let next: () => void;\n let counter = 0;\n\n queueMicrotask(async () => {\n while (true) {\n if (concurency > 0 && processing.size === concurency) {\n await Promise.race(processing.values());\n }\n if (queue.size === 0) {\n const { promise, resolve } = Promise.withResolvers<void>();\n next = resolve;\n await promise;\n }\n const result = iterator.next();\n if (result.done) {\n break;\n }\n const id = counter++;\n const task = Promise.resolve(worker(result.value))\n .catch(() => {})\n .finally(() => {\n processing.delete(id);\n });\n processing.set(id, task);\n }\n });\n\n return {\n push: async (input: T) => {\n queue.add(input);\n\n if (queue.size === 0) {\n next?.();\n }\n },\n };\n};\n"],"names":["createQueue","worker","concurency","queue","Set","processing","Map","iterator","Symbol","next","counter","queueMicrotask","size","Promise","race","values","promise","resolve","withResolvers","result","done","id","task","value","catch","finally","delete","set","push","input","add"],"mappings":"AAAA,OAAO,MAAMA,cAAc,CAAIC,QAAoCC,aAAqB,CAAC;IACvF,MAAMC,QAAQ,IAAIC;IAClB,MAAMC,aAAa,IAAIC;IACvB,MAAMC,WAAWJ,KAAK,CAACK,OAAOD,QAAQ,CAAC;IAEvC,IAAIE;IACJ,IAAIC,UAAU;IAEdC,eAAe;QACb,MAAO,KAAM;YACX,IAAIT,aAAa,KAAKG,WAAWO,IAAI,KAAKV,YAAY;gBACpD,MAAMW,QAAQC,IAAI,CAACT,WAAWU,MAAM;YACtC;YACA,IAAIZ,MAAMS,IAAI,KAAK,GAAG;gBACpB,MAAM,EAAEI,OAAO,EAAEC,OAAO,EAAE,GAAGJ,QAAQK,aAAa;gBAClDT,OAAOQ;gBACP,MAAMD;YACR;YACA,MAAMG,SAASZ,SAASE,IAAI;YAC5B,IAAIU,OAAOC,IAAI,EAAE;gBACf;YACF;YACA,MAAMC,KAAKX;YACX,MAAMY,OAAOT,QAAQI,OAAO,CAAChB,OAAOkB,OAAOI,KAAK,GAC7CC,KAAK,CAAC,KAAO,GACbC,OAAO,CAAC;gBACPpB,WAAWqB,MAAM,CAACL;YACpB;YACFhB,WAAWsB,GAAG,CAACN,IAAIC;QACrB;IACF;IAEA,OAAO;QACLM,MAAM,OAAOC;YACX1B,MAAM2B,GAAG,CAACD;YAEV,IAAI1B,MAAMS,IAAI,KAAK,GAAG;gBACpBH;YACF;QACF;IACF;AACF,EAAE"}
|
package/build/reporter.cjs
CHANGED
package/build/reporter.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { div, max, divs } from './utils.js';\nimport { ReportType } from './types.js';\n\nconst units = [\n { unit: 'ns', factor: 1 },\n { unit: 'µs', factor: 1e3 },\n { unit: 'ms', factor: 1e6 },\n { unit: 's', factor: 1e9 },\n { unit: 'm', factor: 60 * 1e9 },\n { unit: 'h', factor: 3600 * 1e9 },\n] as const;\n\nfunction smartFixed(n: number): string {\n return n.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n useGrouping:
|
|
1
|
+
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { div, max, divs } from './utils.js';\nimport { ReportType } from './types.js';\n\nconst units = [\n { unit: 'ns', factor: 1 },\n { unit: 'µs', factor: 1e3 },\n { unit: 'ms', factor: 1e6 },\n { unit: 's', factor: 1e9 },\n { unit: 'm', factor: 60 * 1e9 },\n { unit: 'h', factor: 3600 * 1e9 },\n] as const;\n\nfunction smartFixed(n: number): string {\n return n.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n useGrouping: true,\n });\n}\nexport class Report {\n constructor(\n public readonly type: ReportType,\n public readonly value: bigint,\n public readonly uncertainty: number = 0,\n public readonly scale: bigint = 1n,\n ) {}\n valueOf() {\n return Number(div(this.value, this.scale));\n }\n toString() {\n const uncertainty = this.uncertainty ? ` ± ${smartFixed(this.uncertainty)}%` : '';\n\n const value = this.valueOf();\n if (this.type === 'ops') {\n return `${smartFixed(value)} ops/s${uncertainty}`;\n }\n let display = value;\n let unit = 'ns';\n\n for (const { unit: u, factor } of units) {\n const candidate = value / factor;\n if (candidate < 1000) {\n display = candidate;\n unit = u;\n break;\n }\n }\n return `${smartFixed(display)} ${unit}${uncertainty}`;\n }\n}\n\nexport const createReport = (durations: BigUint64Array, type: ReportType): Report => {\n const n = durations.length;\n if (n === 0) {\n return new Report(type, 0n);\n }\n switch (type) {\n case 'min': {\n return new Report(type, durations[0]);\n }\n case 'max': {\n return new Report(type, durations[n - 1]);\n }\n case 'median': {\n const mid = Math.floor(n / 2);\n const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];\n return new Report(type, med);\n }\n\n case 'mode': {\n const freq = new Map<bigint, bigint>();\n let maxCount = 0n;\n let modeVal = durations[0];\n for (const d of durations) {\n const count = (freq.get(d) || 0n) + 1n;\n freq.set(d, count);\n if (count > maxCount) {\n maxCount = count;\n modeVal = d;\n }\n }\n let lower = modeVal;\n let upper = modeVal;\n const firstIdx = durations.indexOf(modeVal);\n const lastIdx = durations.lastIndexOf(modeVal);\n if (firstIdx > 0) lower = durations[firstIdx - 1];\n if (lastIdx < n - 1) upper = durations[lastIdx + 1];\n const gap = max(modeVal - lower, upper - modeVal);\n const uncertainty = modeVal > 0 ? Number(((gap / 2n) * 100n) / modeVal) : 0;\n return new Report(type, modeVal, uncertainty);\n }\n\n case 'ops': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const avgNs = sum / BigInt(n);\n const nsPerSec = 1_000_000_000n;\n const raw = Number(nsPerSec) / Number(avgNs);\n const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;\n\n const exp = raw > 100 ? 0 : 2 + extra;\n\n const scale = 10n ** BigInt(exp);\n\n const value = avgNs > 0n ? (nsPerSec * scale) / avgNs : 0n;\n const deviation = durations[n - 1] - durations[0];\n const uncertainty = avgNs > 0 ? Number(div(deviation * scale, 2n * avgNs)) : 0;\n return new Report(type, value, uncertainty, scale);\n }\n case 'mean': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const value = divs(sum, BigInt(n), 1n);\n return new Report(type, value);\n }\n\n default: {\n const p = Number(type.slice(1));\n if (p === 0) {\n return new Report(type, durations[0]);\n }\n if (p === 100) {\n return new Report(type, durations[n - 1]);\n }\n const idx = Math.ceil((p / 100) * n) - 1;\n const value = durations[Math.min(Math.max(idx, 0), n - 1)];\n const prev = idx > 0 ? durations[idx - 1] : value;\n const next = idx < n - 1 ? durations[idx + 1] : value;\n const gap = max(value - prev, next - value);\n const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;\n\n return new Report(type, value, uncertainty);\n }\n }\n};\n"],"names":["Report","createReport","units","unit","factor","smartFixed","n","toLocaleString","undefined","minimumFractionDigits","maximumFractionDigits","useGrouping","constructor","type","value","uncertainty","scale","valueOf","Number","div","toString","display","u","candidate","durations","length","mid","Math","floor","med","freq","Map","maxCount","modeVal","d","count","get","set","lower","upper","firstIdx","indexOf","lastIdx","lastIndexOf","gap","max","sum","duration","avgNs","BigInt","nsPerSec","raw","extra","ceil","log10","exp","deviation","divs","p","slice","idx","min","prev","next"],"mappings":";;;;;;;;;;;IAmBaA,MAAM;eAANA;;IAgCAC,YAAY;eAAZA;;;0BAnDkB;AAG/B,MAAMC,QAAQ;IACZ;QAAEC,MAAM;QAAMC,QAAQ;IAAE;IACxB;QAAED,MAAM;QAAMC,QAAQ;IAAI;IAC1B;QAAED,MAAM;QAAMC,QAAQ;IAAI;IAC1B;QAAED,MAAM;QAAKC,QAAQ;IAAI;IACzB;QAAED,MAAM;QAAKC,QAAQ,KAAK;IAAI;IAC9B;QAAED,MAAM;QAAKC,QAAQ,OAAO;IAAI;CACjC;AAED,SAASC,WAAWC,CAAS;IAC3B,OAAOA,EAAEC,cAAc,CAACC,WAAW;QACjCC,uBAAuB;QACvBC,uBAAuB;QACvBC,aAAa;IACf;AACF;AACO,MAAMX;;;;;IACXY,YACE,AAAgBC,IAAgB,EAChC,AAAgBC,KAAa,EAC7B,AAAgBC,cAAsB,CAAC,EACvC,AAAgBC,QAAgB,EAAE,CAClC;aAJgBH,OAAAA;aACAC,QAAAA;aACAC,cAAAA;aACAC,QAAAA;IACf;IACHC,UAAU;QACR,OAAOC,OAAOC,IAAAA,aAAG,EAAC,IAAI,CAACL,KAAK,EAAE,IAAI,CAACE,KAAK;IAC1C;IACAI,WAAW;QACT,MAAML,cAAc,IAAI,CAACA,WAAW,GAAG,CAAC,GAAG,EAAEV,WAAW,IAAI,CAACU,WAAW,EAAE,CAAC,CAAC,GAAG;QAE/E,MAAMD,QAAQ,IAAI,CAACG,OAAO;QAC1B,IAAI,IAAI,CAACJ,IAAI,KAAK,OAAO;YACvB,OAAO,GAAGR,WAAWS,OAAO,MAAM,EAAEC,aAAa;QACnD;QACA,IAAIM,UAAUP;QACd,IAAIX,OAAO;QAEX,KAAK,MAAM,EAAEA,MAAMmB,CAAC,EAAElB,MAAM,EAAE,IAAIF,MAAO;YACvC,MAAMqB,YAAYT,QAAQV;YAC1B,IAAImB,YAAY,MAAM;gBACpBF,UAAUE;gBACVpB,OAAOmB;gBACP;YACF;QACF;QACA,OAAO,GAAGjB,WAAWgB,SAAS,CAAC,EAAElB,OAAOY,aAAa;IACvD;AACF;AAEO,MAAMd,eAAe,CAACuB,WAA2BX;IACtD,MAAMP,IAAIkB,UAAUC,MAAM;IAC1B,IAAInB,MAAM,GAAG;QACX,OAAO,IAAIN,OAAOa,MAAM,EAAE;IAC5B;IACA,OAAQA;QACN,KAAK;YAAO;gBACV,OAAO,IAAIb,OAAOa,MAAMW,SAAS,CAAC,EAAE;YACtC;QACA,KAAK;YAAO;gBACV,OAAO,IAAIxB,OAAOa,MAAMW,SAAS,CAAClB,IAAI,EAAE;YAC1C;QACA,KAAK;YAAU;gBACb,MAAMoB,MAAMC,KAAKC,KAAK,CAACtB,IAAI;gBAC3B,MAAMuB,MAAMvB,IAAI,MAAM,IAAI,AAACkB,CAAAA,SAAS,CAACE,MAAM,EAAE,GAAGF,SAAS,CAACE,IAAI,AAAD,IAAK,EAAE,GAAGF,SAAS,CAACE,IAAI;gBACrF,OAAO,IAAI1B,OAAOa,MAAMgB;YAC1B;QAEA,KAAK;YAAQ;gBACX,MAAMC,OAAO,IAAIC;gBACjB,IAAIC,WAAW,EAAE;gBACjB,IAAIC,UAAUT,SAAS,CAAC,EAAE;gBAC1B,KAAK,MAAMU,KAAKV,UAAW;oBACzB,MAAMW,QAAQ,AAACL,CAAAA,KAAKM,GAAG,CAACF,MAAM,EAAE,AAAD,IAAK,EAAE;oBACtCJ,KAAKO,GAAG,CAACH,GAAGC;oBACZ,IAAIA,QAAQH,UAAU;wBACpBA,WAAWG;wBACXF,UAAUC;oBACZ;gBACF;gBACA,IAAII,QAAQL;gBACZ,IAAIM,QAAQN;gBACZ,MAAMO,WAAWhB,UAAUiB,OAAO,CAACR;gBACnC,MAAMS,UAAUlB,UAAUmB,WAAW,CAACV;gBACtC,IAAIO,WAAW,GAAGF,QAAQd,SAAS,CAACgB,WAAW,EAAE;gBACjD,IAAIE,UAAUpC,IAAI,GAAGiC,QAAQf,SAAS,CAACkB,UAAU,EAAE;gBACnD,MAAME,MAAMC,IAAAA,aAAG,EAACZ,UAAUK,OAAOC,QAAQN;gBACzC,MAAMlB,cAAckB,UAAU,IAAIf,OAAO,AAAE0B,MAAM,EAAE,GAAI,IAAI,GAAIX,WAAW;gBAC1E,OAAO,IAAIjC,OAAOa,MAAMoB,SAASlB;YACnC;QAEA,KAAK;YAAO;gBACV,IAAI+B,MAAM,EAAE;gBACZ,KAAK,MAAMC,YAAYvB,UAAW;oBAChCsB,OAAOC;gBACT;gBACA,MAAMC,QAAQF,MAAMG,OAAO3C;gBAC3B,MAAM4C,WAAW,cAAc;gBAC/B,MAAMC,MAAMjC,OAAOgC,YAAYhC,OAAO8B;gBACtC,MAAMI,QAAQD,MAAM,IAAIxB,KAAK0B,IAAI,CAAC,CAAC1B,KAAK2B,KAAK,CAACH,QAAQ;gBAEtD,MAAMI,MAAMJ,MAAM,MAAM,IAAI,IAAIC;gBAEhC,MAAMpC,QAAQ,GAAG,IAAIiC,OAAOM;gBAE5B,MAAMzC,QAAQkC,QAAQ,EAAE,GAAG,AAACE,WAAWlC,QAASgC,QAAQ,EAAE;gBAC1D,MAAMQ,YAAYhC,SAAS,CAAClB,IAAI,EAAE,GAAGkB,SAAS,CAAC,EAAE;gBACjD,MAAMT,cAAciC,QAAQ,IAAI9B,OAAOC,IAAAA,aAAG,EAACqC,YAAYxC,OAAO,EAAE,GAAGgC,UAAU;gBAC7E,OAAO,IAAIhD,OAAOa,MAAMC,OAAOC,aAAaC;YAC9C;QACA,KAAK;YAAQ;gBACX,IAAI8B,MAAM,EAAE;gBACZ,KAAK,MAAMC,YAAYvB,UAAW;oBAChCsB,OAAOC;gBACT;gBACA,MAAMjC,QAAQ2C,IAAAA,cAAI,EAACX,KAAKG,OAAO3C,IAAI,EAAE;gBACrC,OAAO,IAAIN,OAAOa,MAAMC;YAC1B;QAEA;YAAS;gBACP,MAAM4C,IAAIxC,OAAOL,KAAK8C,KAAK,CAAC;gBAC5B,IAAID,MAAM,GAAG;oBACX,OAAO,IAAI1D,OAAOa,MAAMW,SAAS,CAAC,EAAE;gBACtC;gBACA,IAAIkC,MAAM,KAAK;oBACb,OAAO,IAAI1D,OAAOa,MAAMW,SAAS,CAAClB,IAAI,EAAE;gBAC1C;gBACA,MAAMsD,MAAMjC,KAAK0B,IAAI,CAAC,AAACK,IAAI,MAAOpD,KAAK;gBACvC,MAAMQ,QAAQU,SAAS,CAACG,KAAKkC,GAAG,CAAClC,KAAKkB,GAAG,CAACe,KAAK,IAAItD,IAAI,GAAG;gBAC1D,MAAMwD,OAAOF,MAAM,IAAIpC,SAAS,CAACoC,MAAM,EAAE,GAAG9C;gBAC5C,MAAMiD,OAAOH,MAAMtD,IAAI,IAAIkB,SAAS,CAACoC,MAAM,EAAE,GAAG9C;gBAChD,MAAM8B,MAAMC,IAAAA,aAAG,EAAC/B,QAAQgD,MAAMC,OAAOjD;gBACrC,MAAMC,cAAcD,QAAQ,IAAII,OAAOC,IAAAA,aAAG,EAACsC,IAAAA,cAAI,EAACb,KAAK,EAAE,EAAE,OAAO,GAAG9B,UAAU,MAAM;gBAEnF,OAAO,IAAId,OAAOa,MAAMC,OAAOC;YACjC;IACF;AACF"}
|
package/build/reporter.js
CHANGED
package/build/reporter.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { div, max, divs } from './utils.js';\nimport { ReportType } from './types.js';\n\nconst units = [\n { unit: 'ns', factor: 1 },\n { unit: 'µs', factor: 1e3 },\n { unit: 'ms', factor: 1e6 },\n { unit: 's', factor: 1e9 },\n { unit: 'm', factor: 60 * 1e9 },\n { unit: 'h', factor: 3600 * 1e9 },\n] as const;\n\nfunction smartFixed(n: number): string {\n return n.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n useGrouping:
|
|
1
|
+
{"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { div, max, divs } from './utils.js';\nimport { ReportType } from './types.js';\n\nconst units = [\n { unit: 'ns', factor: 1 },\n { unit: 'µs', factor: 1e3 },\n { unit: 'ms', factor: 1e6 },\n { unit: 's', factor: 1e9 },\n { unit: 'm', factor: 60 * 1e9 },\n { unit: 'h', factor: 3600 * 1e9 },\n] as const;\n\nfunction smartFixed(n: number): string {\n return n.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n useGrouping: true,\n });\n}\nexport class Report {\n constructor(\n public readonly type: ReportType,\n public readonly value: bigint,\n public readonly uncertainty: number = 0,\n public readonly scale: bigint = 1n,\n ) {}\n valueOf() {\n return Number(div(this.value, this.scale));\n }\n toString() {\n const uncertainty = this.uncertainty ? ` ± ${smartFixed(this.uncertainty)}%` : '';\n\n const value = this.valueOf();\n if (this.type === 'ops') {\n return `${smartFixed(value)} ops/s${uncertainty}`;\n }\n let display = value;\n let unit = 'ns';\n\n for (const { unit: u, factor } of units) {\n const candidate = value / factor;\n if (candidate < 1000) {\n display = candidate;\n unit = u;\n break;\n }\n }\n return `${smartFixed(display)} ${unit}${uncertainty}`;\n }\n}\n\nexport const createReport = (durations: BigUint64Array, type: ReportType): Report => {\n const n = durations.length;\n if (n === 0) {\n return new Report(type, 0n);\n }\n switch (type) {\n case 'min': {\n return new Report(type, durations[0]);\n }\n case 'max': {\n return new Report(type, durations[n - 1]);\n }\n case 'median': {\n const mid = Math.floor(n / 2);\n const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];\n return new Report(type, med);\n }\n\n case 'mode': {\n const freq = new Map<bigint, bigint>();\n let maxCount = 0n;\n let modeVal = durations[0];\n for (const d of durations) {\n const count = (freq.get(d) || 0n) + 1n;\n freq.set(d, count);\n if (count > maxCount) {\n maxCount = count;\n modeVal = d;\n }\n }\n let lower = modeVal;\n let upper = modeVal;\n const firstIdx = durations.indexOf(modeVal);\n const lastIdx = durations.lastIndexOf(modeVal);\n if (firstIdx > 0) lower = durations[firstIdx - 1];\n if (lastIdx < n - 1) upper = durations[lastIdx + 1];\n const gap = max(modeVal - lower, upper - modeVal);\n const uncertainty = modeVal > 0 ? Number(((gap / 2n) * 100n) / modeVal) : 0;\n return new Report(type, modeVal, uncertainty);\n }\n\n case 'ops': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const avgNs = sum / BigInt(n);\n const nsPerSec = 1_000_000_000n;\n const raw = Number(nsPerSec) / Number(avgNs);\n const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;\n\n const exp = raw > 100 ? 0 : 2 + extra;\n\n const scale = 10n ** BigInt(exp);\n\n const value = avgNs > 0n ? (nsPerSec * scale) / avgNs : 0n;\n const deviation = durations[n - 1] - durations[0];\n const uncertainty = avgNs > 0 ? Number(div(deviation * scale, 2n * avgNs)) : 0;\n return new Report(type, value, uncertainty, scale);\n }\n case 'mean': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const value = divs(sum, BigInt(n), 1n);\n return new Report(type, value);\n }\n\n default: {\n const p = Number(type.slice(1));\n if (p === 0) {\n return new Report(type, durations[0]);\n }\n if (p === 100) {\n return new Report(type, durations[n - 1]);\n }\n const idx = Math.ceil((p / 100) * n) - 1;\n const value = durations[Math.min(Math.max(idx, 0), n - 1)];\n const prev = idx > 0 ? durations[idx - 1] : value;\n const next = idx < n - 1 ? durations[idx + 1] : value;\n const gap = max(value - prev, next - value);\n const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;\n\n return new Report(type, value, uncertainty);\n }\n }\n};\n"],"names":["div","max","divs","units","unit","factor","smartFixed","n","toLocaleString","undefined","minimumFractionDigits","maximumFractionDigits","useGrouping","Report","constructor","type","value","uncertainty","scale","valueOf","Number","toString","display","u","candidate","createReport","durations","length","mid","Math","floor","med","freq","Map","maxCount","modeVal","d","count","get","set","lower","upper","firstIdx","indexOf","lastIdx","lastIndexOf","gap","sum","duration","avgNs","BigInt","nsPerSec","raw","extra","ceil","log10","exp","deviation","p","slice","idx","min","prev","next"],"mappings":"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"}
|
package/build/runner.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { Options, Control } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst runSync = (run: Function) => {\n return (...args: unknown[]) => {\n const start = process.hrtime.bigint();\n run(...args);\n return process.hrtime.bigint() - start;\n }
|
|
1
|
+
{"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { Options, Control } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst runSync = (run: Function) => {\n return (...args: unknown[]) => {\n const start = process.hrtime.bigint();\n run(...args);\n return process.hrtime.bigint() - start;\n };\n};\n\nconst runAsync = (run: Function) => {\n return async (...args: unknown[]) => {\n const start = process.hrtime.bigint();\n await run(...args);\n return process.hrtime.bigint() - start;\n };\n};\n\nexport const benchmark = async <TContext, TInput>({\n setup,\n teardown,\n pre,\n run: runRaw,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n\n durationsSAB,\n controlSAB,\n}: Required<Options<TContext, TInput>>) => {\n const durations = new BigUint64Array(durationsSAB);\n const control = new Int32Array(controlSAB);\n\n control[Control.INDEX] = 0;\n control[Control.PROGRESS] = 0;\n control[Control.COMPLETE] = 255;\n\n const context = (await setup?.()) as TContext;\n const maxCycles = durations.length;\n\n try {\n await pre?.(context, data!);\n const result = runRaw(context, data!);\n await post?.(context, data!);\n const run = result instanceof Promise ? runAsync(runRaw) : runSync(runRaw);\n const start = Date.now();\n while (Date.now() - start < 1_000) {\n Math.sqrt(Math.random());\n }\n for (let i = 0; i < warmupCycles; i++) {\n await pre?.(context, data!);\n await run(context, data);\n await post?.(context, data!);\n }\n\n let i = 0;\n let mean = 0n;\n let m2 = 0n;\n\n while (true) {\n if (i >= maxCycles) break;\n\n await pre?.(context, data!);\n const duration = await run(context, data);\n await post?.(context, data!);\n\n durations[i++] = duration;\n const delta = duration - mean;\n mean += delta / BigInt(i);\n m2 += delta * (duration - mean);\n\n const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;\n control[Control.PROGRESS] = progress;\n\n if (i >= minCycles) {\n const variance = Number(m2) / (i - 1);\n const stddev = Math.sqrt(variance);\n if (stddev <= Number(absThreshold)) {\n break;\n }\n\n const meanNum = Number(mean);\n const cov = stddev / (meanNum || 1);\n if (cov <= relThreshold) {\n break;\n }\n }\n }\n\n control[Control.INDEX] = i;\n control[Control.COMPLETE] = 0;\n } catch (e) {\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n control[Control.COMPLETE] = 1;\n } finally {\n try {\n await teardown?.(context);\n } catch (e) {\n control[Control.COMPLETE] = 2;\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n }\n }\n\n return control[Control.COMPLETE];\n};\n"],"names":["benchmark","COMPLETE_VALUE","runSync","run","args","start","process","hrtime","bigint","runAsync","setup","teardown","pre","runRaw","post","data","warmupCycles","minCycles","absThreshold","relThreshold","durationsSAB","controlSAB","durations","BigUint64Array","control","Int32Array","Control","INDEX","PROGRESS","COMPLETE","context","maxCycles","length","result","Promise","Date","now","Math","sqrt","random","i","mean","m2","duration","delta","BigInt","progress","max","variance","Number","stddev","meanNum","cov","e","console","error","stack"],"mappings":"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"}
|
package/build/runner.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { Options, Control } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst runSync = (run: Function) => {\n return (...args: unknown[]) => {\n const start = process.hrtime.bigint();\n run(...args);\n return process.hrtime.bigint() - start;\n }
|
|
1
|
+
{"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { Options, Control } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst runSync = (run: Function) => {\n return (...args: unknown[]) => {\n const start = process.hrtime.bigint();\n run(...args);\n return process.hrtime.bigint() - start;\n };\n};\n\nconst runAsync = (run: Function) => {\n return async (...args: unknown[]) => {\n const start = process.hrtime.bigint();\n await run(...args);\n return process.hrtime.bigint() - start;\n };\n};\n\nexport const benchmark = async <TContext, TInput>({\n setup,\n teardown,\n pre,\n run: runRaw,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n\n durationsSAB,\n controlSAB,\n}: Required<Options<TContext, TInput>>) => {\n const durations = new BigUint64Array(durationsSAB);\n const control = new Int32Array(controlSAB);\n\n control[Control.INDEX] = 0;\n control[Control.PROGRESS] = 0;\n control[Control.COMPLETE] = 255;\n\n const context = (await setup?.()) as TContext;\n const maxCycles = durations.length;\n\n try {\n await pre?.(context, data!);\n const result = runRaw(context, data!);\n await post?.(context, data!);\n const run = result instanceof Promise ? runAsync(runRaw) : runSync(runRaw);\n const start = Date.now();\n while (Date.now() - start < 1_000) {\n Math.sqrt(Math.random());\n }\n for (let i = 0; i < warmupCycles; i++) {\n await pre?.(context, data!);\n await run(context, data);\n await post?.(context, data!);\n }\n\n let i = 0;\n let mean = 0n;\n let m2 = 0n;\n\n while (true) {\n if (i >= maxCycles) break;\n\n await pre?.(context, data!);\n const duration = await run(context, data);\n await post?.(context, data!);\n\n durations[i++] = duration;\n const delta = duration - mean;\n mean += delta / BigInt(i);\n m2 += delta * (duration - mean);\n\n const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;\n control[Control.PROGRESS] = progress;\n\n if (i >= minCycles) {\n const variance = Number(m2) / (i - 1);\n const stddev = Math.sqrt(variance);\n if (stddev <= Number(absThreshold)) {\n break;\n }\n\n const meanNum = Number(mean);\n const cov = stddev / (meanNum || 1);\n if (cov <= relThreshold) {\n break;\n }\n }\n }\n\n control[Control.INDEX] = i;\n control[Control.COMPLETE] = 0;\n } catch (e) {\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n control[Control.COMPLETE] = 1;\n } finally {\n try {\n await teardown?.(context);\n } catch (e) {\n control[Control.COMPLETE] = 2;\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n }\n }\n\n return control[Control.COMPLETE];\n};\n"],"names":["Control","COMPLETE_VALUE","runSync","run","args","start","process","hrtime","bigint","runAsync","benchmark","setup","teardown","pre","runRaw","post","data","warmupCycles","minCycles","absThreshold","relThreshold","durationsSAB","controlSAB","durations","BigUint64Array","control","Int32Array","INDEX","PROGRESS","COMPLETE","context","maxCycles","length","result","Promise","Date","now","Math","sqrt","random","i","mean","m2","duration","delta","BigInt","progress","max","variance","Number","stddev","meanNum","cov","e","console","error","stack"],"mappings":"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"}
|
package/build/types.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface SetupFn<TContext> {\n (): MaybePromise<TContext>;\n}\n\nexport interface TeardownFn<TContext> {\n (ctx: TContext): MaybePromise<void>;\n}\n\
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface SetupFn<TContext> {\n (): MaybePromise<TContext>;\n}\n\nexport interface TeardownFn<TContext> {\n (ctx: TContext): MaybePromise<void>;\n}\n\nexport interface StepFn<TContext, TInput> {\n (ctx: TContext, input: TInput): MaybePromise<void>;\n}\n\nexport interface FeedFn<TInput> {\n (): MaybePromise<TInput>;\n}\n\ntype _Sequence<To extends number, R extends unknown[]> = R['length'] extends To ? R[number] : _Sequence<To, [R['length'], ...R]>;\nexport type Sequence<To extends number> = number extends To ? number : _Sequence<To, []>;\nexport type Between<From extends number, To extends number> = Exclude<Sequence<To>, Sequence<From>>;\n\nexport type ReportType = 'ops' | 'min' | 'max' | 'mean' | 'median' | 'mode' | `p${Between<1, 100>}`;\nexport type ReportTypeList = readonly ReportType[];\nexport const REPORT_TYPES: ReportTypeList = Array.from({ length: 99 }, (_, idx) => `p${idx + 1}` as ReportType).concat(['ops', 'mean', 'min', 'max', 'median', 'mode']);\n\nexport interface ReportOptions<R extends ReportTypeList> {\n reportTypes: R;\n}\n\nexport interface BenchmarkOptions {\n warmupCycles?: number;\n minCycles?: number;\n absThreshold?: number; // ns\n relThreshold?: number; // %\n}\n\nexport interface RunOptions<TContext, TInput> {\n setup?: SetupFn<TContext>;\n teardown?: TeardownFn<TContext>;\n pre?: StepFn<TContext, TInput>;\n run: StepFn<TContext, TInput>;\n post?: StepFn<TContext, TInput>;\n data?: TInput;\n}\n\nexport interface WorkerOptions extends Required<BenchmarkOptions> {\n setupCode?: string;\n teardownCode?: string;\n preCode?: string;\n runCode: string;\n postCode?: string;\n data?: unknown;\n\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport interface Options<TContext, TInput> extends RunOptions<TContext, TInput>, BenchmarkOptions {\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport enum Control {\n INDEX,\n PROGRESS,\n COMPLETE,\n}\n\nexport const CONTROL_SLOTS = Object.values(Control).length / 2;\nexport const DEFAULT_CYCLES = 1_000;\nexport const Z95 = 1.96;\n"],"names":["CONTROL_SLOTS","Control","DEFAULT_CYCLES","REPORT_TYPES","Z95","Array","from","length","_","idx","concat","Object","values"],"mappings":";;;;;;;;;;;IAqEaA,aAAa;eAAbA;;IANDC,OAAO;eAAPA;;IAOCC,cAAc;eAAdA;;IA9CAC,YAAY;eAAZA;;IA+CAC,GAAG;eAAHA;;;AA/CN,MAAMD,eAA+BE,MAAMC,IAAI,CAAC;IAAEC,QAAQ;AAAG,GAAG,CAACC,GAAGC,MAAQ,CAAC,CAAC,EAAEA,MAAM,GAAG,EAAgBC,MAAM,CAAC;IAAC;IAAO;IAAQ;IAAO;IAAO;IAAU;CAAO;AAuC/J,IAAA,AAAKT,iCAAAA;;;;WAAAA;;AAML,MAAMD,gBAAgBW,OAAOC,MAAM,CAACX,SAASM,MAAM,GAAG;AACtD,MAAML,iBAAiB;AACvB,MAAME,MAAM"}
|
package/build/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface SetupFn<TContext> {\n (): MaybePromise<TContext>;\n}\n\nexport interface TeardownFn<TContext> {\n (ctx: TContext): MaybePromise<void>;\n}\n\
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface SetupFn<TContext> {\n (): MaybePromise<TContext>;\n}\n\nexport interface TeardownFn<TContext> {\n (ctx: TContext): MaybePromise<void>;\n}\n\nexport interface StepFn<TContext, TInput> {\n (ctx: TContext, input: TInput): MaybePromise<void>;\n}\n\nexport interface FeedFn<TInput> {\n (): MaybePromise<TInput>;\n}\n\ntype _Sequence<To extends number, R extends unknown[]> = R['length'] extends To ? R[number] : _Sequence<To, [R['length'], ...R]>;\nexport type Sequence<To extends number> = number extends To ? number : _Sequence<To, []>;\nexport type Between<From extends number, To extends number> = Exclude<Sequence<To>, Sequence<From>>;\n\nexport type ReportType = 'ops' | 'min' | 'max' | 'mean' | 'median' | 'mode' | `p${Between<1, 100>}`;\nexport type ReportTypeList = readonly ReportType[];\nexport const REPORT_TYPES: ReportTypeList = Array.from({ length: 99 }, (_, idx) => `p${idx + 1}` as ReportType).concat(['ops', 'mean', 'min', 'max', 'median', 'mode']);\n\nexport interface ReportOptions<R extends ReportTypeList> {\n reportTypes: R;\n}\n\nexport interface BenchmarkOptions {\n warmupCycles?: number;\n minCycles?: number;\n absThreshold?: number; // ns\n relThreshold?: number; // %\n}\n\nexport interface RunOptions<TContext, TInput> {\n setup?: SetupFn<TContext>;\n teardown?: TeardownFn<TContext>;\n pre?: StepFn<TContext, TInput>;\n run: StepFn<TContext, TInput>;\n post?: StepFn<TContext, TInput>;\n data?: TInput;\n}\n\nexport interface WorkerOptions extends Required<BenchmarkOptions> {\n setupCode?: string;\n teardownCode?: string;\n preCode?: string;\n runCode: string;\n postCode?: string;\n data?: unknown;\n\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport interface Options<TContext, TInput> extends RunOptions<TContext, TInput>, BenchmarkOptions {\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport enum Control {\n INDEX,\n PROGRESS,\n COMPLETE,\n}\n\nexport const CONTROL_SLOTS = Object.values(Control).length / 2;\nexport const DEFAULT_CYCLES = 1_000;\nexport const Z95 = 1.96;\n"],"names":["REPORT_TYPES","Array","from","length","_","idx","concat","Control","CONTROL_SLOTS","Object","values","DEFAULT_CYCLES","Z95"],"mappings":"AAwBA,OAAO,MAAMA,eAA+BC,MAAMC,IAAI,CAAC;IAAEC,QAAQ;AAAG,GAAG,CAACC,GAAGC,MAAQ,CAAC,CAAC,EAAEA,MAAM,GAAG,EAAgBC,MAAM,CAAC;IAAC;IAAO;IAAQ;IAAO;IAAO;IAAU;CAAO,EAAE;AAuCxK,OAAO,IAAA,AAAKC,iCAAAA;;;;WAAAA;MAIX;AAED,OAAO,MAAMC,gBAAgBC,OAAOC,MAAM,CAACH,SAASJ,MAAM,GAAG,EAAE;AAC/D,OAAO,MAAMQ,iBAAiB,MAAM;AACpC,OAAO,MAAMC,MAAM,KAAK"}
|
package/build/utils.cjs
CHANGED
|
@@ -59,7 +59,7 @@ const divMod = (a, b)=>{
|
|
|
59
59
|
};
|
|
60
60
|
};
|
|
61
61
|
function div(a, b, decimals = 2) {
|
|
62
|
-
if (b === 0n) throw new RangeError(
|
|
62
|
+
if (b === 0n) throw new RangeError('Division by zero');
|
|
63
63
|
const scale = 10n ** BigInt(decimals);
|
|
64
64
|
const scaled = a * scale / b;
|
|
65
65
|
const intPart = scaled / scale;
|
|
@@ -67,7 +67,7 @@ function div(a, b, decimals = 2) {
|
|
|
67
67
|
return `${intPart}.${fracPart.toString().padStart(decimals, '0')}`;
|
|
68
68
|
}
|
|
69
69
|
function divs(a, b, scale) {
|
|
70
|
-
if (b === 0n) throw new RangeError(
|
|
70
|
+
if (b === 0n) throw new RangeError('Division by zero');
|
|
71
71
|
return a * scale / b;
|
|
72
72
|
}
|
|
73
73
|
class ScaledBigInt {
|
package/build/utils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["export const abs = (value: bigint) => {\n if (value < 0n) {\n return -value;\n }\n return value;\n}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["export const abs = (value: bigint) => {\n if (value < 0n) {\n return -value;\n }\n return value;\n};\nexport const cmp = (a: bigint | number, b: bigint | number): number => {\n if (a > b) {\n return 1;\n }\n if (a < b) {\n return -1;\n }\n return 0;\n};\n\nexport const max = (a: bigint, b: bigint) => {\n if (a > b) {\n return a;\n }\n return b;\n};\n\nexport const divMod = (a: bigint, b: bigint) => {\n return { quotient: a / b, remainder: a % b };\n};\n\nexport function div(a: bigint, b: bigint, decimals: number = 2): string {\n if (b === 0n) throw new RangeError('Division by zero');\n const scale = 10n ** BigInt(decimals);\n const scaled = (a * scale) / b;\n const intPart = scaled / scale;\n const fracPart = scaled % scale;\n return `${intPart}.${fracPart.toString().padStart(decimals, '0')}`;\n}\n\nexport function divs(a: bigint, b: bigint, scale: bigint): bigint {\n if (b === 0n) throw new RangeError('Division by zero');\n return (a * scale) / b;\n}\n\nexport class ScaledBigInt {\n constructor(\n public value: bigint,\n public scale: bigint,\n ) {}\n add(value: bigint) {\n this.value += value * this.scale;\n }\n sub(value: bigint) {\n this.value -= value * this.scale;\n }\n div(value: bigint) {\n this.value /= value;\n }\n mul(value: bigint) {\n this.value *= value;\n }\n unscale() {\n return this.value / this.value;\n }\n number() {\n return Number(div(this.value, this.scale));\n }\n}\n"],"names":["ScaledBigInt","abs","cmp","div","divMod","divs","max","value","a","b","quotient","remainder","decimals","RangeError","scale","BigInt","scaled","intPart","fracPart","toString","padStart","constructor","add","sub","mul","unscale","number","Number"],"mappings":";;;;;;;;;;;IAyCaA,YAAY;eAAZA;;IAzCAC,GAAG;eAAHA;;IAMAC,GAAG;eAAHA;;IAqBGC,GAAG;eAAHA;;IAJHC,MAAM;eAANA;;IAaGC,IAAI;eAAJA;;IApBHC,GAAG;eAAHA;;;AAhBN,MAAML,MAAM,CAACM;IAClB,IAAIA,QAAQ,EAAE,EAAE;QACd,OAAO,CAACA;IACV;IACA,OAAOA;AACT;AACO,MAAML,MAAM,CAACM,GAAoBC;IACtC,IAAID,IAAIC,GAAG;QACT,OAAO;IACT;IACA,IAAID,IAAIC,GAAG;QACT,OAAO,CAAC;IACV;IACA,OAAO;AACT;AAEO,MAAMH,MAAM,CAACE,GAAWC;IAC7B,IAAID,IAAIC,GAAG;QACT,OAAOD;IACT;IACA,OAAOC;AACT;AAEO,MAAML,SAAS,CAACI,GAAWC;IAChC,OAAO;QAAEC,UAAUF,IAAIC;QAAGE,WAAWH,IAAIC;IAAE;AAC7C;AAEO,SAASN,IAAIK,CAAS,EAAEC,CAAS,EAAEG,WAAmB,CAAC;IAC5D,IAAIH,MAAM,EAAE,EAAE,MAAM,IAAII,WAAW;IACnC,MAAMC,QAAQ,GAAG,IAAIC,OAAOH;IAC5B,MAAMI,SAAS,AAACR,IAAIM,QAASL;IAC7B,MAAMQ,UAAUD,SAASF;IACzB,MAAMI,WAAWF,SAASF;IAC1B,OAAO,GAAGG,QAAQ,CAAC,EAAEC,SAASC,QAAQ,GAAGC,QAAQ,CAACR,UAAU,MAAM;AACpE;AAEO,SAASP,KAAKG,CAAS,EAAEC,CAAS,EAAEK,KAAa;IACtD,IAAIL,MAAM,EAAE,EAAE,MAAM,IAAII,WAAW;IACnC,OAAO,AAACL,IAAIM,QAASL;AACvB;AAEO,MAAMT;;;IACXqB,YACE,AAAOd,KAAa,EACpB,AAAOO,KAAa,CACpB;aAFOP,QAAAA;aACAO,QAAAA;IACN;IACHQ,IAAIf,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACO,KAAK;IAClC;IACAS,IAAIhB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACO,KAAK;IAClC;IACAX,IAAII,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAiB,IAAIjB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAkB,UAAU;QACR,OAAO,IAAI,CAAClB,KAAK,GAAG,IAAI,CAACA,KAAK;IAChC;IACAmB,SAAS;QACP,OAAOC,OAAOxB,IAAI,IAAI,CAACI,KAAK,EAAE,IAAI,CAACO,KAAK;IAC1C;AACF"}
|
package/build/utils.js
CHANGED
|
@@ -26,7 +26,7 @@ export const divMod = (a, b)=>{
|
|
|
26
26
|
};
|
|
27
27
|
};
|
|
28
28
|
export function div(a, b, decimals = 2) {
|
|
29
|
-
if (b === 0n) throw new RangeError(
|
|
29
|
+
if (b === 0n) throw new RangeError('Division by zero');
|
|
30
30
|
const scale = 10n ** BigInt(decimals);
|
|
31
31
|
const scaled = a * scale / b;
|
|
32
32
|
const intPart = scaled / scale;
|
|
@@ -34,7 +34,7 @@ export function div(a, b, decimals = 2) {
|
|
|
34
34
|
return `${intPart}.${fracPart.toString().padStart(decimals, '0')}`;
|
|
35
35
|
}
|
|
36
36
|
export function divs(a, b, scale) {
|
|
37
|
-
if (b === 0n) throw new RangeError(
|
|
37
|
+
if (b === 0n) throw new RangeError('Division by zero');
|
|
38
38
|
return a * scale / b;
|
|
39
39
|
}
|
|
40
40
|
export class ScaledBigInt {
|
package/build/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["export const abs = (value: bigint) => {\n if (value < 0n) {\n return -value;\n }\n return value;\n}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts"],"sourcesContent":["export const abs = (value: bigint) => {\n if (value < 0n) {\n return -value;\n }\n return value;\n};\nexport const cmp = (a: bigint | number, b: bigint | number): number => {\n if (a > b) {\n return 1;\n }\n if (a < b) {\n return -1;\n }\n return 0;\n};\n\nexport const max = (a: bigint, b: bigint) => {\n if (a > b) {\n return a;\n }\n return b;\n};\n\nexport const divMod = (a: bigint, b: bigint) => {\n return { quotient: a / b, remainder: a % b };\n};\n\nexport function div(a: bigint, b: bigint, decimals: number = 2): string {\n if (b === 0n) throw new RangeError('Division by zero');\n const scale = 10n ** BigInt(decimals);\n const scaled = (a * scale) / b;\n const intPart = scaled / scale;\n const fracPart = scaled % scale;\n return `${intPart}.${fracPart.toString().padStart(decimals, '0')}`;\n}\n\nexport function divs(a: bigint, b: bigint, scale: bigint): bigint {\n if (b === 0n) throw new RangeError('Division by zero');\n return (a * scale) / b;\n}\n\nexport class ScaledBigInt {\n constructor(\n public value: bigint,\n public scale: bigint,\n ) {}\n add(value: bigint) {\n this.value += value * this.scale;\n }\n sub(value: bigint) {\n this.value -= value * this.scale;\n }\n div(value: bigint) {\n this.value /= value;\n }\n mul(value: bigint) {\n this.value *= value;\n }\n unscale() {\n return this.value / this.value;\n }\n number() {\n return Number(div(this.value, this.scale));\n }\n}\n"],"names":["abs","value","cmp","a","b","max","divMod","quotient","remainder","div","decimals","RangeError","scale","BigInt","scaled","intPart","fracPart","toString","padStart","divs","ScaledBigInt","constructor","add","sub","mul","unscale","number","Number"],"mappings":"AAAA,OAAO,MAAMA,MAAM,CAACC;IAClB,IAAIA,QAAQ,EAAE,EAAE;QACd,OAAO,CAACA;IACV;IACA,OAAOA;AACT,EAAE;AACF,OAAO,MAAMC,MAAM,CAACC,GAAoBC;IACtC,IAAID,IAAIC,GAAG;QACT,OAAO;IACT;IACA,IAAID,IAAIC,GAAG;QACT,OAAO,CAAC;IACV;IACA,OAAO;AACT,EAAE;AAEF,OAAO,MAAMC,MAAM,CAACF,GAAWC;IAC7B,IAAID,IAAIC,GAAG;QACT,OAAOD;IACT;IACA,OAAOC;AACT,EAAE;AAEF,OAAO,MAAME,SAAS,CAACH,GAAWC;IAChC,OAAO;QAAEG,UAAUJ,IAAIC;QAAGI,WAAWL,IAAIC;IAAE;AAC7C,EAAE;AAEF,OAAO,SAASK,IAAIN,CAAS,EAAEC,CAAS,EAAEM,WAAmB,CAAC;IAC5D,IAAIN,MAAM,EAAE,EAAE,MAAM,IAAIO,WAAW;IACnC,MAAMC,QAAQ,GAAG,IAAIC,OAAOH;IAC5B,MAAMI,SAAS,AAACX,IAAIS,QAASR;IAC7B,MAAMW,UAAUD,SAASF;IACzB,MAAMI,WAAWF,SAASF;IAC1B,OAAO,GAAGG,QAAQ,CAAC,EAAEC,SAASC,QAAQ,GAAGC,QAAQ,CAACR,UAAU,MAAM;AACpE;AAEA,OAAO,SAASS,KAAKhB,CAAS,EAAEC,CAAS,EAAEQ,KAAa;IACtD,IAAIR,MAAM,EAAE,EAAE,MAAM,IAAIO,WAAW;IACnC,OAAO,AAACR,IAAIS,QAASR;AACvB;AAEA,OAAO,MAAMgB;;;IACXC,YACE,AAAOpB,KAAa,EACpB,AAAOW,KAAa,CACpB;aAFOX,QAAAA;aACAW,QAAAA;IACN;IACHU,IAAIrB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACW,KAAK;IAClC;IACAW,IAAItB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACW,KAAK;IAClC;IACAH,IAAIR,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAuB,IAAIvB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAwB,UAAU;QACR,OAAO,IAAI,CAACxB,KAAK,GAAG,IAAI,CAACA,KAAK;IAChC;IACAyB,SAAS;QACP,OAAOC,OAAOlB,IAAI,IAAI,CAACR,KAAK,EAAE,IAAI,CAACW,KAAK;IAC1C;AACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const suite = benchmark('1M array of strings', () => Array.from({ length: 1_000_000 }, (_, idx) => `${idx}`))
|
|
2
|
+
.feed('1M array of numbers', () => Array.from({ length: 1_000_000 }, (_, idx) => idx))
|
|
3
|
+
.feed('1M typed array', () => new Uint32Array(1_000_000).map((_, idx) => idx));
|
|
4
|
+
|
|
5
|
+
suite.target('for loop').measure('copy half', (_, input) => {
|
|
6
|
+
const n = input?.length ?? 0;
|
|
7
|
+
const mid = n / 2;
|
|
8
|
+
for (let i = 0; i < mid; i++) {
|
|
9
|
+
input[i + mid] = input[i];
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
suite.target('copyWithin').measure('copy half', (_, input) => {
|
|
14
|
+
const n = input?.length ?? 0;
|
|
15
|
+
const mid = n / 2;
|
|
16
|
+
input.copyWithin(mid, 0, mid);
|
|
17
|
+
});
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "overtake",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.3",
|
|
4
4
|
"description": "NodeJS performance benchmark",
|
|
5
5
|
"main": "build/index.js",
|
|
6
|
-
"types": "index.d.ts",
|
|
6
|
+
"types": "build/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"bin": {
|
|
9
9
|
"overtake": "bin/overtake.js"
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "rm -rf build && inop src build -i __tests__ -i *.tmp.ts && tsc --declaration --emitDeclarationOnly",
|
|
13
13
|
"start": "./bin/overtake.js",
|
|
14
|
-
"test": "jest --detectOpenHandles",
|
|
14
|
+
"test": "jest --detectOpenHandles --passWithNoTests",
|
|
15
15
|
"prepare": "husky"
|
|
16
16
|
},
|
|
17
17
|
"engines": {
|
package/src/cli.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createRequire, Module } from 'node:module';
|
|
2
|
-
import { SyntheticModule, createContext, SourceTextModule
|
|
2
|
+
import { SyntheticModule, createContext, SourceTextModule } from 'node:vm';
|
|
3
3
|
import { stat, readFile } from 'node:fs/promises';
|
|
4
4
|
import { parse, print } from '@swc/core';
|
|
5
5
|
import { Command, Option } from 'commander';
|
|
6
6
|
import { glob } from 'glob';
|
|
7
|
-
import { Benchmark, printTableReports, printJSONReports, printSimpleReports, DEFAULT_REPORT_TYPES, DEFAULT_WORKERS } from './
|
|
7
|
+
import { Benchmark, printTableReports, printJSONReports, printSimpleReports, DEFAULT_REPORT_TYPES, DEFAULT_WORKERS } from './index.js';
|
|
8
8
|
import { REPORT_TYPES } from './types.js';
|
|
9
9
|
|
|
10
10
|
const require = createRequire(import.meta.url);
|