benchforge 0.1.2 → 0.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.
@@ -9,10 +9,7 @@ import { runMatrix } from "../BenchMatrix.ts";
9
9
  import type { BenchGroup, BenchmarkSpec, BenchSuite } from "../Benchmark.ts";
10
10
  import type { BenchmarkReport, ReportGroup } from "../BenchmarkReport.ts";
11
11
  import { reportResults } from "../BenchmarkReport.ts";
12
- import {
13
- type BrowserProfileResult,
14
- profileBrowser,
15
- } from "../browser/BrowserHeapSampler.ts";
12
+ import type { BrowserProfileResult } from "../browser/BrowserHeapSampler.ts";
16
13
  import { exportBenchmarkJson } from "../export/JsonExport.ts";
17
14
  import { exportPerfettoTrace } from "../export/PerfettoExport.ts";
18
15
  import type { GitVersion } from "../GitUtils.ts";
@@ -38,12 +35,10 @@ import {
38
35
  type MatrixReportOptions,
39
36
  reportMatrixResults,
40
37
  } from "../matrix/MatrixReport.ts";
41
- import { checkConvergence } from "../runners/AdaptiveWrapper.ts";
42
38
  import { computeStats } from "../runners/BasicRunner.ts";
43
39
  import type { RunnerOptions } from "../runners/BenchRunner.ts";
44
40
  import type { KnownRunner } from "../runners/CreateRunner.ts";
45
41
  import { runBenchmark } from "../runners/RunnerOrchestrator.ts";
