overtake 1.1.2 → 1.1.4
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/build/gc-watcher.cjs +5 -6
- package/build/gc-watcher.cjs.map +1 -1
- package/build/gc-watcher.d.ts +0 -1
- package/build/gc-watcher.js +5 -6
- package/build/gc-watcher.js.map +1 -1
- package/build/reporter.cjs +14 -13
- package/build/reporter.cjs.map +1 -1
- package/build/reporter.js +14 -13
- package/build/reporter.js.map +1 -1
- package/build/runner.cjs +267 -66
- package/build/runner.cjs.map +1 -1
- package/build/runner.js +268 -67
- package/build/runner.js.map +1 -1
- package/build/types.cjs +4 -0
- package/build/types.cjs.map +1 -1
- package/build/types.d.ts +2 -1
- package/build/types.js +1 -0
- package/build/types.js.map +1 -1
- package/build/worker.cjs +1 -1
- package/build/worker.cjs.map +1 -1
- package/build/worker.js +1 -1
- package/build/worker.js.map +1 -1
- package/examples/accuracy.ts +30 -5
- package/package.json +1 -1
- package/src/gc-watcher.ts +5 -6
- package/src/reporter.ts +14 -14
- package/src/runner.ts +327 -74
- package/src/types.ts +2 -1
- package/src/worker.ts +1 -1
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\nexport interface StepFn<TContext, TInput> {\n (ctx: TContext, input: TInput): MaybePromise<
|
|
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<unknown>;\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 gcObserver?: boolean;\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 benchmarkUrl?: string;\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;\nexport const DURATION_SCALE = 1000n;\n"],"names":["REPORT_TYPES","Array","from","length","_","idx","concat","Control","CONTROL_SLOTS","Object","values","DEFAULT_CYCLES","Z95","DURATION_SCALE"],"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;AAyCxK,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;AACxB,OAAO,MAAMC,iBAAiB,KAAK,CAAC"}
|
package/build/worker.cjs
CHANGED
|
@@ -50,7 +50,7 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
50
50
|
return newObj;
|
|
51
51
|
}
|
|
52
52
|
const { benchmarkUrl, setupCode, teardownCode, preCode, runCode, postCode, data, warmupCycles, minCycles, absThreshold, relThreshold, gcObserver = true, durationsSAB, controlSAB } = _nodeworker_threads.workerData;
|
|
53
|
-
const serialize = (code)=>code ? code : '
|
|
53
|
+
const serialize = (code)=>code ? code : 'undefined';
|
|
54
54
|
const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : (0, _nodeurl.pathToFileURL)(process.cwd()).href;
|
|
55
55
|
const benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;
|
|
56
56
|
const requireFrom = (0, _nodemodule.createRequire)((0, _nodeurl.fileURLToPath)(new URL('benchmark.js', benchmarkDirUrl)));
|
package/build/worker.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule, createContext } from 'node:vm';\nimport { createRequire } from 'node:module';\nimport { isAbsolute } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { benchmark } from './runner.js';\nimport { WorkerOptions } from './types.js';\n\nconst {\n benchmarkUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = true,\n\n durationsSAB,\n controlSAB,\n}: WorkerOptions = workerData;\n\nconst serialize = (code?: string) => (code ? code : '
|
|
1
|
+
{"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule, createContext } from 'node:vm';\nimport { createRequire } from 'node:module';\nimport { isAbsolute } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { benchmark } from './runner.js';\nimport { WorkerOptions } from './types.js';\n\nconst {\n benchmarkUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = true,\n\n durationsSAB,\n controlSAB,\n}: WorkerOptions = workerData;\n\nconst serialize = (code?: string) => (code ? code : 'undefined');\n\nconst resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;\nconst benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;\nconst requireFrom = createRequire(fileURLToPath(new URL('benchmark.js', benchmarkDirUrl)));\n\nconst resolveSpecifier = (specifier: string) => {\n if (specifier.startsWith('file:')) {\n return specifier;\n }\n if (specifier.startsWith('./') || specifier.startsWith('../')) {\n return new URL(specifier, benchmarkDirUrl).href;\n }\n if (isAbsolute(specifier)) {\n return pathToFileURL(specifier).href;\n }\n return requireFrom.resolve(specifier);\n};\n\nconst source = `\nexport const setup = ${serialize(setupCode)};\nexport const teardown = ${serialize(teardownCode)};\nexport const pre = ${serialize(preCode)};\nexport const run = ${serialize(runCode)};\nexport const post = ${serialize(postCode)};\n `;\n\nconst context = createContext({ console, Buffer });\nconst imports = new Map<string, SyntheticModule>();\n\nconst createSyntheticModule = (moduleExports: unknown, exportNames: string[], identifier: string) => {\n const mod = new SyntheticModule(\n exportNames,\n () => {\n for (const name of exportNames) {\n if (name === 'default') {\n mod.setExport(name, moduleExports);\n continue;\n }\n mod.setExport(name, (moduleExports as Record<string, unknown>)[name]);\n }\n },\n { identifier, context },\n );\n return mod;\n};\n\nconst isCjsModule = (target: string) => target.endsWith('.cjs') || target.endsWith('.cts');\n\nconst toRequireTarget = (target: string) => (target.startsWith('file:') ? fileURLToPath(target) : target);\n\nconst loadModule = async (target: string) => {\n const cached = imports.get(target);\n if (cached) return cached;\n\n if (isCjsModule(target)) {\n const required = requireFrom(toRequireTarget(target));\n const exportNames = required && (typeof required === 'object' || typeof required === 'function') ? Object.keys(required) : [];\n if (!exportNames.includes('default')) {\n exportNames.push('default');\n }\n const mod = createSyntheticModule(required, exportNames, target);\n imports.set(target, mod);\n return mod;\n }\n\n const importedModule = await import(target);\n const exportNames = Object.keys(importedModule);\n const mod = createSyntheticModule(importedModule, exportNames, target);\n imports.set(target, mod);\n return mod;\n};\n\nconst loadDynamicModule = async (target: string) => {\n const mod = await loadModule(target);\n if (mod.status !== 'evaluated') {\n await mod.evaluate();\n }\n return mod;\n};\nconst mod = new SourceTextModule(source, {\n identifier: resolvedBenchmarkUrl,\n context,\n initializeImportMeta(meta) {\n meta.url = resolvedBenchmarkUrl;\n },\n importModuleDynamically(specifier) {\n const resolved = resolveSpecifier(specifier);\n return loadDynamicModule(resolved);\n },\n});\n\nawait mod.link(async (specifier) => loadModule(resolveSpecifier(specifier)));\n\nawait mod.evaluate();\nconst { setup, teardown, pre, run, post } = mod.namespace as any;\n\nif (!run) {\n throw new Error('Benchmark run function is required');\n}\n\nprocess.exitCode = await benchmark({\n setup,\n teardown,\n pre,\n run,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n\n durationsSAB,\n controlSAB,\n});\n"],"names":["benchmarkUrl","setupCode","teardownCode","preCode","runCode","postCode","data","warmupCycles","minCycles","absThreshold","relThreshold","gcObserver","durationsSAB","controlSAB","workerData","serialize","code","resolvedBenchmarkUrl","pathToFileURL","process","cwd","href","benchmarkDirUrl","URL","requireFrom","createRequire","fileURLToPath","resolveSpecifier","specifier","startsWith","isAbsolute","resolve","source","context","createContext","console","Buffer","imports","Map","createSyntheticModule","moduleExports","exportNames","identifier","mod","SyntheticModule","name","setExport","isCjsModule","target","endsWith","toRequireTarget","loadModule","cached","get","required","Object","keys","includes","push","set","importedModule","loadDynamicModule","status","evaluate","SourceTextModule","initializeImportMeta","meta","url","importModuleDynamically","resolved","link","setup","teardown","pre","run","post","namespace","Error","exitCode","benchmark"],"mappings":"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"}
|
package/build/worker.js
CHANGED
|
@@ -5,7 +5,7 @@ import { isAbsolute } from 'node:path';
|
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
6
|
import { benchmark } from "./runner.js";
|
|
7
7
|
const { benchmarkUrl, setupCode, teardownCode, preCode, runCode, postCode, data, warmupCycles, minCycles, absThreshold, relThreshold, gcObserver = true, durationsSAB, controlSAB } = workerData;
|
|
8
|
-
const serialize = (code)=>code ? code : '
|
|
8
|
+
const serialize = (code)=>code ? code : 'undefined';
|
|
9
9
|
const resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;
|
|
10
10
|
const benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;
|
|
11
11
|
const requireFrom = createRequire(fileURLToPath(new URL('benchmark.js', benchmarkDirUrl)));
|
package/build/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule, createContext } from 'node:vm';\nimport { createRequire } from 'node:module';\nimport { isAbsolute } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { benchmark } from './runner.js';\nimport { WorkerOptions } from './types.js';\n\nconst {\n benchmarkUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = true,\n\n durationsSAB,\n controlSAB,\n}: WorkerOptions = workerData;\n\nconst serialize = (code?: string) => (code ? code : '
|
|
1
|
+
{"version":3,"sources":["../src/worker.ts"],"sourcesContent":["import { workerData } from 'node:worker_threads';\nimport { SourceTextModule, SyntheticModule, createContext } from 'node:vm';\nimport { createRequire } from 'node:module';\nimport { isAbsolute } from 'node:path';\nimport { fileURLToPath, pathToFileURL } from 'node:url';\nimport { benchmark } from './runner.js';\nimport { WorkerOptions } from './types.js';\n\nconst {\n benchmarkUrl,\n setupCode,\n teardownCode,\n preCode,\n runCode,\n postCode,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = true,\n\n durationsSAB,\n controlSAB,\n}: WorkerOptions = workerData;\n\nconst serialize = (code?: string) => (code ? code : 'undefined');\n\nconst resolvedBenchmarkUrl = typeof benchmarkUrl === 'string' ? benchmarkUrl : pathToFileURL(process.cwd()).href;\nconst benchmarkDirUrl = new URL('.', resolvedBenchmarkUrl).href;\nconst requireFrom = createRequire(fileURLToPath(new URL('benchmark.js', benchmarkDirUrl)));\n\nconst resolveSpecifier = (specifier: string) => {\n if (specifier.startsWith('file:')) {\n return specifier;\n }\n if (specifier.startsWith('./') || specifier.startsWith('../')) {\n return new URL(specifier, benchmarkDirUrl).href;\n }\n if (isAbsolute(specifier)) {\n return pathToFileURL(specifier).href;\n }\n return requireFrom.resolve(specifier);\n};\n\nconst source = `\nexport const setup = ${serialize(setupCode)};\nexport const teardown = ${serialize(teardownCode)};\nexport const pre = ${serialize(preCode)};\nexport const run = ${serialize(runCode)};\nexport const post = ${serialize(postCode)};\n `;\n\nconst context = createContext({ console, Buffer });\nconst imports = new Map<string, SyntheticModule>();\n\nconst createSyntheticModule = (moduleExports: unknown, exportNames: string[], identifier: string) => {\n const mod = new SyntheticModule(\n exportNames,\n () => {\n for (const name of exportNames) {\n if (name === 'default') {\n mod.setExport(name, moduleExports);\n continue;\n }\n mod.setExport(name, (moduleExports as Record<string, unknown>)[name]);\n }\n },\n { identifier, context },\n );\n return mod;\n};\n\nconst isCjsModule = (target: string) => target.endsWith('.cjs') || target.endsWith('.cts');\n\nconst toRequireTarget = (target: string) => (target.startsWith('file:') ? fileURLToPath(target) : target);\n\nconst loadModule = async (target: string) => {\n const cached = imports.get(target);\n if (cached) return cached;\n\n if (isCjsModule(target)) {\n const required = requireFrom(toRequireTarget(target));\n const exportNames = required && (typeof required === 'object' || typeof required === 'function') ? Object.keys(required) : [];\n if (!exportNames.includes('default')) {\n exportNames.push('default');\n }\n const mod = createSyntheticModule(required, exportNames, target);\n imports.set(target, mod);\n return mod;\n }\n\n const importedModule = await import(target);\n const exportNames = Object.keys(importedModule);\n const mod = createSyntheticModule(importedModule, exportNames, target);\n imports.set(target, mod);\n return mod;\n};\n\nconst loadDynamicModule = async (target: string) => {\n const mod = await loadModule(target);\n if (mod.status !== 'evaluated') {\n await mod.evaluate();\n }\n return mod;\n};\nconst mod = new SourceTextModule(source, {\n identifier: resolvedBenchmarkUrl,\n context,\n initializeImportMeta(meta) {\n meta.url = resolvedBenchmarkUrl;\n },\n importModuleDynamically(specifier) {\n const resolved = resolveSpecifier(specifier);\n return loadDynamicModule(resolved);\n },\n});\n\nawait mod.link(async (specifier) => loadModule(resolveSpecifier(specifier)));\n\nawait mod.evaluate();\nconst { setup, teardown, pre, run, post } = mod.namespace as any;\n\nif (!run) {\n throw new Error('Benchmark run function is required');\n}\n\nprocess.exitCode = await benchmark({\n setup,\n teardown,\n pre,\n run,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver,\n\n durationsSAB,\n controlSAB,\n});\n"],"names":["workerData","SourceTextModule","SyntheticModule","createContext","createRequire","isAbsolute","fileURLToPath","pathToFileURL","benchmark","benchmarkUrl","setupCode","teardownCode","preCode","runCode","postCode","data","warmupCycles","minCycles","absThreshold","relThreshold","gcObserver","durationsSAB","controlSAB","serialize","code","resolvedBenchmarkUrl","process","cwd","href","benchmarkDirUrl","URL","requireFrom","resolveSpecifier","specifier","startsWith","resolve","source","context","console","Buffer","imports","Map","createSyntheticModule","moduleExports","exportNames","identifier","mod","name","setExport","isCjsModule","target","endsWith","toRequireTarget","loadModule","cached","get","required","Object","keys","includes","push","set","importedModule","loadDynamicModule","status","evaluate","initializeImportMeta","meta","url","importModuleDynamically","resolved","link","setup","teardown","pre","run","post","namespace","Error","exitCode"],"mappings":"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"}
|
package/examples/accuracy.ts
CHANGED
|
@@ -6,10 +6,11 @@ const baseline = benchmark('accuracy tuning feed', () => {
|
|
|
6
6
|
for (let i = 0; i < uints.length; i++) {
|
|
7
7
|
uints[i] = (i * 31) ^ 0x9e3779b1;
|
|
8
8
|
}
|
|
9
|
+
const tiny = Buffer.alloc(4_096, 3);
|
|
9
10
|
const src = Buffer.alloc(bytes, 7);
|
|
10
11
|
const dst = Buffer.allocUnsafe(bytes);
|
|
11
12
|
|
|
12
|
-
return { uints, src, dst };
|
|
13
|
+
return { uints, tiny, src, dst };
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
baseline
|
|
@@ -17,10 +18,10 @@ baseline
|
|
|
17
18
|
return { scratch: 0 };
|
|
18
19
|
})
|
|
19
20
|
.measure('sum uint32 array', (ctx, { uints }) => {
|
|
20
|
-
let acc = ctx.scratch;
|
|
21
|
+
let acc = ctx.scratch | 0;
|
|
21
22
|
for (let round = 0; round < 8; round++) {
|
|
22
23
|
for (let i = 0; i < uints.length; i++) {
|
|
23
|
-
acc
|
|
24
|
+
acc = (acc + uints[i]) | 0;
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
ctx.scratch = acc;
|
|
@@ -45,10 +46,34 @@ baseline
|
|
|
45
46
|
dst.fill(0);
|
|
46
47
|
});
|
|
47
48
|
|
|
48
|
-
baseline.target('steady loop baseline').measure('counter increment', () => {
|
|
49
|
+
baseline.target('steady loop baseline').measure('counter increment', (_, { uints }) => {
|
|
49
50
|
let x = 0;
|
|
50
51
|
for (let i = 0; i < 200_000; i++) {
|
|
51
|
-
x
|
|
52
|
+
x = (x + uints[i & (uints.length - 1)]) | 0;
|
|
53
|
+
}
|
|
54
|
+
return x;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const gcImpact = baseline.target('gc impact', () => {
|
|
58
|
+
const pool: Buffer[] = Array.from({ length: 512 }, () => Buffer.alloc(4_096));
|
|
59
|
+
return { pool };
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
gcImpact.measure('alloc churn', (_, { tiny }) => {
|
|
63
|
+
let x = 0;
|
|
64
|
+
for (let i = 0; i < 512; i++) {
|
|
65
|
+
const buf = Buffer.from(tiny);
|
|
66
|
+
x ^= buf[0];
|
|
67
|
+
}
|
|
68
|
+
return x;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
gcImpact.measure('pool reuse', (ctx, { tiny }) => {
|
|
72
|
+
let x = 0;
|
|
73
|
+
const { pool } = ctx;
|
|
74
|
+
for (let i = 0; i < pool.length; i++) {
|
|
75
|
+
pool[i].set(tiny);
|
|
76
|
+
x ^= pool[i][0];
|
|
52
77
|
}
|
|
53
78
|
return x;
|
|
54
79
|
});
|
package/package.json
CHANGED
package/src/gc-watcher.ts
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
export interface GCMarker {
|
|
2
2
|
ref: WeakRef<object>;
|
|
3
|
-
token: object;
|
|
4
3
|
}
|
|
5
4
|
|
|
6
5
|
export class GCWatcher {
|
|
7
6
|
#registry = new FinalizationRegistry(() => {});
|
|
8
7
|
|
|
9
8
|
start(): GCMarker {
|
|
10
|
-
const
|
|
11
|
-
const ref = new WeakRef(
|
|
12
|
-
this.#registry.register(
|
|
13
|
-
return { ref
|
|
9
|
+
const target = {};
|
|
10
|
+
const ref = new WeakRef(target);
|
|
11
|
+
this.#registry.register(target, null, ref);
|
|
12
|
+
return { ref };
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
seen(marker: GCMarker): boolean {
|
|
17
16
|
const collected = marker.ref.deref() === undefined;
|
|
18
17
|
if (!collected) {
|
|
19
|
-
this.#registry.unregister(marker.
|
|
18
|
+
this.#registry.unregister(marker.ref);
|
|
20
19
|
}
|
|
21
20
|
return collected;
|
|
22
21
|
}
|
package/src/reporter.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { div, max, divs } from './utils.js';
|
|
2
|
-
import { ReportType } from './types.js';
|
|
2
|
+
import { ReportType, DURATION_SCALE } from './types.js';
|
|
3
3
|
|
|
4
4
|
const units = [
|
|
5
5
|
{ unit: 'ns', factor: 1 },
|
|
@@ -56,15 +56,15 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
|
|
|
56
56
|
}
|
|
57
57
|
switch (type) {
|
|
58
58
|
case 'min': {
|
|
59
|
-
return new Report(type, durations[0]);
|
|
59
|
+
return new Report(type, durations[0], 0, DURATION_SCALE);
|
|
60
60
|
}
|
|
61
61
|
case 'max': {
|
|
62
|
-
return new Report(type, durations[n - 1]);
|
|
62
|
+
return new Report(type, durations[n - 1], 0, DURATION_SCALE);
|
|
63
63
|
}
|
|
64
64
|
case 'median': {
|
|
65
65
|
const mid = Math.floor(n / 2);
|
|
66
66
|
const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];
|
|
67
|
-
return new Report(type, med);
|
|
67
|
+
return new Report(type, med, 0, DURATION_SCALE);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
case 'mode': {
|
|
@@ -87,7 +87,7 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
|
|
|
87
87
|
if (lastIdx < n - 1) upper = durations[lastIdx + 1];
|
|
88
88
|
const gap = max(modeVal - lower, upper - modeVal);
|
|
89
89
|
const uncertainty = modeVal > 0 ? Number(((gap / 2n) * 100n) / modeVal) : 0;
|
|
90
|
-
return new Report(type, modeVal, uncertainty);
|
|
90
|
+
return new Report(type, modeVal, uncertainty, DURATION_SCALE);
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
case 'ops': {
|
|
@@ -95,18 +95,18 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
|
|
|
95
95
|
for (const duration of durations) {
|
|
96
96
|
sum += duration;
|
|
97
97
|
}
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const raw = Number(
|
|
98
|
+
const avgScaled = sum / BigInt(n);
|
|
99
|
+
const nsPerSecScaled = 1_000_000_000n * DURATION_SCALE;
|
|
100
|
+
const raw = Number(nsPerSecScaled) / Number(avgScaled);
|
|
101
101
|
const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;
|
|
102
102
|
|
|
103
103
|
const exp = raw > 100 ? 0 : 2 + extra;
|
|
104
104
|
|
|
105
105
|
const scale = 10n ** BigInt(exp);
|
|
106
106
|
|
|
107
|
-
const value =
|
|
107
|
+
const value = avgScaled > 0n ? (nsPerSecScaled * scale) / avgScaled : 0n;
|
|
108
108
|
const deviation = durations[n - 1] - durations[0];
|
|
109
|
-
const uncertainty =
|
|
109
|
+
const uncertainty = avgScaled > 0 ? Number(div(deviation * scale, 2n * avgScaled)) : 0;
|
|
110
110
|
return new Report(type, value, uncertainty, scale);
|
|
111
111
|
}
|
|
112
112
|
case 'mean': {
|
|
@@ -115,16 +115,16 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
|
|
|
115
115
|
sum += duration;
|
|
116
116
|
}
|
|
117
117
|
const value = divs(sum, BigInt(n), 1n);
|
|
118
|
-
return new Report(type, value);
|
|
118
|
+
return new Report(type, value, 0, DURATION_SCALE);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
default: {
|
|
122
122
|
const p = Number(type.slice(1));
|
|
123
123
|
if (p === 0) {
|
|
124
|
-
return new Report(type, durations[0]);
|
|
124
|
+
return new Report(type, durations[0], 0, DURATION_SCALE);
|
|
125
125
|
}
|
|
126
126
|
if (p === 100) {
|
|
127
|
-
return new Report(type, durations[n - 1]);
|
|
127
|
+
return new Report(type, durations[n - 1], 0, DURATION_SCALE);
|
|
128
128
|
}
|
|
129
129
|
const idx = Math.ceil((p / 100) * n) - 1;
|
|
130
130
|
const value = durations[Math.min(Math.max(idx, 0), n - 1)];
|
|
@@ -133,7 +133,7 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
|
|
|
133
133
|
const gap = max(value - prev, next - value);
|
|
134
134
|
const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;
|
|
135
135
|
|
|
136
|
-
return new Report(type, value, uncertainty);
|
|
136
|
+
return new Report(type, value, uncertainty, DURATION_SCALE);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
};
|