overtake 1.0.5 → 1.1.1

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.
Files changed (57) hide show
  1. package/README.md +25 -29
  2. package/build/cli.cjs +43 -33
  3. package/build/cli.cjs.map +1 -1
  4. package/build/cli.js +42 -32
  5. package/build/cli.js.map +1 -1
  6. package/build/executor.cjs +6 -3
  7. package/build/executor.cjs.map +1 -1
  8. package/build/executor.d.ts +3 -2
  9. package/build/executor.js +6 -3
  10. package/build/executor.js.map +1 -1
  11. package/build/gc-watcher.cjs +31 -0
  12. package/build/gc-watcher.cjs.map +1 -0
  13. package/build/gc-watcher.d.ts +9 -0
  14. package/build/gc-watcher.js +21 -0
  15. package/build/gc-watcher.js.map +1 -0
  16. package/build/index.cjs +9 -1
  17. package/build/index.cjs.map +1 -1
  18. package/build/index.d.ts +1 -1
  19. package/build/index.js +9 -1
  20. package/build/index.js.map +1 -1
  21. package/build/runner.cjs +229 -24
  22. package/build/runner.cjs.map +1 -1
  23. package/build/runner.d.ts +1 -1
  24. package/build/runner.js +229 -24
  25. package/build/runner.js.map +1 -1
  26. package/build/types.cjs.map +1 -1
  27. package/build/types.d.ts +4 -0
  28. package/build/types.js.map +1 -1
  29. package/build/utils.cjs +21 -0
  30. package/build/utils.cjs.map +1 -1
  31. package/build/utils.d.ts +1 -0
  32. package/build/utils.js +18 -0
  33. package/build/utils.js.map +1 -1
  34. package/build/worker.cjs +104 -14
  35. package/build/worker.cjs.map +1 -1
  36. package/build/worker.d.ts +1 -1
  37. package/build/worker.js +63 -8
  38. package/build/worker.js.map +1 -1
  39. package/examples/accuracy.ts +54 -0
  40. package/examples/custom-reports.ts +0 -1
  41. package/examples/imports.ts +3 -7
  42. package/examples/quick-start.ts +2 -0
  43. package/package.json +11 -10
  44. package/src/cli.ts +44 -31
  45. package/src/executor.ts +8 -2
  46. package/src/gc-watcher.ts +23 -0
  47. package/src/index.ts +11 -0
  48. package/src/runner.ts +269 -23
  49. package/src/types.ts +4 -0
  50. package/src/utils.ts +20 -0
  51. package/src/worker.ts +72 -9
  52. package/build/queue.cjs +0 -48
  53. package/build/queue.cjs.map +0 -1
  54. package/build/queue.d.ts +0 -3
  55. package/build/queue.js +0 -38
  56. package/build/queue.js.map +0 -1
  57. package/src/queue.ts +0 -42