46
- import { msToNs } from "../runners/RunnerUtils.ts";
47
42
  import {
48
43
  adaptiveSection,
49
44
  browserGcStatsSection,
@@ -309,7 +304,6 @@ function mergeResults(results: MeasuredResults[]): MeasuredResults {
309
304
  const allSamples = results.flatMap(r => r.samples);
310
305
  const allWarmup = results.flatMap(r => r.warmupSamples || []);
311
306
  const time = computeStats(allSamples);
312
- const convergence = checkConvergence(allSamples.map(s => s * msToNs));
313
307
 
314
308
  let offset = 0;
315
309
  const allPausePoints = results.flatMap(r => {
@@ -327,7 +321,6 @@ function mergeResults(results: MeasuredResults[]): MeasuredResults {
327
321
  warmupSamples: allWarmup.length ? allWarmup : undefined,
328
322
  time,
329
323
  totalTime: results.reduce((sum, r) => sum + (r.totalTime || 0), 0),
330
- convergence,
331
324
  pausePoints: allPausePoints.length ? allPausePoints : undefined,
332
325
  };
333
326
  }
@@ -390,6 +383,20 @@ export async function benchExports(
390
383
  /** Run browser profiling via Playwright + CDP, report with standard pipeline */
391
384
  export async function browserBenchExports(args: DefaultCliArgs): Promise<void> {
392
385
  warnBrowserFlags(args);
386
+
387
+ let profileBrowser: typeof import("../browser/BrowserHeapSampler.ts").profileBrowser;
388
+ try {
389
+ ({ profileBrowser } = await import("../browser/BrowserHeapSampler.ts"));
390
+ } catch {
391
+ throw new Error(
392
+ "playwright is required for browser benchmarking (--url).\n\n" +
393
+ "Quick start: npx benchforge-browser --url <your-url>\n\n" +
394
+ "Or install manually:\n" +
395
+ " npm install playwright\n" +
396
+ " npx playwright install chromium",
397
+ );
398
+ }
399
+
393
400
  const url = args.url!;
394
401
  const { iterations, time } = args;
395
402
  const result = await profileBrowser({
@@ -400,6 +407,7 @@ export async function browserBenchExports(args: DefaultCliArgs): Promise<void> {
400
407
  stackDepth: args["heap-depth"],
401
408
  },
402
409
  headless: args.headless,
410
+ chromeArgs: args["chrome-args"]?.split(/\s+/).filter(Boolean),
403
411
  timeout: args.timeout,
404
412
  gcStats: args["gc-stats"],
405
413
  maxTime: iterations ? Number.MAX_SAFE_INTEGER : time * 1000,
@@ -5,10 +5,8 @@ import type {
5
5
  OptStatusInfo,
6
6
  PausePoint,
7
7
  } from "../MeasuredResults.ts";
8
- import { checkConvergence } from "./AdaptiveWrapper.ts";
9
8
  import type { BenchRunner, RunnerOptions } from "./BenchRunner.ts";
10
9
  import { executeBenchmark } from "./BenchRunner.ts";
11
- import { msToNs } from "./RunnerUtils.ts";
12
10
 
13
11
  /**
14
12
  * Wait time after gc() for V8 to stabilize (ms).
@@ -91,7 +89,6 @@ const defaultCollectOptions = {
91
89
 
92
90
  function buildMeasuredResults(name: string, c: CollectResult): MeasuredResults {
93
91
  const time = computeStats(c.samples);
94
- const convergence = checkConvergence(c.samples.map(s => s * msToNs));
95
92
  return {
96
93
  name,
97
94
  samples: c.samples,
@@ -100,7 +97,6 @@ function buildMeasuredResults(name: string, c: CollectResult): MeasuredResults {
100
97
  timestamps: c.timestamps,
101
98
  time,
102
99
  heapSize: { avg: c.heapGrowth, min: c.heapGrowth, max: c.heapGrowth },
103
- convergence,
104
100
  optStatus: c.optStatus,
105
101
  optSamples: c.optSamples,
106
102
  pausePoints: c.pausePoints,
@@ -1 +0,0 @@
1
- {"version":3,"file":"TimingUtils-D4z1jpp2.mjs","names":["percentile","percentile"],"sources":["../src/matrix/VariantLoader.ts","../src/StatisticalUtils.ts","../src/runners/RunnerUtils.ts","../src/runners/AdaptiveWrapper.ts","../src/runners/BenchRunner.ts","../src/runners/BasicRunner.ts","../src/runners/CreateRunner.ts","../src/runners/TimingUtils.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Variant } from \"../BenchMatrix.ts\";\n\n/** Discover variant ids from a directory of .ts files */\nexport async function discoverVariants(dirUrl: string): Promise<string[]> {\n const dirPath = fileURLToPath(dirUrl);\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n return entries\n .filter(e => e.isFile() && e.name.endsWith(\".ts\"))\n .map(e => e.name.slice(0, -3))\n .sort();\n}\n\n/** Load a variant module and extract run/setup exports */\nexport async function loadVariant<T = unknown>(\n dirUrl: string,\n variantId: string,\n): Promise<Variant<T>> {\n const moduleUrl = variantModuleUrl(dirUrl, variantId);\n const module = await import(moduleUrl);\n return extractVariant(module, variantId, moduleUrl);\n}\n\n/** Extract variant from module exports */\nfunction extractVariant<T>(\n module: Record<string, unknown>,\n variantId: string,\n moduleUrl: string,\n): Variant<T> {\n const { setup, run } = module;\n const loc = `Variant '${variantId}' at ${moduleUrl}`;\n if (typeof run !== \"function\") {\n throw new Error(`${loc} must export 'run'`);\n }\n if (setup === undefined) return run as (data: T) => void;\n if (typeof setup !== \"function\") {\n throw new Error(`${loc}: 'setup' must be a function`);\n }\n return { setup: setup as (data: T) => unknown, run: run as () => void };\n}\n\n/** Get module URL for a variant in a directory */\nexport function variantModuleUrl(dirUrl: string, variantId: string): string {\n return new URL(`${variantId}.ts`, dirUrl).href;\n}\n","const outlierMultiplier = 1.5; // Tukey's fence multiplier\nconst bootstrapSamples = 10000;\nconst confidence = 0.95;\n\n/** Options for bootstrap resampling methods */\ntype BootstrapOptions = {\n resamples?: number;\n confidence?: number;\n};\n\n/** Bootstrap estimate with confidence interval and raw resample data */\nexport interface BootstrapResult {\n estimate: number;\n ci: [number, number];\n samples: number[];\n}\n\n/** @return relative standard deviation (coefficient of variation) */\nexport function coefficientOfVariation(samples: number[]): number {\n const mean = average(samples);\n if (mean === 0) return 0;\n const stdDev = standardDeviation(samples);\n return stdDev / mean;\n}\n\n/** @return median absolute deviation for robust variability measure */\nexport function medianAbsoluteDeviation(samples: number[]): number {\n const median = percentile(samples, 0.5);\n const deviations = samples.map(x => Math.abs(x - median));\n return percentile(deviations, 0.5);\n}\n\n/** @return outliers detected via Tukey's interquartile range method */\nexport function findOutliers(samples: number[]): {\n rate: number;\n indices: number[];\n} {\n const q1 = percentile(samples, 0.25);\n const q3 = percentile(samples, 0.75);\n const iqr = q3 - q1;\n const lowerBound = q1 - outlierMultiplier * iqr;\n const upperBound = q3 + outlierMultiplier * iqr;\n\n const indices = samples\n .map((v, i) => (v < lowerBound || v > upperBound ? i : -1))\n .filter(i => i >= 0);\n return { rate: indices.length / samples.length, indices };\n}\n\n/** @return bootstrap confidence interval for median */\nexport function bootstrapMedian(\n samples: number[],\n options: BootstrapOptions = {},\n): BootstrapResult {\n const { resamples = bootstrapSamples, confidence: conf = confidence } =\n options;\n const medians = generateMedians(samples, resamples);\n const ci = computeInterval(medians, conf);\n\n return {\n estimate: percentile(samples, 0.5),\n ci,\n samples: medians,\n };\n}\n\n/** @return mean of values */\nexport function average(values: number[]): number {\n const sum = values.reduce((a, b) => a + b, 0);\n return sum / values.length;\n}\n\n/** @return standard deviation with Bessel's correction */\nexport function standardDeviation(samples: number[]): number {\n if (samples.length <= 1) return 0;\n const mean = average(samples);\n const variance =\n samples.reduce((sum, x) => sum + (x - mean) ** 2, 0) / (samples.length - 1);\n return Math.sqrt(variance);\n}\n\n/** @return value at percentile p (0-1) */\nexport function percentile(values: number[], p: number): number {\n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.ceil(sorted.length * p) - 1;\n return sorted[Math.max(0, index)];\n}\n\n/** @return medians from bootstrap resamples */\nfunction generateMedians(samples: number[], resamples: number): number[] {\n return Array.from({ length: resamples }, () =>\n percentile(createResample(samples), 0.5),\n );\n}\n\n/** @return bootstrap resample with replacement */\nexport function createResample(samples: number[]): number[] {\n const n = samples.length;\n const rand = () => samples[Math.floor(Math.random() * n)];\n return Array.from({ length: n }, rand);\n}\n\n/** @return confidence interval [lower, upper] */\nfunction computeInterval(\n medians: number[],\n confidence: number,\n): [number, number] {\n const alpha = (1 - confidence) / 2;\n const lower = percentile(medians, alpha);\n const upper = percentile(medians, 1 - alpha);\n return [lower, upper];\n}\n\nexport type CIDirection = \"faster\" | \"slower\" | \"uncertain\";\n\n/** Binned histogram for efficient transfer to browser */\nexport interface HistogramBin {\n x: number; // bin center\n count: number;\n}\n\n/** Bootstrap confidence interval for percentage difference between two samples */\nexport interface DifferenceCI {\n percent: number;\n ci: [number, number];\n direction: CIDirection;\n /** Histogram of bootstrap distribution for visualization */\n histogram?: HistogramBin[];\n}\n\n/** Bin values into histogram for compact visualization */\nfunction binValues(values: number[], binCount = 30): HistogramBin[] {\n const sorted = [...values].sort((a, b) => a - b);\n const min = sorted[0];\n const max = sorted[sorted.length - 1];\n if (min === max) return [{ x: min, count: values.length }];\n\n const step = (max - min) / binCount;\n const counts = new Array(binCount).fill(0);\n for (const v of values) {\n const bin = Math.min(Math.floor((v - min) / step), binCount - 1);\n counts[bin]++;\n }\n return counts.map((count, i) => ({ x: min + (i + 0.5) * step, count }));\n}\n\n/** @return bootstrap CI for percentage difference between baseline and current medians */\nexport function bootstrapDifferenceCI(\n baseline: number[],\n current: number[],\n options: BootstrapOptions = {},\n): DifferenceCI {\n const { resamples = bootstrapSamples, confidence: conf = confidence } =\n options;\n\n const baselineMedian = percentile(baseline, 0.5);\n const currentMedian = percentile(current, 0.5);\n const observedPercent =\n ((currentMedian - baselineMedian) / baselineMedian) * 100;\n\n const diffs: number[] = [];\n for (let i = 0; i < resamples; i++) {\n const resB = createResample(baseline);\n const resC = createResample(current);\n const medB = percentile(resB, 0.5);\n const medC = percentile(resC, 0.5);\n diffs.push(((medC - medB) / medB) * 100);\n }\n\n const ci = computeInterval(diffs, conf);\n const excludesZero = ci[0] > 0 || ci[1] < 0;\n let direction: CIDirection = \"uncertain\";\n if (excludesZero) direction = observedPercent < 0 ? \"faster\" : \"slower\";\n const histogram = binValues(diffs);\n return { percent: observedPercent, ci, direction, histogram };\n}\n","export const msToNs = 1e6;\nexport const nsToMs = 1e-6;\n","import type { BenchmarkSpec } from \"../Benchmark.ts\";\nimport type { MeasuredResults } from \"../MeasuredResults.ts\";\nimport {\n coefficientOfVariation,\n medianAbsoluteDeviation,\n percentile,\n} from \"../StatisticalUtils.ts\";\nimport type { BenchRunner, RunnerOptions } from \"./BenchRunner.ts\";\nimport { msToNs } from \"./RunnerUtils.ts\";\n\nconst minTime = 1000;\nconst maxTime = 10000;\nconst targetConfidence = 95;\nconst fallbackThreshold = 80;\nconst windowSize = 50;\nconst stability = 0.05; // 5% drift threshold (was 2%, too strict for real benchmarks)\nconst initialBatch = 100;\nconst continueBatch = 100;\nconst continueIterations = 10;\n\ntype Metrics = {\n medianDrift: number;\n impactDrift: number;\n medianStable: boolean;\n impactStable: boolean;\n};\n\ninterface ConvergenceResult {\n converged: boolean;\n confidence: number;\n reason: string;\n}\n\nexport interface AdaptiveOptions extends RunnerOptions {\n adaptive?: boolean;\n minTime?: number;\n maxTime?: number;\n targetConfidence?: number;\n convergence?: number; // Confidence threshold (0-100)\n}\n\n/** @return adaptive sampling runner wrapper */\nexport function createAdaptiveWrapper(\n baseRunner: BenchRunner,\n options: AdaptiveOptions,\n): BenchRunner {\n return {\n async runBench<T = unknown>(\n benchmark: BenchmarkSpec<T>,\n runnerOptions: RunnerOptions,\n params?: T,\n ): Promise<MeasuredResults[]> {\n return runAdaptiveBench(\n baseRunner,\n benchmark,\n runnerOptions,\n options,\n params,\n );\n },\n };\n}\n\n/** @return results using adaptive sampling strategy */\nasync function runAdaptiveBench<T>(\n baseRunner: BenchRunner,\n benchmark: BenchmarkSpec<T>,\n runnerOptions: RunnerOptions,\n options: AdaptiveOptions,\n params?: T,\n): Promise<MeasuredResults[]> {\n const {\n minTime: min = options.minTime ?? minTime,\n maxTime: max = options.maxTime ?? maxTime,\n targetConfidence: target = options.convergence ?? targetConfidence,\n } = runnerOptions as AdaptiveOptions;\n const allSamples: number[] = [];\n\n // Collect initial batch (includes warmup + settle)\n const warmup = await collectInitial(\n baseRunner,\n benchmark,\n runnerOptions,\n params,\n allSamples,\n );\n\n // Start timing AFTER warmup - warmup time doesn't count against maxTime\n const startTime = performance.now();\n\n const limits = {\n minTime: min,\n maxTime: max,\n targetConfidence: target,\n startTime,\n };\n await collectAdaptive(\n baseRunner,\n benchmark,\n runnerOptions,\n params,\n allSamples,\n limits,\n );\n\n const convergence = checkConvergence(allSamples.map(s => s * msToNs));\n return buildResults(\n allSamples,\n startTime,\n convergence,\n benchmark.name,\n warmup,\n );\n}\n\n/** @return warmupSamples from initial batch */\nasync function collectInitial<T>(\n baseRunner: BenchRunner,\n benchmark: BenchmarkSpec<T>,\n runnerOptions: RunnerOptions,\n params: T | undefined,\n allSamples: number[],\n): Promise<number[] | undefined> {\n // Don't pass adaptive flag to base runner to avoid double wrapping\n const opts = {\n ...(runnerOptions as any),\n maxTime: initialBatch,\n maxIterations: undefined,\n };\n const results = await baseRunner.runBench(benchmark, opts, params);\n appendSamples(results[0], allSamples);\n return results[0].warmupSamples;\n}\n\n/** @return samples until convergence or timeout */\nasync function collectAdaptive<T>(\n baseRunner: BenchRunner,\n benchmark: BenchmarkSpec<T>,\n runnerOptions: RunnerOptions,\n params: T | undefined,\n allSamples: number[],\n limits: {\n minTime: number;\n maxTime: number;\n targetConfidence: number;\n startTime: number;\n },\n): Promise<void> {\n const { minTime, maxTime, targetConfidence, startTime } = limits;\n let lastLog = 0;\n while (performance.now() - startTime < maxTime) {\n const samplesNs = allSamples.map(s => s * msToNs);\n const convergence = checkConvergence(samplesNs);\n const elapsed = performance.now() - startTime;\n\n if (elapsed - lastLog > 1000) {\n const elapsedSec = (elapsed / 1000).toFixed(1);\n const conf = convergence.confidence.toFixed(0);\n process.stderr.write(\n `\\r◊ ${benchmark.name}: ${conf}% confident (${elapsedSec}s) `,\n );\n lastLog = elapsed;\n }\n\n if (shouldStop(convergence, targetConfidence, elapsed, minTime)) {\n break;\n }\n\n // Skip warmup for continuation batches (warmup done in initial batch)\n const opts = {\n ...(runnerOptions as any),\n maxTime: continueBatch,\n maxIterations: continueIterations,\n skipWarmup: true,\n };\n const batchResults = await baseRunner.runBench(benchmark, opts, params);\n appendSamples(batchResults[0], allSamples);\n }\n process.stderr.write(\"\\r\" + \" \".repeat(60) + \"\\r\");\n}\n\n/** Append samples one-by-one to avoid stack overflow from spread on large arrays */\nfunction appendSamples(result: MeasuredResults, samples: number[]): void {\n if (!result.samples?.length) return;\n for (const sample of result.samples) samples.push(sample);\n}\n\n/** @return true if convergence reached or timeout */\nfunction shouldStop(\n convergence: ConvergenceResult,\n targetConfidence: number,\n elapsedTime: number,\n minTime: number,\n): boolean {\n if (convergence.converged && convergence.confidence >= targetConfidence) {\n return true;\n }\n // After minTime, accept whichever is higher: targetConfidence or fallbackThreshold\n const threshold = Math.max(targetConfidence, fallbackThreshold);\n return elapsedTime >= minTime && convergence.confidence >= threshold;\n}\n\n/** @return measured results with convergence metrics */\nfunction buildResults(\n samplesMs: number[],\n startTime: number,\n convergence: ConvergenceResult,\n name: string,\n warmupSamples?: number[],\n): MeasuredResults[] {\n const totalTime = (performance.now() - startTime) / 1000;\n const samplesNs = samplesMs.map(s => s * msToNs);\n const timeStats = computeTimeStats(samplesNs);\n\n return [\n {\n name,\n samples: samplesMs,\n warmupSamples,\n time: timeStats,\n totalTime,\n convergence,\n },\n ];\n}\n\n/** @return time percentiles and statistics in ms */\nfunction computeTimeStats(samplesNs: number[]) {\n const samplesMs = samplesNs.map(s => s / msToNs);\n const { min, max, sum } = getMinMaxSum(samplesNs);\n const percentiles = getPercentiles(samplesNs);\n const robust = getRobustMetrics(samplesMs);\n\n return {\n min: min / msToNs,\n max: max / msToNs,\n avg: sum / samplesNs.length / msToNs,\n ...percentiles,\n ...robust,\n };\n}\n\n/** @return min, max, sum of samples */\nfunction getMinMaxSum(samples: number[]) {\n const min = samples.reduce(\n (a, b) => Math.min(a, b),\n Number.POSITIVE_INFINITY,\n );\n const max = samples.reduce(\n (a, b) => Math.max(a, b),\n Number.NEGATIVE_INFINITY,\n );\n const sum = samples.reduce((a, b) => a + b, 0);\n return { min, max, sum };\n}\n\n/** @return percentiles in ms */\nfunction getPercentiles(samples: number[]) {\n return {\n p25: percentile(samples, 0.25) / msToNs,\n p50: percentile(samples, 0.5) / msToNs,\n p75: percentile(samples, 0.75) / msToNs,\n p95: percentile(samples, 0.95) / msToNs,\n p99: percentile(samples, 0.99) / msToNs,\n p999: percentile(samples, 0.999) / msToNs,\n };\n}\n\n/** @return robust variability metrics */\nfunction getRobustMetrics(samplesMs: number[]) {\n const impact = getOutlierImpact(samplesMs);\n return {\n cv: coefficientOfVariation(samplesMs),\n mad: medianAbsoluteDeviation(samplesMs),\n outlierRate: impact.ratio,\n };\n}\n\n/** @return outlier impact as proportion of total time */\nfunction getOutlierImpact(samples: number[]): { ratio: number; count: number } {\n if (samples.length === 0) return { ratio: 0, count: 0 };\n\n const median = percentile(samples, 0.5);\n const q75 = percentile(samples, 0.75);\n const threshold = median + 1.5 * (q75 - median);\n\n let excessTime = 0;\n let count = 0;\n\n for (const sample of samples) {\n if (sample > threshold) {\n excessTime += sample - median;\n count++;\n }\n }\n\n const totalTime = samples.reduce((a, b) => a + b, 0);\n return {\n ratio: totalTime > 0 ? excessTime / totalTime : 0,\n count,\n };\n}\n\n/** @return convergence based on window stability */\nexport function checkConvergence(samples: number[]): ConvergenceResult {\n const windowSize = getWindowSize(samples);\n const minSamples = windowSize * 2;\n\n if (samples.length < minSamples) {\n return buildProgressResult(samples.length, minSamples);\n }\n\n const metrics = getStability(samples, windowSize);\n return buildConvergence(metrics);\n}\n\n/** @return progress when samples insufficient */\nfunction buildProgressResult(\n currentSamples: number,\n minSamples: number,\n): ConvergenceResult {\n return {\n converged: false,\n confidence: (currentSamples / minSamples) * 100,\n reason: `Collecting samples: ${currentSamples}/${minSamples}`,\n };\n}\n\n/** @return stability metrics between windows */\nfunction getStability(samples: number[], windowSize: number): Metrics {\n const recent = samples.slice(-windowSize);\n const previous = samples.slice(-windowSize * 2, -windowSize);\n\n const recentMs = recent.map(s => s / msToNs);\n const previousMs = previous.map(s => s / msToNs);\n\n const medianRecent = percentile(recentMs, 0.5);\n const medianPrevious = percentile(previousMs, 0.5);\n const medianDrift = Math.abs(medianRecent - medianPrevious) / medianPrevious;\n\n const impactRecent = getOutlierImpact(recentMs);\n const impactPrevious = getOutlierImpact(previousMs);\n const impactDrift = Math.abs(impactRecent.ratio - impactPrevious.ratio);\n\n return {\n medianDrift,\n impactDrift,\n medianStable: medianDrift < stability,\n impactStable: impactDrift < stability,\n };\n}\n\n/** @return convergence from stability metrics */\nfunction buildConvergence(metrics: Metrics): ConvergenceResult {\n const { medianDrift, impactDrift, medianStable, impactStable } = metrics;\n\n if (medianStable && impactStable) {\n return {\n converged: true,\n confidence: 100,\n reason: \"Stable performance pattern\",\n };\n }\n\n const confidence = Math.min(\n 100,\n (1 - medianDrift / stability) * 50 + (1 - impactDrift / stability) * 50,\n );\n\n const reason =\n medianDrift > impactDrift\n ? `Median drifting: ${(medianDrift * 100).toFixed(1)}%`\n : `Outlier impact changing: ${(impactDrift * 100).toFixed(1)}%`;\n\n return { converged: false, confidence: Math.max(0, confidence), reason };\n}\n\n/** @return window size scaled to execution time */\nfunction getWindowSize(samples: number[]): number {\n if (samples.length < 20) return windowSize; // Default for initial samples\n\n const recentMs = samples.slice(-20).map(s => s / msToNs);\n const recentMedian = percentile(recentMs, 0.5);\n\n // Inverse scaling with execution time\n if (recentMedian < 0.01) return 200; // <10μs\n if (recentMedian < 0.1) return 100; // <100μs\n if (recentMedian < 1) return 50; // <1ms\n if (recentMedian < 10) return 30; // <10ms\n return 20; // >10ms\n}\n","import type { BenchmarkSpec } from \"../Benchmark.ts\";\nimport type { MeasuredResults } from \"../MeasuredResults.ts\";\n\n/** Execute benchmark with optional parameters */\nexport function executeBenchmark<T>(\n benchmark: BenchmarkSpec<T>,\n params?: T,\n): void {\n (benchmark.fn as (params?: T) => void)(params);\n}\n\n/** Interface for benchmark execution libraries */\nexport interface BenchRunner {\n runBench<T = unknown>(\n benchmark: BenchmarkSpec<T>,\n options: RunnerOptions,\n params?: T,\n ): Promise<MeasuredResults[]>;\n}\n\nexport interface RunnerOptions {\n /** Minimum time to run each benchmark (milliseconds) */\n minTime?: number;\n /** Maximum time to run each benchmark - ignored by mitata (milliseconds) */\n maxTime?: number;\n /** Maximum iterations per benchmark - ignored by TinyBench */\n maxIterations?: number;\n /** Warmup iterations before measurement (default: 0) */\n warmup?: number;\n /** Warmup time before measurement (milliseconds) */\n warmupTime?: number;\n /** Warmup samples - mitata only, for reducing test time */\n warmupSamples?: number;\n /** Warmup threshold - mitata only (nanoseconds) */\n warmupThreshold?: number;\n /** Minimum samples required - mitata only */\n minSamples?: number;\n /** Force GC after each iteration (requires --expose-gc) */\n collect?: boolean;\n /** Enable CPU performance counters (requires root access) */\n cpuCounters?: boolean;\n /** Trace V8 optimization tiers (requires --allow-natives-syntax) */\n traceOpt?: boolean;\n /** Skip post-warmup settle time (default: false) */\n noSettle?: boolean;\n /** Iterations before first pause (then pauseInterval applies) */\n pauseFirst?: number;\n /** Iterations between pauses for V8 optimization (0 to disable) */\n pauseInterval?: number;\n /** Pause duration in ms for V8 optimization */\n pauseDuration?: number;\n /** Collect GC stats via --trace-gc-nvp (requires worker mode) */\n gcStats?: boolean;\n /** Heap sampling allocation attribution */\n heapSample?: boolean;\n /** Heap sampling interval in bytes */\n heapInterval?: number;\n /** Heap sampling stack depth */\n heapDepth?: number;\n}\n","import { getHeapStatistics } from \"node:v8\";\nimport type { BenchmarkSpec } from \"../Benchmark.ts\";\nimport type {\n MeasuredResults,\n OptStatusInfo,\n PausePoint,\n} from \"../MeasuredResults.ts\";\nimport { checkConvergence } from \"./AdaptiveWrapper.ts\";\nimport type { BenchRunner, RunnerOptions } from \"./BenchRunner.ts\";\nimport { executeBenchmark } from \"./BenchRunner.ts\";\nimport { msToNs } from \"./RunnerUtils.ts\";\n\n/**\n * Wait time after gc() for V8 to stabilize (ms).\n *\n * V8 has 4 compilation tiers: Ignition (interpreter) -> Sparkplug (baseline) ->\n * Maglev (mid-tier optimizer) -> TurboFan (full optimizer). Tiering thresholds:\n * - Ignition -> Sparkplug: 8 invocations\n * - Sparkplug -> Maglev: 500 invocations\n * - Maglev -> TurboFan: 6000 invocations\n *\n * Optimization compilation happens on background threads and requires idle time\n * on the main thread to complete. Without sufficient warmup + settle time,\n * benchmarks exhibit bimodal timing: slow Sparkplug samples (~30% slower) mixed\n * with fast optimized samples.\n *\n * The warmup iterations trigger the optimization decision, then gcSettleTime\n * provides idle time for background compilation to finish before measurement.\n *\n * @see https://v8.dev/blog/sparkplug\n * @see https://v8.dev/blog/maglev\n * @see https://v8.dev/blog/background-compilation\n */\nconst gcSettleTime = 1000;\n\ntype CollectParams<T = unknown> = {\n benchmark: BenchmarkSpec<T>;\n maxTime: number;\n maxIterations: number;\n warmup: number;\n params?: T;\n skipWarmup?: boolean;\n traceOpt?: boolean;\n noSettle?: boolean;\n pauseFirst?: number;\n pauseInterval?: number;\n pauseDuration?: number;\n};\n\ntype CollectResult = {\n samples: number[];\n warmupSamples: number[]; // timing of warmup iterations\n heapGrowth: number; // amortized KB per sample\n heapSamples?: number[]; // heap size per sample (bytes)\n timestamps?: number[]; // wall-clock μs per sample for Perfetto\n optStatus?: OptStatusInfo;\n optSamples?: number[]; // per-sample V8 opt status codes\n pausePoints: PausePoint[]; // where pauses occurred\n};\n\nexport type SampleTimeStats = {\n min: number;\n max: number;\n avg: number;\n p50: number;\n p75: number;\n p99: number;\n p999: number;\n};\n\n/** @return runner with time and iteration limits */\nexport class BasicRunner implements BenchRunner {\n async runBench<T = unknown>(\n benchmark: BenchmarkSpec<T>,\n options: RunnerOptions,\n params?: T,\n ): Promise<MeasuredResults[]> {\n const opts = { ...defaultCollectOptions, ...(options as any) };\n const collected = await collectSamples({ benchmark, params, ...opts });\n return [buildMeasuredResults(benchmark.name, collected)];\n }\n}\n\nconst defaultCollectOptions = {\n maxTime: 5000,\n maxIterations: 1000000,\n warmup: 0,\n traceOpt: false,\n noSettle: false,\n};\n\nfunction buildMeasuredResults(name: string, c: CollectResult): MeasuredResults {\n const time = computeStats(c.samples);\n const convergence = checkConvergence(c.samples.map(s => s * msToNs));\n return {\n name,\n samples: c.samples,\n warmupSamples: c.warmupSamples,\n heapSamples: c.heapSamples,\n timestamps: c.timestamps,\n time,\n heapSize: { avg: c.heapGrowth, min: c.heapGrowth, max: c.heapGrowth },\n convergence,\n optStatus: c.optStatus,\n optSamples: c.optSamples,\n pausePoints: c.pausePoints,\n };\n}\n\n/** @return timing samples and amortized allocation from benchmark execution */\nasync function collectSamples<T>(p: CollectParams<T>): Promise<CollectResult> {\n if (!p.maxIterations && !p.maxTime) {\n throw new Error(`At least one of maxIterations or maxTime must be set`);\n }\n const warmupSamples = p.skipWarmup ? [] : await runWarmup(p);\n const heapBefore = process.memoryUsage().heapUsed;\n const { samples, heapSamples, timestamps, optStatuses, pausePoints } =\n await runSampleLoop(p);\n const heapGrowth =\n Math.max(0, process.memoryUsage().heapUsed - heapBefore) /\n 1024 /\n samples.length;\n if (samples.length === 0) {\n throw new Error(`No samples collected for benchmark: ${p.benchmark.name}`);\n }\n const optStatus = p.traceOpt\n ? analyzeOptStatus(samples, optStatuses)\n : undefined;\n const optSamples =\n p.traceOpt && optStatuses.length > 0 ? optStatuses : undefined;\n return {\n samples,\n warmupSamples,\n heapGrowth,\n heapSamples,\n timestamps,\n optStatus,\n optSamples,\n pausePoints,\n };\n}\n\n/** Run warmup iterations with gc + settle time for V8 optimization */\nasync function runWarmup<T>(p: CollectParams<T>): Promise<number[]> {\n const gc = gcFunction();\n const samples = new Array<number>(p.warmup);\n for (let i = 0; i < p.warmup; i++) {\n const start = performance.now();\n executeBenchmark(p.benchmark, p.params);\n samples[i] = performance.now() - start;\n }\n gc();\n if (!p.noSettle) {\n await new Promise(r => setTimeout(r, gcSettleTime));\n gc();\n }\n return samples;\n}\n\ntype SampleLoopResult = {\n samples: number[];\n heapSamples?: number[];\n timestamps?: number[];\n optStatuses: number[];\n pausePoints: PausePoint[];\n};\n\n/** Estimate sample count for pre-allocation */\nfunction estimateSampleCount(maxTime: number, maxIterations: number): number {\n return maxIterations || Math.ceil(maxTime / 0.1); // assume 0.1ms per iteration minimum\n}\n\ntype SampleArrays = {\n samples: number[];\n timestamps: number[];\n heapSamples: number[];\n optStatuses: number[];\n pausePoints: PausePoint[];\n};\n\n/** Pre-allocate arrays to reduce GC pressure during measurement */\nfunction createSampleArrays(\n n: number,\n trackHeap: boolean,\n trackOpt: boolean,\n): SampleArrays {\n const arr = (track: boolean) => (track ? new Array<number>(n) : []);\n return {\n samples: new Array<number>(n),\n timestamps: new Array<number>(n),\n heapSamples: arr(trackHeap),\n optStatuses: arr(trackOpt),\n pausePoints: [],\n };\n}\n\n/** Trim arrays to actual sample count */\nfunction trimArrays(\n a: SampleArrays,\n count: number,\n trackHeap: boolean,\n trackOpt: boolean,\n): void {\n a.samples.length = a.timestamps.length = count;\n if (trackHeap) a.heapSamples.length = count;\n if (trackOpt) a.optStatuses.length = count;\n}\n\n/** Collect timing samples with periodic pauses for V8 optimization */\nasync function runSampleLoop<T>(\n p: CollectParams<T>,\n): Promise<SampleLoopResult> {\n const {\n maxTime,\n maxIterations,\n pauseFirst,\n pauseInterval = 0,\n pauseDuration = 100,\n } = p;\n const trackHeap = true; // Always track heap for charts\n const getOptStatus = p.traceOpt ? createOptStatusGetter() : undefined;\n const estimated = estimateSampleCount(maxTime, maxIterations);\n const a = createSampleArrays(estimated, trackHeap, !!getOptStatus);\n\n let count = 0;\n let elapsed = 0;\n let totalPauseTime = 0;\n const loopStart = performance.now();\n\n while (\n (!maxIterations || count < maxIterations) &&\n (!maxTime || elapsed < maxTime)\n ) {\n const start = performance.now();\n executeBenchmark(p.benchmark, p.params);\n const end = performance.now();\n a.samples[count] = end - start;\n a.timestamps[count] = Number(process.hrtime.bigint() / 1000n);\n if (trackHeap) a.heapSamples[count] = getHeapStatistics().used_heap_size;\n if (getOptStatus) a.optStatuses[count] = getOptStatus(p.benchmark.fn);\n count++;\n\n if (shouldPause(count, pauseFirst, pauseInterval)) {\n a.pausePoints.push({ sampleIndex: count - 1, durationMs: pauseDuration });\n const pauseStart = performance.now();\n await new Promise(r => setTimeout(r, pauseDuration));\n totalPauseTime += performance.now() - pauseStart;\n }\n elapsed = performance.now() - loopStart - totalPauseTime;\n }\n\n trimArrays(a, count, trackHeap, !!getOptStatus);\n return {\n samples: a.samples,\n heapSamples: trackHeap ? a.heapSamples : undefined,\n timestamps: a.timestamps,\n optStatuses: a.optStatuses,\n pausePoints: a.pausePoints,\n };\n}\n\n/** Check if we should pause at this iteration for V8 optimization */\nfunction shouldPause(\n iter: number,\n first: number | undefined,\n interval: number,\n): boolean {\n if (first !== undefined && iter === first) return true;\n if (interval <= 0) return false;\n if (first === undefined) return iter % interval === 0;\n return (iter - first) % interval === 0;\n}\n\n/** @return percentiles and basic statistics */\nexport function computeStats(samples: number[]): SampleTimeStats {\n const sorted = [...samples].sort((a, b) => a - b);\n const avg = samples.reduce((sum, s) => sum + s, 0) / samples.length;\n return {\n min: sorted[0],\n max: sorted[sorted.length - 1],\n avg,\n p50: percentile(sorted, 0.5),\n p75: percentile(sorted, 0.75),\n p99: percentile(sorted, 0.99),\n p999: percentile(sorted, 0.999),\n };\n}\n\n/** @return percentile value with linear interpolation */\nfunction percentile(sortedArray: number[], p: number): number {\n const index = (sortedArray.length - 1) * p;\n const lower = Math.floor(index);\n const upper = Math.ceil(index);\n const weight = index % 1;\n\n if (upper >= sortedArray.length) return sortedArray[sortedArray.length - 1];\n\n return sortedArray[lower] * (1 - weight) + sortedArray[upper] * weight;\n}\n\n/** @return runtime gc() function, or no-op if unavailable */\nfunction gcFunction(): () => void {\n const gc = globalThis.gc || (globalThis as any).__gc;\n if (gc) return gc;\n console.warn(\"gc() not available, run node/bun with --expose-gc\");\n return () => {};\n}\n\n/** @return function to get V8 optimization status (requires --allow-natives-syntax) */\nfunction createOptStatusGetter(): ((fn: unknown) => number) | undefined {\n try {\n // %GetOptimizationStatus returns a bitmask\n const getter = new Function(\"f\", \"return %GetOptimizationStatus(f)\");\n getter(() => {});\n return getter as (fn: unknown) => number;\n } catch {\n return undefined;\n }\n}\n\n/**\n * V8 optimization status bit meanings:\n * Bit 0 (1): is_function\n * Bit 4 (16): is_optimized (TurboFan)\n * Bit 5 (32): is_optimized (Maglev)\n * Bit 7 (128): is_baseline (Sparkplug)\n * Bit 3 (8): maybe_deoptimized\n */\nconst statusNames: Record<number, string> = {\n 1: \"interpreted\",\n 129: \"sparkplug\", // 1 + 128\n 17: \"turbofan\", // 1 + 16\n 33: \"maglev\", // 1 + 32\n 49: \"turbofan+maglev\", // 1 + 16 + 32\n 32769: \"optimized\", // common optimized status\n};\n\n/** @return analysis of V8 optimization status per sample */\nfunction analyzeOptStatus(\n samples: number[],\n statuses: number[],\n): OptStatusInfo | undefined {\n if (statuses.length === 0 || statuses[0] === undefined) return undefined;\n\n const byStatusCode = new Map<number, number[]>();\n let deoptCount = 0;\n\n for (let i = 0; i < samples.length; i++) {\n const status = statuses[i];\n if (status === undefined) continue;\n\n // Check deopt flag (bit 3)\n if (status & 8) deoptCount++;\n\n if (!byStatusCode.has(status)) byStatusCode.set(status, []);\n byStatusCode.get(status)!.push(samples[i]);\n }\n\n const byTier: Record<string, { count: number; medianMs: number }> = {};\n for (const [status, times] of byStatusCode) {\n const name = statusNames[status] || `status=${status}`;\n const sorted = [...times].sort((a, b) => a - b);\n const median = sorted[Math.floor(sorted.length / 2)];\n byTier[name] = { count: times.length, medianMs: median };\n }\n\n return { byTier, deoptCount };\n}\n","import { BasicRunner } from \"./BasicRunner.ts\";\nimport type { BenchRunner } from \"./BenchRunner.ts\";\n\nexport type KnownRunner = \"basic\";\n\n/** @return benchmark runner */\nexport async function createRunner(\n _runnerName: KnownRunner,\n): Promise<BenchRunner> {\n return new BasicRunner();\n}\n","export const debugWorkerTiming = false;\n\n/** Get current time or 0 if debugging disabled */\nexport function getPerfNow(): number {\n return debugWorkerTiming ? performance.now() : 0;\n}\n\n/** Calculate elapsed milliseconds between marks */\nexport function getElapsed(startMark: number, endMark?: number): number {\n if (!debugWorkerTiming) return 0;\n const end = endMark ?? performance.now();\n return end - startMark;\n}\n"],"mappings":"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"}