benchforge 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,39 +16,31 @@ pnpm add benchforge
16
16
 
17
17
  ## Quick Start
18
18
 
19
- ```typescript
20
- import { parseBenchArgs, runBenchmarks, reportResults, timeSection, runsSection, type BenchSuite } from 'benchforge';
19
+ The simplest way to benchmark a function: export it as the default export and pass the file to `benchforge`.
21
20
 
22
- const suite: BenchSuite = {
23
- name: "String Operations",
24
- groups: [
25
- {
26
- name: "Concatenation",
27
- benchmarks: [
28
- { name: "plus", fn: () => "a" + "b" },
29
- { name: "template", fn: () => `a${"b"}` },
30
- ],
31
- },
32
- ],
33
- };
21
+ ```typescript
22
+ // my-bench.ts
23
+ export default function (): string {
24
+ return "a" + "b";
25
+ }
26
+ ```
34
27
 
35
- const args = parseBenchArgs();
36
- const results = await runBenchmarks(suite, args);
37
- const table = reportResults(results, [timeSection, runsSection]);
38
- console.log(table);
28
+ ```bash
29
+ benchforge my-bench.ts --gc-stats
39
30
  ```
40
31
 
41
- ### Setup and Baseline Example
32
+ ### BenchSuite Export
42
33
 
43
- Here's a more comprehensive example with shared setup data and baseline comparison:
34
+ For multiple benchmarks with groups, setup data, and baseline comparison, export a `BenchSuite`:
44
35
 
45
36
  ```typescript
46
- import { parseBenchArgs, runBenchmarks, defaultReport, type BenchGroup, type BenchSuite } from 'benchforge';
37
+ // sorting.ts
38
+ import type { BenchGroup, BenchSuite } from 'benchforge';
47
39
 