@@ -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 };\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 global.gc?.();\n global.gc?.();\n\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 global.gc?.();\n global.gc?.();\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 global.gc?.();\n global.gc?.();\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","global","gc","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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"}
1
+ {"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { performance, PerformanceObserver } from 'node:perf_hooks';\nimport { Options, Control } from './types.js';\nimport { GCWatcher } from './gc-watcher.js';\nimport { StepFn, MaybePromise } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst hr = process.hrtime.bigint.bind(process.hrtime);\n\nconst runSync = (run: Function) => {\n return (...args: unknown[]) => {\n const start = hr();\n run(...args);\n return hr() - start;\n };\n};\n\nconst runAsync = (run: Function) => {\n return async (...args: unknown[]) => {\n const start = hr();\n await run(...args);\n return hr() - start;\n };\n};\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> => {\n return value !== null && (typeof value === 'object' || typeof value === 'function') && typeof (value as PromiseLike<unknown>).then === 'function';\n};\n\nconst TARGET_SAMPLE_NS = 1_000_000n; // aim for ~1ms per measured sample\nconst MAX_BATCH = 1_048_576;\nconst PROGRESS_STRIDE = 16;\nconst GC_STRIDE = 32;\nconst OUTLIER_MULTIPLIER = 4;\nconst OUTLIER_IQR_MULTIPLIER = 3;\nconst OUTLIER_WINDOW = 64;\n\ntype GCEvent = { start: number; end: number };\n\nconst collectSample = async <TContext, TInput>(\n batchSize: number,\n run: (ctx: TContext, data: TInput) => MaybePromise<bigint>,\n pre: StepFn<TContext, TInput> | undefined,\n post: StepFn<TContext, TInput> | undefined,\n context: TContext,\n data: TInput,\n) => {\n let sampleDuration = 0n;\n for (let b = 0; b < batchSize; b++) {\n await pre?.(context, data);\n sampleDuration += await run(context, data);\n await post?.(context, data);\n }\n return sampleDuration / BigInt(batchSize);\n};\n\nconst tuneParameters = async <TContext, TInput>({\n initialBatch,\n run,\n pre,\n post,\n context,\n data,\n minCycles,\n relThreshold,\n maxCycles,\n}: {\n initialBatch: number;\n run: (ctx: TContext, data: TInput) => MaybePromise<bigint>;\n pre?: StepFn<TContext, TInput>;\n post?: StepFn<TContext, TInput>;\n context: TContext;\n data: TInput;\n minCycles: number;\n relThreshold: number;\n maxCycles: number;\n}) => {\n let batchSize = initialBatch;\n let bestCv = Number.POSITIVE_INFINITY;\n let bestBatch = batchSize;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const samples: number[] = [];\n const sampleCount = Math.min(8, maxCycles);\n for (let s = 0; s < sampleCount; s++) {\n const duration = await collectSample(batchSize, run, pre, post, context, data);\n samples.push(Number(duration));\n }\n const mean = samples.reduce((acc, v) => acc + v, 0) / samples.length;\n const variance = samples.reduce((acc, v) => acc + (v - mean) * (v - mean), 0) / Math.max(1, samples.length - 1);\n const stddev = Math.sqrt(variance);\n const cv = mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n\n if (cv < bestCv) {\n bestCv = cv;\n bestBatch = batchSize;\n }\n\n if (cv <= relThreshold || batchSize >= MAX_BATCH) {\n break;\n }\n batchSize = Math.min(MAX_BATCH, batchSize * 2);\n }\n\n const tunedRel = bestCv < relThreshold ? Math.max(bestCv * 1.5, relThreshold * 0.5) : relThreshold;\n const tunedMin = Math.min(maxCycles, Math.max(minCycles, Math.ceil(minCycles * Math.max(1, bestCv / (relThreshold || 1e-6)))));\n\n return { batchSize: bestBatch, relThreshold: tunedRel, minCycles: tunedMin };\n};\n\nconst createGCTracker = () => {\n if (process.env.OVERTAKE_GC_OBSERVER !== '1') {\n return null;\n }\n if (typeof PerformanceObserver === 'undefined') {\n return null;\n }\n\n const events: GCEvent[] = [];\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n events.push({ start: entry.startTime, end: entry.startTime + entry.duration });\n }\n });\n\n try {\n observer.observe({ entryTypes: ['gc'] });\n } catch {\n return null;\n }\n\n const overlaps = (start: number, end: number) => {\n let noisy = false;\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i];\n if (event.end < start - 5_000) {\n events.splice(i, 1);\n continue;\n }\n if (event.start <= end && event.end >= start) {\n noisy = true;\n }\n }\n return noisy;\n };\n\n const dispose = () => observer.disconnect();\n\n return { overlaps, dispose };\n};\n\nconst pushWindow = (arr: number[], value: number, cap: number) => {\n if (arr.length === cap) {\n arr.shift();\n }\n arr.push(value);\n};\n\nconst medianAndIqr = (arr: number[]) => {\n if (arr.length === 0) return { median: 0, iqr: 0 };\n const sorted = [...arr].sort((a, b) => a - b);\n const mid = Math.floor(sorted.length / 2);\n const median = sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];\n const q1Idx = Math.floor(sorted.length * 0.25);\n const q3Idx = Math.floor(sorted.length * 0.75);\n const q1 = sorted[q1Idx];\n const q3 = sorted[q3Idx];\n return { median, iqr: q3 - q1 };\n};\n\nconst windowCv = (arr: number[]) => {\n if (arr.length < 2) return Number.POSITIVE_INFINITY;\n const mean = arr.reduce((a, v) => a + v, 0) / arr.length;\n const variance = arr.reduce((a, v) => a + (v - mean) * (v - mean), 0) / (arr.length - 1);\n const stddev = Math.sqrt(variance);\n return mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\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 gcObserver = false,\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 const gcWatcher = gcObserver ? new GCWatcher() : null;\n const gcTracker = gcObserver ? createGCTracker() : null;\n\n try {\n // classify sync/async and capture initial duration\n await pre?.(context, data!);\n const probeStart = hr();\n const probeResult = runRaw(context, data!);\n const isAsync = isThenable(probeResult);\n if (isAsync) {\n await probeResult;\n }\n const durationProbe = hr() - probeStart;\n await post?.(context, data!);\n\n const run = isAsync ? runAsync(runRaw) : runSync(runRaw);\n\n // choose batch size to amortize timer overhead\n const durationPerRun = durationProbe === 0n ? 1n : durationProbe;\n const suggestedBatch = Number(TARGET_SAMPLE_NS / durationPerRun);\n const initialBatchSize = Math.min(MAX_BATCH, Math.max(1, suggestedBatch));\n\n // auto-tune based on warmup samples\n const tuned = await tuneParameters({\n initialBatch: initialBatchSize,\n run,\n pre,\n post,\n context,\n data: data as TInput,\n minCycles,\n relThreshold,\n maxCycles,\n });\n let batchSize = tuned.batchSize;\n minCycles = tuned.minCycles;\n relThreshold = tuned.relThreshold;\n\n // warmup: run until requested cycles, adapt if unstable\n const warmupStart = Date.now();\n let warmupRemaining = warmupCycles;\n const warmupWindow: number[] = [];\n const warmupCap = Math.max(warmupCycles, Math.min(maxCycles, warmupCycles * 4 || 1000));\n\n while (Date.now() - warmupStart < 1_000 && warmupRemaining > 0) {\n const start = hr();\n await pre?.(context, data!);\n await run(context, data);\n await post?.(context, data!);\n pushWindow(warmupWindow, Number(hr() - start), warmupCap);\n warmupRemaining--;\n }\n let warmupDone = 0;\n while (warmupDone < warmupRemaining) {\n const start = hr();\n await pre?.(context, data!);\n await run(context, data);\n await post?.(context, data!);\n pushWindow(warmupWindow, Number(hr() - start), warmupCap);\n warmupDone++;\n if (global.gc && warmupDone % GC_STRIDE === 0) {\n global.gc();\n }\n }\n while (warmupWindow.length >= 8 && warmupWindow.length < warmupCap) {\n const cv = windowCv(warmupWindow);\n if (cv <= relThreshold * 2) {\n break;\n }\n const start = hr();\n await pre?.(context, data!);\n await run(context, data);\n await post?.(context, data!);\n pushWindow(warmupWindow, Number(hr() - start), warmupCap);\n }\n\n let i = 0;\n let mean = 0n;\n let m2 = 0n;\n const outlierWindow: number[] = [];\n\n while (true) {\n if (i >= maxCycles) break;\n\n const gcMarker = gcWatcher?.start();\n const sampleStart = performance.now();\n let sampleDuration = 0n;\n for (let b = 0; b < batchSize; b++) {\n await pre?.(context, data!);\n sampleDuration += await run(context, data);\n await post?.(context, data!);\n if (global.gc && (i + b) % GC_STRIDE === 0) {\n global.gc();\n }\n }\n\n // normalize by batch size\n sampleDuration /= BigInt(batchSize);\n\n const sampleEnd = performance.now();\n const gcNoise = (gcMarker ? gcWatcher!.seen(gcMarker) : false) || (gcTracker?.overlaps(sampleStart, sampleEnd) ?? false);\n if (gcNoise) {\n continue;\n }\n\n const durationNumber = Number(sampleDuration);\n pushWindow(outlierWindow, durationNumber, OUTLIER_WINDOW);\n const { median, iqr } = medianAndIqr(outlierWindow);\n const maxAllowed = median + OUTLIER_IQR_MULTIPLIER * iqr || Number.POSITIVE_INFINITY;\n if (outlierWindow.length >= 8 && durationNumber > maxAllowed) {\n continue;\n }\n\n const meanNumber = Number(mean);\n if (i >= 8 && meanNumber > 0 && durationNumber > OUTLIER_MULTIPLIER * meanNumber) {\n continue;\n }\n\n durations[i++] = sampleDuration;\n const delta = sampleDuration - mean;\n mean += delta / BigInt(i);\n m2 += delta * (sampleDuration - mean);\n\n const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;\n if (i % PROGRESS_STRIDE === 0) {\n control[Control.PROGRESS] = progress;\n }\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 gcTracker?.dispose?.();\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","hr","process","hrtime","bigint","bind","runSync","run","args","start","runAsync","isThenable","value","then","TARGET_SAMPLE_NS","MAX_BATCH","PROGRESS_STRIDE","GC_STRIDE","OUTLIER_MULTIPLIER","OUTLIER_IQR_MULTIPLIER","OUTLIER_WINDOW","collectSample","batchSize","pre","post","context","data","sampleDuration","b","BigInt","tuneParameters","initialBatch","minCycles","relThreshold","maxCycles","bestCv","Number","POSITIVE_INFINITY","bestBatch","attempt","samples","sampleCount","Math","min","s","duration","push","mean","reduce","acc","v","length","variance","max","stddev","sqrt","cv","tunedRel","tunedMin","ceil","createGCTracker","env","OVERTAKE_GC_OBSERVER","PerformanceObserver","events","observer","list","entry","getEntries","startTime","end","observe","entryTypes","overlaps","noisy","i","event","splice","dispose","disconnect","pushWindow","arr","cap","shift","medianAndIqr","median","iqr","sorted","sort","a","mid","floor","q1Idx","q3Idx","q1","q3","windowCv","setup","teardown","runRaw","warmupCycles","absThreshold","gcObserver","durationsSAB","controlSAB","durations","BigUint64Array","control","Int32Array","Control","INDEX","PROGRESS","COMPLETE","gcWatcher","GCWatcher","gcTracker","probeStart","probeResult","isAsync","durationProbe","durationPerRun","suggestedBatch","initialBatchSize","tuned","warmupStart","Date","now","warmupRemaining","warmupWindow","warmupCap","warmupDone","global","gc","m2","outlierWindow","gcMarker","sampleStart","performance","sampleEnd","gcNoise","seen","durationNumber","maxAllowed","meanNumber","delta","progress","meanNum","cov","e","console","error","stack"],"mappings":"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"}
package/build/runner.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  import { Options } from './types.js';
2
- export declare const benchmark: <TContext, TInput>({ setup, teardown, pre, run: runRaw, post, data, warmupCycles, minCycles, absThreshold, relThreshold, durationsSAB, controlSAB, }: Required<Options<TContext, TInput>>) => Promise<number>;
2
+ export declare const benchmark: <TContext, TInput>({ setup, teardown, pre, run: runRaw, post, data, warmupCycles, minCycles, absThreshold, relThreshold, gcObserver, durationsSAB, controlSAB, }: Required<Options<TContext, TInput>>) => Promise<number>;
package/build/runner.js CHANGED
@@ -1,20 +1,151 @@
1
+ import { performance, PerformanceObserver } from 'node:perf_hooks';
1
2
  import { Control } from "./types.js";
