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 +31 -38
- package/dist/bin/benchforge.mjs +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.mjs +1 -1
- package/dist/{src-HfimYuW_.mjs → src-Cf_LXwlp.mjs} +29 -5
- package/dist/src-Cf_LXwlp.mjs.map +1 -0
- package/package.json +3 -3
- package/src/cli/CliArgs.ts +14 -3
- package/src/cli/RunBenchCLI.ts +30 -1
- package/src/test/RunBenchCLI.test.ts +25 -0
- package/src/test/fixtures/fn-export-bench.ts +3 -0
- package/src/test/fixtures/suite-export-bench.ts +16 -0
- package/dist/src-HfimYuW_.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -16,39 +16,31 @@ pnpm add benchforge
|
|
|
16
16
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
36
|
-
|
|
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
|
-
###
|
|
32
|
+
### BenchSuite Export
|
|
42
33
|
|
|
43
|
-
|
|
34
|
+
For multiple benchmarks with groups, setup data, and baseline comparison, export a `BenchSuite`:
|
|
44
35
|
|
|
45
36
|
```typescript
|
|
46
|
-
|
|
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:
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
126
|
-
|
|
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
|
|
128
|
+
node --inspect-brk $(which benchforge) my-bench.ts --profile
|
|
136
129
|
|
|
137
130
|
# Use with other profiling tools
|
|
138
|
-
node --prof
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
215
|
+
benchforge my-bench.ts --heap-sample --iterations 100
|
|
223
216
|
|
|
224
217
|
# Smaller interval = more samples = better coverage of rare allocations
|
|
225
|
-
|
|
218
|
+
benchforge my-bench.ts --heap-sample --heap-interval 4096 --iterations 100
|
|
226
219
|
|
|
227
220
|
# Verbose output with clickable file:// paths
|
|
228
|
-
|
|
221
|
+
benchforge my-bench.ts --heap-sample --heap-verbose
|
|
229
222
|
|
|
230
223
|
# Control call stack display depth
|
|
231
|
-
|
|
224
|
+
benchforge my-bench.ts --heap-sample --heap-stack 5
|
|
232
225
|
```
|
|
233
226
|
|
|
234
227
|
**CLI Options:**
|
package/dist/bin/benchforge.mjs
CHANGED
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-
|
|
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.
|
|
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
|
|
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-
|
|
2873
|
+
//# sourceMappingURL=src-Cf_LXwlp.mjs.map
|