48
40
  const sortingGroup: BenchGroup<number[]> = {
49
41
  name: "Array Sorting (1000 numbers)",
50
42
  setup: () => Array.from({ length: 1000 }, () => Math.random()),
51
- baseline: { name: "native sort", fn: nativeSort },
43
+ baseline: { name: "native sort", fn: (arr) => [...arr].sort((a, b) => a - b) },
52
44
  benchmarks: [
53
45
  { name: "quicksort", fn: quickSort },
54
46
  { name: "insertion sort", fn: insertionSort },
@@ -60,10 +52,11 @@ const suite: BenchSuite = {
60
52
  groups: [sortingGroup],
61
53
  };
62
54
 
63
- const args = parseBenchArgs();
64
- const results = await runBenchmarks(suite, args);
65
- const report = defaultReport(results, args);
66
- console.log(report);
55
+ export default suite;
56
+ ```
57
+
58
+ ```bash
59
+ benchforge sorting.ts --gc-stats
67
60
  ```
68
61
 
69
62
  See `examples/simple-cli.ts` for a complete runnable example.
@@ -122,8 +115,8 @@ This eliminates manual caching boilerplate in worker modules.
122
115
  ### Filter benchmarks by name
123
116
 
124
117
  ```bash
125
- simple-cli.ts --filter "concat"
126
- simple-cli.ts --filter "^parse" --time 2
118
+ benchforge my-bench.ts --filter "concat"
119
+ benchforge my-bench.ts --filter "^parse" --time 2
127
120
  ```
128
121
 
129
122
  ### Profiling with external debuggers
@@ -132,10 +125,10 @@ Use `--profile` to run benchmarks once for attaching external profilers:
132
125
 
133
126
  ```bash
134
127
  # Use with Chrome DevTools profiler
135
- node --inspect-brk simple-cli.ts --profile
128
+ node --inspect-brk $(which benchforge) my-bench.ts --profile
136
129
 
137
130
  # Use with other profiling tools
138
- node --prof simple-cli.ts --profile
131
+ node --prof $(which benchforge) my-bench.ts --profile
139
132
  ```
140
133
 
141
134
  The `--profile` flag executes exactly one iteration with no warmup, making it ideal for debugging and performance profiling.
@@ -172,7 +165,7 @@ The HTML report displays:
172
165
 
173
166
  ```bash
174
167
  # Generate HTML report, start server, and open in browser
175
- simple-cli.ts --html
168
+ benchforge my-bench.ts --html
176
169
  # Press Ctrl+C to exit when done viewing
177
170
  ```
178
171
 
@@ -182,11 +175,11 @@ Export benchmark data as a Perfetto-compatible trace file for detailed analysis:
182
175
 
183
176
  ```bash
184
177
  # Export trace file
185
- simple-cli.ts --perfetto trace.json
178
+ benchforge my-bench.ts --perfetto trace.json
186
179
 
187
180
  # With V8 GC events (automatically merged after exit)
188
181
  node --expose-gc --trace-events-enabled --trace-event-categories=v8,v8.gc \
189
- simple-cli.ts --perfetto trace.json
182
+ benchforge my-bench.ts --perfetto trace.json
190
183
  ```
191
184
 
192
185
  View the trace at https://ui.perfetto.dev by dragging the JSON file.
@@ -203,7 +196,7 @@ Collect detailed garbage collection statistics via V8's `--trace-gc-nvp`:
203
196
 
204
197
  ```bash
205
198
  # Collect GC allocation/collection stats (requires worker mode)
206
- simple-cli.ts --gc-stats
199
+ benchforge my-bench.ts --gc-stats
207
200
  ```
208
201
 
209
202
  Adds these columns to the output table:
@@ -219,16 +212,16 @@ For allocation profiling including garbage (short-lived objects), use `--heap-sa
219
212
 
220
213
  ```bash
221
214
  # Basic heap sampling
222
- simple-cli.ts --heap-sample --iterations 100
215
+ benchforge my-bench.ts --heap-sample --iterations 100
223
216
 
224
217
  # Smaller interval = more samples = better coverage of rare allocations
225
- simple-cli.ts --heap-sample --heap-interval 4096 --iterations 100
218
+ benchforge my-bench.ts --heap-sample --heap-interval 4096 --iterations 100
226
219
 
227
220
  # Verbose output with clickable file:// paths
228
- simple-cli.ts --heap-sample --heap-verbose
221
+ benchforge my-bench.ts --heap-sample --heap-verbose
229
222
 
230
223
  # Control call stack display depth
231
- simple-cli.ts --heap-sample --heap-stack 5
224
+ benchforge my-bench.ts --heap-sample --heap-stack 5
232
225
  ```
233
226
 
234
227
  **CLI Options:**
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { g as runDefaultBench } from "../src-HfimYuW_.mjs";
2
+ import { g as runDefaultBench } from "../src-Cf_LXwlp.mjs";
3
3
 
4
4
  //#region src/bin/benchforge.ts
5
5
  await runDefaultBench();
package/dist/index.d.mts CHANGED
@@ -138,8 +138,10 @@ declare function reportResults<S extends ReadonlyArray<ResultsMapper<any>>>(grou
138
138
  //#endregion
139
139
  //#region src/cli/CliArgs.d.ts
140
140
  type Configure<T> = (yargs: Argv) => Argv<T>;
141
- /** CLI args type inferred from cliOptions */
142
- type DefaultCliArgs = InferredOptionTypes<typeof cliOptions>;
141
+ /** CLI args type inferred from cliOptions, plus optional file positional */
142
+ type DefaultCliArgs = InferredOptionTypes<typeof cliOptions> & {
143
+ file?: string;
144
+ };
143
145
  declare const cliOptions: {
144
146
  readonly time: {
145
147
  readonly type: "number";
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as timeSection, B as parseCliArgs, C as adaptiveSection, D as gcStatsSection, E as gcSection, F as generateHtmlReport, G as truncate, H as formatBytes, I as formatDateWithTimezone, J as loadCaseData, K as isStatefulVariant, L as prepareHtmlData, M as formatConvergence, N as filterMatrix, O as optSection, P as parseMatrixFilter, R as exportPerfettoTrace, S as reportMatrixResults, T as cpuSection, U as integer, V as reportResults, W as timeMs, Y as loadCasesModule, _ as runDefaultMatrixBench, a as cliToMatrixOptions, b as gcStatsColumns, c as exportReports, d as matrixToReportGroups, f as parseBenchArgs, g as runDefaultBench, h as runBenchmarks, i as benchExports, j as totalTimeSection, k as runsSection, l as hasField, m as reportOptStatus, n as getBaselineVersion, o as defaultMatrixReport, p as printHeapReports, q as runMatrix, r as getCurrentGitVersion, s as defaultReport, t as formatGitVersion, u as matrixBenchExports, v as runMatrixSuite, w as buildGenericSections, x as heapTotalColumn, y as gcPauseColumn, z as defaultCliArgs } from "./src-HfimYuW_.mjs";
1
+ import { A as timeSection, B as parseCliArgs, C as adaptiveSection, D as gcStatsSection, E as gcSection, F as generateHtmlReport, G as truncate, H as formatBytes, I as formatDateWithTimezone, J as loadCaseData, K as isStatefulVariant, L as prepareHtmlData, M as formatConvergence, N as filterMatrix, O as optSection, P as parseMatrixFilter, R as exportPerfettoTrace, S as reportMatrixResults, T as cpuSection, U as integer, V as reportResults, W as timeMs, Y as loadCasesModule, _ as runDefaultMatrixBench, a as cliToMatrixOptions, b as gcStatsColumns, c as exportReports, d as matrixToReportGroups, f as parseBenchArgs, g as runDefaultBench, h as runBenchmarks, i as benchExports, j as totalTimeSection, k as runsSection, l as hasField, m as reportOptStatus, n as getBaselineVersion, o as defaultMatrixReport, p as printHeapReports, q as runMatrix, r as getCurrentGitVersion, s as defaultReport, t as formatGitVersion, u as matrixBenchExports, v as runMatrixSuite, w as buildGenericSections, x as heapTotalColumn, y as gcPauseColumn, z as defaultCliArgs } from "./src-Cf_LXwlp.mjs";
2
2
  import { o as average } from "./TimingUtils-ClclVQ7E.mjs";
3
3
 
4
4
  export { adaptiveSection, average, benchExports, buildGenericSections, cliToMatrixOptions, cpuSection, defaultCliArgs, defaultMatrixReport, defaultReport, exportPerfettoTrace, exportReports, filterMatrix, formatBytes, formatConvergence, formatDateWithTimezone, formatGitVersion, gcPauseColumn, gcSection, gcStatsColumns, gcStatsSection, generateHtmlReport, getBaselineVersion, getCurrentGitVersion, hasField, heapTotalColumn, integer, isStatefulVariant, loadCaseData, loadCasesModule, matrixBenchExports, matrixToReportGroups, optSection, parseBenchArgs, parseCliArgs, parseMatrixFilter, prepareHtmlData, printHeapReports, reportMatrixResults, reportOptStatus, reportResults, runBenchmarks, runDefaultBench, runDefaultMatrixBench, runMatrix, runMatrixSuite, runsSection, timeMs, timeSection, totalTimeSection, truncate };
@@ -1,10 +1,10 @@
1
1
  import { a as createAdaptiveWrapper, c as BasicRunner, i as createRunner, l as computeStats, n as getElapsed, o as average, r as getPerfNow, s as bootstrapDifferenceCI, t as debugWorkerTiming, u as discoverVariants } from "./TimingUtils-ClclVQ7E.mjs";
2
2
  import { n as parseGcLine, t as aggregateGcStats } from "./GcStats-ByEovUi1.mjs";
3
3
  import { mkdir, readFile, writeFile } from "node:fs/promises";
4
- import { fileURLToPath } from "node:url";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
5
  import { execSync, fork, spawn } from "node:child_process";
6
6
  import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
7
- import path, { dirname, extname, join, resolve } from "node:path";
7
+ import path, { basename, dirname, extname, join, resolve } from "node:path";
8
8
  import pico from "picocolors";
9
9
  import { table } from "table";
10
10
  import yargs from "yargs";
@@ -944,7 +944,12 @@ const cliOptions = {
944
944
  };
945
945
  /** @return yargs with standard benchmark options */
946
946
  function defaultCliArgs(yargsInstance) {
947
- return yargsInstance.options(cliOptions).help().strict();
947
+ return yargsInstance.command("$0 [file]", "run benchmarks", (y) => {
948
+ y.positional("file", {
949
+ type: "string",
950
+ describe: "benchmark file to run"
951
+ });
952
+ }).options(cliOptions).help().strict();
948
953
  }
949
954
  /** @return parsed command line arguments */
950
955
  function parseCliArgs(args, configure = defaultCliArgs) {
@@ -2559,7 +2564,26 @@ async function runDefaultBench(suite, configureArgs) {
2559
2564
  const args = parseBenchArgs(configureArgs);
2560
2565
  if (args.url) await browserBenchExports(args);
2561
2566
  else if (suite) await benchExports(suite, args);
2562
- else throw new Error("Either --url or a BenchSuite is required.");
2567
+ else if (args.file) await fileBenchExports(args.file, args);
2568
+ else throw new Error("Provide a benchmark file, --url for browser mode, or pass a BenchSuite directly.");
2569
+ }
2570
+ /** Import a file and run it as a benchmark based on what it exports */
2571
+ async function fileBenchExports(filePath, args) {
2572
+ const candidate = (await import(pathToFileURL(resolve(filePath)).href)).default;
2573
+ if (candidate && Array.isArray(candidate.groups)) await benchExports(candidate, args);
2574
+ else if (typeof candidate === "function") {
2575
+ const name = basename(filePath).replace(/\.[^.]+$/, "");
2576
+ await benchExports({
2577
+ name,
2578
+ groups: [{
2579
+ name,
2580
+ benchmarks: [{
2581
+ name,
2582
+ fn: candidate
2583
+ }]
2584
+ }]
2585
+ }, args);
2586
+ }
2563
2587
  }
2564
2588
  /** Convert CLI args to runner options */
2565
2589
  function cliToRunnerOptions(args) {
@@ -2846,4 +2870,4 @@ function getMostRecentModifiedDate(dir) {
2846
2870
 
2847
2871
  //#endregion
2848
2872
  export { timeSection as A, parseCliArgs as B, adaptiveSection as C, gcStatsSection as D, gcSection as E, generateHtmlReport as F, truncate as G, formatBytes as H, formatDateWithTimezone as I, loadCaseData as J, isStatefulVariant as K, prepareHtmlData as L, formatConvergence as M, filterMatrix as N, optSection as O, parseMatrixFilter as P, exportPerfettoTrace as R, reportMatrixResults as S, cpuSection as T, integer as U, reportResults as V, timeMs as W, loadCasesModule as Y, runDefaultMatrixBench as _, cliToMatrixOptions as a, gcStatsColumns as b, exportReports as c, matrixToReportGroups as d, parseBenchArgs as f, runDefaultBench as g, runBenchmarks as h, benchExports as i, totalTimeSection as j, runsSection as k, hasField as l, reportOptStatus as m, getBaselineVersion as n, defaultMatrixReport as o, printHeapReports as p, runMatrix as q, getCurrentGitVersion as r, defaultReport as s, formatGitVersion as t, matrixBenchExports as u, runMatrixSuite as v, buildGenericSections as w, heapTotalColumn as x, gcPauseColumn as y, defaultCliArgs as z };
2849
- //# sourceMappingURL=src-HfimYuW_.mjs.map
2873
+ //# sourceMappingURL=src-Cf_LXwlp.mjs.map