3
+ import { GCWatcher } from "./gc-watcher.js";
2
4
  const COMPLETE_VALUE = 100_00;
5
+ const hr = process.hrtime.bigint.bind(process.hrtime);
3
6
  const runSync = (run)=>{
4
7
  return (...args)=>{
5
- const start = process.hrtime.bigint();
8
+ const start = hr();
6
9
  run(...args);
7
- return process.hrtime.bigint() - start;
10
+ return hr() - start;
8
11
  };
9
12
  };
10
13
  const runAsync = (run)=>{
11
14
  return async (...args)=>{
12
- const start = process.hrtime.bigint();
15
+ const start = hr();
13
16
  await run(...args);
14
- return process.hrtime.bigint() - start;
17
+ return hr() - start;
15
18
  };
16
19
  };
17
- export const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data, warmupCycles, minCycles, absThreshold, relThreshold, durationsSAB, controlSAB })=>{
20
+ const isThenable = (value)=>{
21
+ return value !== null && (typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function';
22
+ };
23
+ const TARGET_SAMPLE_NS = 1_000_000n;
24
+ const MAX_BATCH = 1_048_576;
25
+ const PROGRESS_STRIDE = 16;
26
+ const GC_STRIDE = 32;
27
+ const OUTLIER_MULTIPLIER = 4;
28
+ const OUTLIER_IQR_MULTIPLIER = 3;
29
+ const OUTLIER_WINDOW = 64;
30
+ const collectSample = async (batchSize, run, pre, post, context, data)=>{
31
+ let sampleDuration = 0n;
32
+ for(let b = 0; b < batchSize; b++){
33
+ await pre?.(context, data);
34
+ sampleDuration += await run(context, data);
35
+ await post?.(context, data);
36
+ }
37
+ return sampleDuration / BigInt(batchSize);
38
+ };
39
+ const tuneParameters = async ({ initialBatch, run, pre, post, context, data, minCycles, relThreshold, maxCycles })=>{
40
+ let batchSize = initialBatch;
41
+ let bestCv = Number.POSITIVE_INFINITY;
42
+ let bestBatch = batchSize;
43
+ for(let attempt = 0; attempt < 3; attempt++){
44
+ const samples = [];
45
+ const sampleCount = Math.min(8, maxCycles);
46
+ for(let s = 0; s < sampleCount; s++){
47
+ const duration = await collectSample(batchSize, run, pre, post, context, data);
48
+ samples.push(Number(duration));
49
+ }
50
+ const mean = samples.reduce((acc, v)=>acc + v, 0) / samples.length;
51
+ const variance = samples.reduce((acc, v)=>acc + (v - mean) * (v - mean), 0) / Math.max(1, samples.length - 1);
52
+ const stddev = Math.sqrt(variance);
53
+ const cv = mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;
54
+ if (cv < bestCv) {
55
+ bestCv = cv;
56
+ bestBatch = batchSize;
57
+ }
58
+ if (cv <= relThreshold || batchSize >= MAX_BATCH) {
59
+ break;
60
+ }
61
+ batchSize = Math.min(MAX_BATCH, batchSize * 2);
62
+ }
63
+ const tunedRel = bestCv < relThreshold ? Math.max(bestCv * 1.5, relThreshold * 0.5) : relThreshold;
64
+ const tunedMin = Math.min(maxCycles, Math.max(minCycles, Math.ceil(minCycles * Math.max(1, bestCv / (relThreshold || 1e-6)))));
65
+ return {
66
+ batchSize: bestBatch,
67
+ relThreshold: tunedRel,
68
+ minCycles: tunedMin
69
+ };
70
+ };
71
+ const createGCTracker = ()=>{
72
+ if (process.env.OVERTAKE_GC_OBSERVER !== '1') {
73
+ return null;
74
+ }
75
+ if (typeof PerformanceObserver === 'undefined') {
76
+ return null;
77
+ }
78
+ const events = [];
79
+ const observer = new PerformanceObserver((list)=>{
80
+ for (const entry of list.getEntries()){
81
+ events.push({
82
+ start: entry.startTime,
83
+ end: entry.startTime + entry.duration
84
+ });
85
+ }
86
+ });
87
+ try {
88
+ observer.observe({
89
+ entryTypes: [
90
+ 'gc'
91
+ ]
92
+ });
93
+ } catch {
94
+ return null;
95
+ }
96
+ const overlaps = (start, end)=>{
97
+ let noisy = false;
98
+ for(let i = events.length - 1; i >= 0; i--){
99
+ const event = events[i];
100
+ if (event.end < start - 5_000) {
101
+ events.splice(i, 1);
102
+ continue;
103
+ }
104
+ if (event.start <= end && event.end >= start) {
105
+ noisy = true;
106
+ }
107
+ }
108
+ return noisy;
109
+ };
110
+ const dispose = ()=>observer.disconnect();
111
+ return {
112
+ overlaps,
113
+ dispose
114
+ };
115
+ };
116
+ const pushWindow = (arr, value, cap)=>{
117
+ if (arr.length === cap) {
118
+ arr.shift();
119
+ }
120
+ arr.push(value);
121
+ };
122
+ const medianAndIqr = (arr)=>{
123
+ if (arr.length === 0) return {
124
+ median: 0,
125
+ iqr: 0
126
+ };
127
+ const sorted = [
128
+ ...arr
129
+ ].sort((a, b)=>a - b);
130
+ const mid = Math.floor(sorted.length / 2);
131
+ const median = sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
132
+ const q1Idx = Math.floor(sorted.length * 0.25);
133
+ const q3Idx = Math.floor(sorted.length * 0.75);
134
+ const q1 = sorted[q1Idx];
135
+ const q3 = sorted[q3Idx];
136
+ return {
137
+ median,
138
+ iqr: q3 - q1
139
+ };
140
+ };
141
+ const windowCv = (arr)=>{
142
+ if (arr.length < 2) return Number.POSITIVE_INFINITY;
143
+ const mean = arr.reduce((a, v)=>a + v, 0) / arr.length;
144
+ const variance = arr.reduce((a, v)=>a + (v - mean) * (v - mean), 0) / (arr.length - 1);
145
+ const stddev = Math.sqrt(variance);
146
+ return mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;
147
+ };
148
+ export const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data, warmupCycles, minCycles, absThreshold, relThreshold, gcObserver = false, durationsSAB, controlSAB })=>{
18
149
  const durations = new BigUint64Array(durationsSAB);
19
150
  const control = new Int32Array(controlSAB);
20
151
  control[Control.INDEX] = 0;
@@ -22,40 +153,113 @@ export const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data,
22
153
  control[Control.COMPLETE] = 255;
23
154
  const context = await setup?.();
24
155
  const maxCycles = durations.length;
156
+ const gcWatcher = gcObserver ? new GCWatcher() : null;
157
+ const gcTracker = gcObserver ? createGCTracker() : null;
25
158
  try {
26
159
  await pre?.(context, data);
27
- const result = runRaw(context, data);
160
+ const probeStart = hr();
161
+ const probeResult = runRaw(context, data);
162
+ const isAsync = isThenable(probeResult);
163
+ if (isAsync) {
164
+ await probeResult;
165
+ }
166
+ const durationProbe = hr() - probeStart;
28
167
  await post?.(context, data);
29
- global.gc?.();
30
- global.gc?.();
31
- const run = result instanceof Promise ? runAsync(runRaw) : runSync(runRaw);
32
- const start = Date.now();
33
- while(Date.now() - start < 1_000){
34
- Math.sqrt(Math.random());
168
+ const run = isAsync ? runAsync(runRaw) : runSync(runRaw);
169
+ const durationPerRun = durationProbe === 0n ? 1n : durationProbe;
170
+ const suggestedBatch = Number(TARGET_SAMPLE_NS / durationPerRun);
171
+ const initialBatchSize = Math.min(MAX_BATCH, Math.max(1, suggestedBatch));
172
+ const tuned = await tuneParameters({
173
+ initialBatch: initialBatchSize,
174
+ run,
175
+ pre,
176
+ post,
177
+ context,
178
+ data: data,
179
+ minCycles,
180
+ relThreshold,
181
+ maxCycles
182
+ });
183
+ let batchSize = tuned.batchSize;
184
+ minCycles = tuned.minCycles;
185
+ relThreshold = tuned.relThreshold;
186
+ const warmupStart = Date.now();
187
+ let warmupRemaining = warmupCycles;
188
+ const warmupWindow = [];
189
+ const warmupCap = Math.max(warmupCycles, Math.min(maxCycles, warmupCycles * 4 || 1000));
190
+ while(Date.now() - warmupStart < 1_000 && warmupRemaining > 0){
191
+ const start = hr();
192
+ await pre?.(context, data);
193
+ await run(context, data);
194
+ await post?.(context, data);
195
+ pushWindow(warmupWindow, Number(hr() - start), warmupCap);
196
+ warmupRemaining--;
35
197
  }
36
- for(let i = 0; i < warmupCycles; i++){
198
+ let warmupDone = 0;
199
+ while(warmupDone < warmupRemaining){
200
+ const start = hr();
37
201
  await pre?.(context, data);
38
202
  await run(context, data);
39
203
  await post?.(context, data);
40
- global.gc?.();
41
- global.gc?.();
204
+ pushWindow(warmupWindow, Number(hr() - start), warmupCap);
205
+ warmupDone++;
206
+ if (global.gc && warmupDone % GC_STRIDE === 0) {
207
+ global.gc();
208
+ }
209
+ }
210
+ while(warmupWindow.length >= 8 && warmupWindow.length < warmupCap){
211
+ const cv = windowCv(warmupWindow);
212
+ if (cv <= relThreshold * 2) {
213
+ break;
214
+ }
215
+ const start = hr();
216
+ await pre?.(context, data);
217
+ await run(context, data);
218
+ await post?.(context, data);
219
+ pushWindow(warmupWindow, Number(hr() - start), warmupCap);
42
220
  }
43
221
  let i = 0;
44
222
  let mean = 0n;
45
223
  let m2 = 0n;
224
+ const outlierWindow = [];
46
225
  while(true){
47
226
  if (i >= maxCycles) break;
48
- await pre?.(context, data);
49
- const duration = await run(context, data);
50
- await post?.(context, data);
51
- global.gc?.();
52
- global.gc?.();
53
- durations[i++] = duration;
54
- const delta = duration - mean;
227
+ const gcMarker = gcWatcher?.start();
228
+ const sampleStart = performance.now();
229
+ let sampleDuration = 0n;
230
+ for(let b = 0; b < batchSize; b++){
231
+ await pre?.(context, data);
232
+ sampleDuration += await run(context, data);
233
+ await post?.(context, data);
234
+ if (global.gc && (i + b) % GC_STRIDE === 0) {
235
+ global.gc();
236
+ }
237
+ }
238
+ sampleDuration /= BigInt(batchSize);
239
+ const sampleEnd = performance.now();
240
+ const gcNoise = (gcMarker ? gcWatcher.seen(gcMarker) : false) || (gcTracker?.overlaps(sampleStart, sampleEnd) ?? false);
241
+ if (gcNoise) {
242
+ continue;
243
+ }
244
+ const durationNumber = Number(sampleDuration);
245
+ pushWindow(outlierWindow, durationNumber, OUTLIER_WINDOW);
246
+ const { median, iqr } = medianAndIqr(outlierWindow);
247
+ const maxAllowed = median + OUTLIER_IQR_MULTIPLIER * iqr || Number.POSITIVE_INFINITY;
248
+ if (outlierWindow.length >= 8 && durationNumber > maxAllowed) {
249
+ continue;
250
+ }
251
+ const meanNumber = Number(mean);
252
+ if (i >= 8 && meanNumber > 0 && durationNumber > OUTLIER_MULTIPLIER * meanNumber) {
253
+ continue;
254
+ }
255
+ durations[i++] = sampleDuration;
256
+ const delta = sampleDuration - mean;
55
257
  mean += delta / BigInt(i);
56
- m2 += delta * (duration - mean);
258
+ m2 += delta * (sampleDuration - mean);
57
259
  const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;
58
- control[Control.PROGRESS] = progress;
260
+ if (i % PROGRESS_STRIDE === 0) {
261
+ control[Control.PROGRESS] = progress;
262
+ }
59
263
  if (i >= minCycles) {
60
264
  const variance = Number(m2) / (i - 1);
61
265
  const stddev = Math.sqrt(variance);
@@ -75,6 +279,7 @@ export const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data,
75
279
  console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);
76
280
  control[Control.COMPLETE] = 1;
77
281
  } finally{
282
+ gcTracker?.dispose?.();
78
283
  try {
79
284
  await teardown?.(context);
80
285
  } catch (e) {
@@ -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 };\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 global.gc?.();\n global.gc?.();\n\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 global.gc?.();\n global.gc?.();\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 global.gc?.();\n global.gc?.();\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","global","gc","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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"}
1
+ {"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { performance, PerformanceObserver } from 'node:perf_hooks';\nimport { Options, Control } from './types.js';\nimport { GCWatcher } from './gc-watcher.js';\nimport { StepFn, MaybePromise } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst hr = process.hrtime.bigint.bind(process.hrtime);\n\nconst runSync = (run: Function) => {\n return (...args: unknown[]) => {\n const start = hr();\n run(...args);\n return hr() - start;\n };\n};\n\nconst runAsync = (run: Function) => {\n return async (...args: unknown[]) => {\n const start = hr();\n await run(...args);\n return hr() - start;\n };\n};\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> => {\n return value !== null && (typeof value === 'object' || typeof value === 'function') && typeof (value as PromiseLike<unknown>).then === 'function';\n};\n\nconst TARGET_SAMPLE_NS = 1_000_000n; // aim for ~1ms per measured sample\nconst MAX_BATCH = 1_048_576;\nconst PROGRESS_STRIDE = 16;\nconst GC_STRIDE = 32;\nconst OUTLIER_MULTIPLIER = 4;\nconst OUTLIER_IQR_MULTIPLIER = 3;\nconst OUTLIER_WINDOW = 64;\n\ntype GCEvent = { start: number; end: number };\n\nconst collectSample = async <TContext, TInput>(\n batchSize: number,\n run: (ctx: TContext, data: TInput) => MaybePromise<bigint>,\n pre: StepFn<TContext, TInput> | undefined,\n post: StepFn<TContext, TInput> | undefined,\n context: TContext,\n data: TInput,\n) => {\n let sampleDuration = 0n;\n for (let b = 0; b < batchSize; b++) {\n await pre?.(context, data);\n sampleDuration += await run(context, data);\n await post?.(context, data);\n }\n return sampleDuration / BigInt(batchSize);\n};\n\nconst tuneParameters = async <TContext, TInput>({\n initialBatch,\n run,\n pre,\n post,\n context,\n data,\n minCycles,\n relThreshold,\n maxCycles,\n}: {\n initialBatch: number;\n run: (ctx: TContext, data: TInput) => MaybePromise<bigint>;\n pre?: StepFn<TContext, TInput>;\n post?: StepFn<TContext, TInput>;\n context: TContext;\n data: TInput;\n minCycles: number;\n relThreshold: number;\n maxCycles: number;\n}) => {\n let batchSize = initialBatch;\n let bestCv = Number.POSITIVE_INFINITY;\n let bestBatch = batchSize;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const samples: number[] = [];\n const sampleCount = Math.min(8, maxCycles);\n for (let s = 0; s < sampleCount; s++) {\n const duration = await collectSample(batchSize, run, pre, post, context, data);\n samples.push(Number(duration));\n }\n const mean = samples.reduce((acc, v) => acc + v, 0) / samples.length;\n const variance = samples.reduce((acc, v) => acc + (v - mean) * (v - mean), 0) / Math.max(1, samples.length - 1);\n const stddev = Math.sqrt(variance);\n const cv = mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n\n if (cv < bestCv) {\n bestCv = cv;\n bestBatch = batchSize;\n }\n\n if (cv <= relThreshold || batchSize >= MAX_BATCH) {\n break;\n }\n batchSize = Math.min(MAX_BATCH, batchSize * 2);\n }\n\n const tunedRel = bestCv < relThreshold ? Math.max(bestCv * 1.5, relThreshold * 0.5) : relThreshold;\n const tunedMin = Math.min(maxCycles, Math.max(minCycles, Math.ceil(minCycles * Math.max(1, bestCv / (relThreshold || 1e-6)))));\n\n return { batchSize: bestBatch, relThreshold: tunedRel, minCycles: tunedMin };\n};\n\nconst createGCTracker = () => {\n if (process.env.OVERTAKE_GC_OBSERVER !== '1') {\n return null;\n }\n if (typeof PerformanceObserver === 'undefined') {\n return null;\n }\n\n const events: GCEvent[] = [];\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n events.push({ start: entry.startTime, end: entry.startTime + entry.duration });\n }\n });\n\n try {\n observer.observe({ entryTypes: ['gc'] });\n } catch {\n return null;\n }\n\n const overlaps = (start: number, end: number) => {\n let noisy = false;\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i];\n if (event.end < start - 5_000) {\n events.splice(i, 1);\n continue;\n }\n if (event.start <= end && event.end >= start) {\n noisy = true;\n }\n }\n return noisy;\n };\n\n const dispose = () => observer.disconnect();\n\n return { overlaps, dispose };\n};\n\nconst pushWindow = (arr: number[], value: number, cap: number) => {\n if (arr.length === cap) {\n arr.shift();\n }\n arr.push(value);\n};\n\nconst medianAndIqr = (arr: number[]) => {\n if (arr.length === 0) return { median: 0, iqr: 0 };\n const sorted = [...arr].sort((a, b) => a - b);\n const mid = Math.floor(sorted.length / 2);\n const median = sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];\n const q1Idx = Math.floor(sorted.length * 0.25);\n const q3Idx = Math.floor(sorted.length * 0.75);\n const q1 = sorted[q1Idx];\n const q3 = sorted[q3Idx];\n return { median, iqr: q3 - q1 };\n};\n\nconst windowCv = (arr: number[]) => {\n if (arr.length < 2) return Number.POSITIVE_INFINITY;\n const mean = arr.reduce((a, v) => a + v, 0) / arr.length;\n const variance = arr.reduce((a, v) => a + (v - mean) * (v - mean), 0) / (arr.length - 1);\n const stddev = Math.sqrt(variance);\n return mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\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 gcObserver = false,\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 const gcWatcher = gcObserver ? new GCWatcher() : null;\n const gcTracker = gcObserver ? createGCTracker() : null;\n\n try {\n // classify sync/async and capture initial duration\n await pre?.(context, data!);\n const probeStart = hr();\n const probeResult = runRaw(context, data!);\n const isAsync = isThenable(probeResult);\n if (isAsync) {\n await probeResult;\n }\n const durationProbe = hr() - probeStart;\n await post?.(context, data!);\n\n const run = isAsync ? runAsync(runRaw) : runSync(runRaw);\n\n // choose batch size to amortize timer overhead\n const durationPerRun = durationProbe === 0n ? 1n : durationProbe;\n const suggestedBatch = Number(TARGET_SAMPLE_NS / durationPerRun);\n const initialBatchSize = Math.min(MAX_BATCH, Math.max(1, suggestedBatch));\n\n // auto-tune based on warmup samples\n const tuned = await tuneParameters({\n initialBatch: initialBatchSize,\n run,\n pre,\n post,\n context,\n data: data as TInput,\n minCycles,\n relThreshold,\n maxCycles,\n });\n let batchSize = tuned.batchSize;\n minCycles = tuned.minCycles;\n relThreshold = tuned.relThreshold;\n\n // warmup: run until requested cycles, adapt if unstable\n const warmupStart = Date.now();\n let warmupRemaining = warmupCycles;\n const warmupWindow: number[] = [];\n const warmupCap = Math.max(warmupCycles, Math.min(maxCycles, warmupCycles * 4 || 1000));\n\n while (Date.now() - warmupStart < 1_000 && warmupRemaining > 0) {\n const start = hr();\n await pre?.(context, data!);\n await run(context, data);\n await post?.(context, data!);\n pushWindow(warmupWindow, Number(hr() - start), warmupCap);\n warmupRemaining--;\n }\n let warmupDone = 0;\n while (warmupDone < warmupRemaining) {\n const start = hr();\n await pre?.(context, data!);\n await run(context, data);\n await post?.(context, data!);\n pushWindow(warmupWindow, Number(hr() - start), warmupCap);\n warmupDone++;\n if (global.gc && warmupDone % GC_STRIDE === 0) {\n global.gc();\n }\n }\n while (warmupWindow.length >= 8 && warmupWindow.length < warmupCap) {\n const cv = windowCv(warmupWindow);\n if (cv <= relThreshold * 2) {\n break;\n }\n const start = hr();\n await pre?.(context, data!);\n await run(context, data);\n await post?.(context, data!);\n pushWindow(warmupWindow, Number(hr() - start), warmupCap);\n }\n\n let i = 0;\n let mean = 0n;\n let m2 = 0n;\n const outlierWindow: number[] = [];\n\n while (true) {\n if (i >= maxCycles) break;\n\n const gcMarker = gcWatcher?.start();\n const sampleStart = performance.now();\n let sampleDuration = 0n;\n for (let b = 0; b < batchSize; b++) {\n await pre?.(context, data!);\n sampleDuration += await run(context, data);\n await post?.(context, data!);\n if (global.gc && (i + b) % GC_STRIDE === 0) {\n global.gc();\n }\n }\n\n // normalize by batch size\n sampleDuration /= BigInt(batchSize);\n\n const sampleEnd = performance.now();\n const gcNoise = (gcMarker ? gcWatcher!.seen(gcMarker) : false) || (gcTracker?.overlaps(sampleStart, sampleEnd) ?? false);\n if (gcNoise) {\n continue;\n }\n\n const durationNumber = Number(sampleDuration);\n pushWindow(outlierWindow, durationNumber, OUTLIER_WINDOW);\n const { median, iqr } = medianAndIqr(outlierWindow);\n const maxAllowed = median + OUTLIER_IQR_MULTIPLIER * iqr || Number.POSITIVE_INFINITY;\n if (outlierWindow.length >= 8 && durationNumber > maxAllowed) {\n continue;\n }\n\n const meanNumber = Number(mean);\n if (i >= 8 && meanNumber > 0 && durationNumber > OUTLIER_MULTIPLIER * meanNumber) {\n continue;\n }\n\n durations[i++] = sampleDuration;\n const delta = sampleDuration - mean;\n mean += delta / BigInt(i);\n m2 += delta * (sampleDuration - mean);\n\n const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;\n if (i % PROGRESS_STRIDE === 0) {\n control[Control.PROGRESS] = progress;\n }\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 gcTracker?.dispose?.();\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":["performance","PerformanceObserver","Control","GCWatcher","COMPLETE_VALUE","hr","process","hrtime","bigint","bind","runSync","run","args","start","runAsync","isThenable","value","then","TARGET_SAMPLE_NS","MAX_BATCH","PROGRESS_STRIDE","GC_STRIDE","OUTLIER_MULTIPLIER","OUTLIER_IQR_MULTIPLIER","OUTLIER_WINDOW","collectSample","batchSize","pre","post","context","data","sampleDuration","b","BigInt","tuneParameters","initialBatch","minCycles","relThreshold","maxCycles","bestCv","Number","POSITIVE_INFINITY","bestBatch","attempt","samples","sampleCount","Math","min","s","duration","push","mean","reduce","acc","v","length","variance","max","stddev","sqrt","cv","tunedRel","tunedMin","ceil","createGCTracker","env","OVERTAKE_GC_OBSERVER","events","observer","list","entry","getEntries","startTime","end","observe","entryTypes","overlaps","noisy","i","event","splice","dispose","disconnect","pushWindow","arr","cap","shift","medianAndIqr","median","iqr","sorted","sort","a","mid","floor","q1Idx","q3Idx","q1","q3","windowCv","benchmark","setup","teardown","runRaw","warmupCycles","absThreshold","gcObserver","durationsSAB","controlSAB","durations","BigUint64Array","control","Int32Array","INDEX","PROGRESS","COMPLETE","gcWatcher","gcTracker","probeStart","probeResult","isAsync","durationProbe","durationPerRun","suggestedBatch","initialBatchSize","tuned","warmupStart","Date","now","warmupRemaining","warmupWindow","warmupCap","warmupDone","global","gc","m2","outlierWindow","gcMarker","sampleStart","sampleEnd","gcNoise","seen","durationNumber","maxAllowed","meanNumber","delta","progress","meanNum","cov","e","console","error","stack"],"mappings":"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"}
@@ -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<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":";;;;;;;;;;;QAqEaA;eAAAA;;QANDC;eAAAA;;QAOCC;eAAAA;;QA9CAC;eAAAA;;QA+CAC;eAAAA;;;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"}
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 gcObserver?: boolean;\n baseUrl?: string;\n}\n\nexport interface RunOptions<TContext, TInput> {\n baseUrl?: string;\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 baseUrl: 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;\n"],"names":["CONTROL_SLOTS","Control","DEFAULT_CYCLES","REPORT_TYPES","Z95","Array","from","length","_","idx","concat","Object","values"],"mappings":";;;;;;;;;;;QAyEaA;eAAAA;;QANDC;eAAAA;;QAOCC;eAAAA;;QAlDAC;eAAAA;;QAmDAC;eAAAA;;;AAnDN,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;AA2C/J,IAAA,AAAKT,iCAAAA;;;;WAAAA;;AAML,MAAMD,gBAAgBW,OAAOC,MAAM,CAACX,SAASM,MAAM,GAAG;AACtD,MAAML,iBAAiB;AACvB,MAAME,MAAM"}
package/build/types.d.ts CHANGED
@@ -25,8 +25,11 @@ export interface BenchmarkOptions {
25
25
  minCycles?: number;
26
26
  absThreshold?: number;
27
27
  relThreshold?: number;
28
+ gcObserver?: boolean;
29
+ baseUrl?: string;
28
30
  }
29
31
  export interface RunOptions<TContext, TInput> {
32
+ baseUrl?: string;
30
33
  setup?: SetupFn<TContext>;
31
34
  teardown?: TeardownFn<TContext>;
32
35
  pre?: StepFn<TContext, TInput>;
@@ -35,6 +38,7 @@ export interface RunOptions<TContext, TInput> {
35
38
  data?: TInput;
36
39
  }
37
40
  export interface WorkerOptions extends Required<BenchmarkOptions> {
41
+ baseUrl: string;
38
42
  setupCode?: string;
39
43
  teardownCode?: string;
40
44
  preCode?: string;
@@ -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<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"}
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 gcObserver?: boolean;\n baseUrl?: string;\n}\n\nexport interface RunOptions<TContext, TInput> {\n baseUrl?: string;\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 baseUrl: 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;\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;AA2CxK,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
@@ -29,8 +29,12 @@ _export(exports, {
29
29
  },
30
30
  get max () {
31
31
  return max;
32
+ },
33
+ get transpile () {
34
+ return transpile;
32
35
  }
33
36
  });
37
+ const _core = require("@swc/core");
34
38
  const abs = (value)=>{
35
39
  if (value < 0n) {
36
40
  return -value;
@@ -96,5 +100,22 @@ class ScaledBigInt {
96
100
  return Number(div(this.value, this.scale));
97
101
  }
98
102
  }
103
+ const transpile = async (code)=>{
104
+ const output = await (0, _core.transform)(code, {
105
+ filename: 'benchmark.ts',
106
+ jsc: {
107
+ parser: {
108
+ syntax: 'typescript',
109
+ tsx: false,
110
+ dynamicImport: true
111
+ },
112
+ target: 'esnext'
113
+ },
114
+ module: {
115
+ type: 'es6'
116
+ }
117
+ });
118
+ return output.code;
119
+ };
99
120
 
100
121
  //# sourceMappingURL=utils.cjs.map
@@ -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};\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.scale;\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","add","sub","mul","unscale","number","Number"],"mappings":";;;;;;;;;;;QAyCaA;eAAAA;;QAzCAC;eAAAA;;QAMAC;eAAAA;;QAqBGC;eAAAA;;QAJHC;eAAAA;;QAaGC;eAAAA;;QApBHC;eAAAA;;;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;;;IACX,YACE,AAAOO,KAAa,EACpB,AAAOO,KAAa,CACpB;aAFOP,QAAAA;aACAO,QAAAA;IACN;IACHO,IAAId,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACO,KAAK;IAClC;IACAQ,IAAIf,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACO,KAAK;IAClC;IACAX,IAAII,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAgB,IAAIhB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAiB,UAAU;QACR,OAAO,IAAI,CAACjB,KAAK,GAAG,IAAI,CAACO,KAAK;IAChC;IACAW,SAAS;QACP,OAAOC,OAAOvB,IAAI,IAAI,CAACI,KAAK,EAAE,IAAI,CAACO,KAAK;IAC1C;AACF"}
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import { transform } from '@swc/core';\n\nexport 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.scale;\n }\n number() {\n return Number(div(this.value, this.scale));\n }\n}\n\nexport const transpile = async (code: string): Promise<string> => {\n const output = await transform(code, {\n filename: 'benchmark.ts',\n jsc: {\n parser: {\n syntax: 'typescript',\n tsx: false,\n dynamicImport: true,\n },\n target: 'esnext',\n },\n module: {\n type: 'es6',\n },\n });\n return output.code;\n};\n"],"names":["ScaledBigInt","abs","cmp","div","divMod","divs","max","transpile","value","a","b","quotient","remainder","decimals","RangeError","scale","BigInt","scaled","intPart","fracPart","toString","padStart","add","sub","mul","unscale","number","Number","code","output","transform","filename","jsc","parser","syntax","tsx","dynamicImport","target","module","type"],"mappings":";;;;;;;;;;;QA2CaA;eAAAA;;QAzCAC;eAAAA;;QAMAC;eAAAA;;QAqBGC;eAAAA;;QAJHC;eAAAA;;QAaGC;eAAAA;;QApBHC;eAAAA;;QAkDAC;eAAAA;;;sBApEa;AAEnB,MAAMN,MAAM,CAACO;IAClB,IAAIA,QAAQ,EAAE,EAAE;QACd,OAAO,CAACA;IACV;IACA,OAAOA;AACT;AACO,MAAMN,MAAM,CAACO,GAAoBC;IACtC,IAAID,IAAIC,GAAG;QACT,OAAO;IACT;IACA,IAAID,IAAIC,GAAG;QACT,OAAO,CAAC;IACV;IACA,OAAO;AACT;AAEO,MAAMJ,MAAM,CAACG,GAAWC;IAC7B,IAAID,IAAIC,GAAG;QACT,OAAOD;IACT;IACA,OAAOC;AACT;AAEO,MAAMN,SAAS,CAACK,GAAWC;IAChC,OAAO;QAAEC,UAAUF,IAAIC;QAAGE,WAAWH,IAAIC;IAAE;AAC7C;AAEO,SAASP,IAAIM,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,SAASR,KAAKI,CAAS,EAAEC,CAAS,EAAEK,KAAa;IACtD,IAAIL,MAAM,EAAE,EAAE,MAAM,IAAII,WAAW;IACnC,OAAO,AAACL,IAAIM,QAASL;AACvB;AAEO,MAAMV;;;IACX,YACE,AAAOQ,KAAa,EACpB,AAAOO,KAAa,CACpB;aAFOP,QAAAA;aACAO,QAAAA;IACN;IACHO,IAAId,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACO,KAAK;IAClC;IACAQ,IAAIf,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACO,KAAK;IAClC;IACAZ,IAAIK,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAgB,IAAIhB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAiB,UAAU;QACR,OAAO,IAAI,CAACjB,KAAK,GAAG,IAAI,CAACO,KAAK;IAChC;IACAW,SAAS;QACP,OAAOC,OAAOxB,IAAI,IAAI,CAACK,KAAK,EAAE,IAAI,CAACO,KAAK;IAC1C;AACF;AAEO,MAAMR,YAAY,OAAOqB;IAC9B,MAAMC,SAAS,MAAMC,IAAAA,eAAS,EAACF,MAAM;QACnCG,UAAU;QACVC,KAAK;YACHC,QAAQ;gBACNC,QAAQ;gBACRC,KAAK;gBACLC,eAAe;YACjB;YACAC,QAAQ;QACV;QACAC,QAAQ;YACNC,MAAM;QACR;IACF;IACA,OAAOV,OAAOD,IAAI;AACpB"}
package/build/utils.d.ts CHANGED
@@ -18,3 +18,4 @@ export declare class ScaledBigInt {
18
18
  unscale(): bigint;
19
19
  number(): number;
20
20
  }
21
+ export declare const transpile: (code: string) => Promise<string>;
package/build/utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { transform } from '@swc/core';
1
2
  export const abs = (value)=>{
2
3
  if (value < 0n) {
3
4
  return -value;
@@ -63,5 +64,22 @@ export class ScaledBigInt {
63
64
  return Number(div(this.value, this.scale));
64
65
  }
65
66
  }
67
+ export const transpile = async (code)=>{
68
+ const output = await transform(code, {
69
+ filename: 'benchmark.ts',
70
+ jsc: {
71
+ parser: {
72
+ syntax: 'typescript',
73
+ tsx: false,
74
+ dynamicImport: true
75
+ },
76
+ target: 'esnext'
77
+ },
78
+ module: {
79
+ type: 'es6'
80
+ }
81
+ });
82
+ return output.code;
83
+ };
66
84
 
67
85
  //# sourceMappingURL=utils.js.map
@@ -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};\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.scale;\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","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;;;IACX,YACE,AAAOnB,KAAa,EACpB,AAAOW,KAAa,CACpB;aAFOX,QAAAA;aACAW,QAAAA;IACN;IACHS,IAAIpB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACW,KAAK;IAClC;IACAU,IAAIrB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACW,KAAK;IAClC;IACAH,IAAIR,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAsB,IAAItB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAuB,UAAU;QACR,OAAO,IAAI,CAACvB,KAAK,GAAG,IAAI,CAACW,KAAK;IAChC;IACAa,SAAS;QACP,OAAOC,OAAOjB,IAAI,IAAI,CAACR,KAAK,EAAE,IAAI,CAACW,KAAK;IAC1C;AACF"}
1
+ {"version":3,"sources":["../src/utils.ts"],"sourcesContent":["import { transform } from '@swc/core';\n\nexport 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.scale;\n }\n number() {\n return Number(div(this.value, this.scale));\n }\n}\n\nexport const transpile = async (code: string): Promise<string> => {\n const output = await transform(code, {\n filename: 'benchmark.ts',\n jsc: {\n parser: {\n syntax: 'typescript',\n tsx: false,\n dynamicImport: true,\n },\n target: 'esnext',\n },\n module: {\n type: 'es6',\n },\n });\n return output.code;\n};\n"],"names":["transform","abs","value","cmp","a","b","max","divMod","quotient","remainder","div","decimals","RangeError","scale","BigInt","scaled","intPart","fracPart","toString","padStart","divs","ScaledBigInt","add","sub","mul","unscale","number","Number","transpile","code","output","filename","jsc","parser","syntax","tsx","dynamicImport","target","module","type"],"mappings":"AAAA,SAASA,SAAS,QAAQ,YAAY;AAEtC,OAAO,MAAMC,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;;;IACX,YACE,AAAOnB,KAAa,EACpB,AAAOW,KAAa,CACpB;aAFOX,QAAAA;aACAW,QAAAA;IACN;IACHS,IAAIpB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACW,KAAK;IAClC;IACAU,IAAIrB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA,QAAQ,IAAI,CAACW,KAAK;IAClC;IACAH,IAAIR,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAsB,IAAItB,KAAa,EAAE;QACjB,IAAI,CAACA,KAAK,IAAIA;IAChB;IACAuB,UAAU;QACR,OAAO,IAAI,CAACvB,KAAK,GAAG,IAAI,CAACW,KAAK;IAChC;IACAa,SAAS;QACP,OAAOC,OAAOjB,IAAI,IAAI,CAACR,KAAK,EAAE,IAAI,CAACW,KAAK;IAC1C;AACF;AAEA,OAAO,MAAMe,YAAY,OAAOC;IAC9B,MAAMC,SAAS,MAAM9B,UAAU6B,MAAM;QACnCE,UAAU;QACVC,KAAK;YACHC,QAAQ;gBACNC,QAAQ;gBACRC,KAAK;gBACLC,eAAe;YACjB;YACAC,QAAQ;QACV;QACAC,QAAQ;YACNC,MAAM;QACR;IACF;IACA,OAAOT,OAAOD,IAAI;AACpB,EAAE"}