ostia 0.1.7 → 0.2.0
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 +438 -107
- package/chunk-qbt85kmg.js +4 -0
- package/chunk-r5b8vf8w.js +21 -0
- package/cli.js +132 -62
- package/index.d.ts +296 -33
- package/index.js +1 -1
- package/package.json +1 -1
- package/runner.ts +5 -4
- package/chunk-3qbcj1m9.js +0 -21
- package/chunk-zrck2q0b.js +0 -4
package/index.d.ts
CHANGED
|
@@ -1,16 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
export declare function defineConfig(config: Partial<OstiaConfig>): Partial<OstiaConfig>;
|
|
2
|
+
|
|
3
|
+
interface TimeOptions {
|
|
2
4
|
commands: (string | string[])[];
|
|
3
|
-
|
|
5
|
+
/** Exact trial count. When set, `budgetMs` is ignored. */
|
|
6
|
+
samples?: number;
|
|
7
|
+
/** Wall-clock time budget for the sampling loop, ms (default: a
|
|
8
|
+
* hyperfine-style ~3s min-total-time loop when neither `samples` nor
|
|
9
|
+
* `budgetMs` is given). */
|
|
10
|
+
budgetMs?: number;
|
|
11
|
+
/** Hard floor on trials when no exact `samples` count is given. */
|
|
12
|
+
minSamples?: number;
|
|
4
13
|
warmup?: number;
|
|
14
|
+
/** Round-robin trials across commands (one trial per command, repeated)
|
|
15
|
+
* instead of running each command's whole trial loop to completion before
|
|
16
|
+
* the next command starts. Default: true when 2+ commands are given (a
|
|
17
|
+
* single command has nothing to interleave against). Spreads any drift
|
|
18
|
+
* over the run's wall-clock span (thermal throttling, a noisy neighbor
|
|
19
|
+
* process) evenly across every command instead of favoring whichever ran
|
|
20
|
+
* first or last. */
|
|
21
|
+
interleave?: boolean;
|
|
5
22
|
cwd?: string;
|
|
6
23
|
env?: Record<string, string>;
|
|
7
24
|
cpu?: boolean;
|
|
8
25
|
heap?: boolean;
|
|
9
26
|
cpuIntervalUs?: number;
|
|
10
27
|
outDir?: string;
|
|
28
|
+
/** Measure this machine's noise floor before the first command (default:
|
|
29
|
+
* true) and stamp it on the document as `environment`. Set false to skip
|
|
30
|
+
* the ~200ms reference measurement. */
|
|
31
|
+
noiseCheck?: boolean;
|
|
11
32
|
}
|
|
12
33
|
|
|
13
|
-
export declare function
|
|
34
|
+
export declare function time(opts: TimeOptions): Promise<ProfileDocument>;
|
|
14
35
|
|
|
15
36
|
interface ProfileOptions {
|
|
16
37
|
intervalUs?: number;
|
|
@@ -19,13 +40,67 @@ interface ProfileOptions {
|
|
|
19
40
|
|
|
20
41
|
interface ProfileResult<T> {
|
|
21
42
|
result: T;
|
|
22
|
-
|
|
43
|
+
measurement: Measurement;
|
|
44
|
+
document: ProfileDocument;
|
|
23
45
|
}
|
|
24
46
|
|
|
25
47
|
export declare function profile<T>(fn: () => T | Promise<T>, opts?: ProfileOptions): Promise<ProfileResult<T>>;
|
|
26
48
|
|
|
49
|
+
interface WorkloadConfig {
|
|
50
|
+
label?: string;
|
|
51
|
+
command?: string[];
|
|
52
|
+
suites?: string[];
|
|
53
|
+
inputs?: string[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface BenchConfig {
|
|
57
|
+
/** Suite file globs, resolved with Bun.Glob against the config's directory
|
|
58
|
+
* (e.g. "bench/**\/*.bench.ts"). Ignored when suite files are also given
|
|
59
|
+
* on the command line - CLI args replace this list rather than merging
|
|
60
|
+
* with it. */
|
|
61
|
+
suites?: string[];
|
|
62
|
+
preload?: string[];
|
|
63
|
+
jobs?: number | "auto";
|
|
64
|
+
budgetMs?: number;
|
|
65
|
+
samples?: number;
|
|
66
|
+
minSamples?: number;
|
|
67
|
+
gc?: boolean;
|
|
68
|
+
cpu?: boolean;
|
|
69
|
+
alloc?: boolean;
|
|
70
|
+
filter?: string;
|
|
71
|
+
isolate?: boolean;
|
|
72
|
+
outDir?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface OstiaConfig {
|
|
76
|
+
runs: number | null;
|
|
77
|
+
warmup: number;
|
|
78
|
+
outDir: string;
|
|
79
|
+
baselineDir: string;
|
|
80
|
+
baseline: string;
|
|
81
|
+
cpuIntervalUs: number;
|
|
82
|
+
thresholds: Thresholds;
|
|
83
|
+
workloads: WorkloadConfig[];
|
|
84
|
+
bench?: BenchConfig;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
interface Thresholds {
|
|
88
|
+
timingPct: number;
|
|
89
|
+
frameSelfPct: number;
|
|
90
|
+
heapTypePct: number;
|
|
91
|
+
minFrameSelfUs: number;
|
|
92
|
+
/** Significance level for the Mann-Whitney p-value: a `regressed` /
|
|
93
|
+
* `improved` verdict also requires `pValue < alpha`. */
|
|
94
|
+
alpha: number;
|
|
95
|
+
/** Bootstrap resample rounds for the timing CI. Capped work regardless:
|
|
96
|
+
* see `bootstrapMedianDiffCi`. */
|
|
97
|
+
bootstrapIterations: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export declare function compareDocuments(base: ProfileDocument, cand: ProfileDocument, thresholds?: Thresholds): Comparison[];
|
|
101
|
+
|
|
27
102
|
export interface ProfileDocument {
|
|
28
|
-
schemaVersion:
|
|
103
|
+
schemaVersion: 2;
|
|
29
104
|
toolVersion: string;
|
|
30
105
|
bunVersion: string;
|
|
31
106
|
platform: {
|
|
@@ -34,8 +109,41 @@ export interface ProfileDocument {
|
|
|
34
109
|
};
|
|
35
110
|
createdAt: string;
|
|
36
111
|
workloads: Workload[];
|
|
37
|
-
|
|
112
|
+
measurements: Measurement[];
|
|
38
113
|
comparisons?: Comparison[];
|
|
114
|
+
/** Machine conditions when this document was measured. Additive, no
|
|
115
|
+
* schema bump. Absent when `noiseCheck: false` (or `--no-noise-check`)
|
|
116
|
+
* skipped the reference measurement. */
|
|
117
|
+
environment?: Environment;
|
|
118
|
+
/** Repo state when this document was measured, from `git rev-parse` /
|
|
119
|
+
* `git status --porcelain` in the process's cwd. Additive, no schema
|
|
120
|
+
* bump. Absent outside a git repo (or when `git` itself isn't
|
|
121
|
+
* available). Metadata only: never part of any fingerprint or id, so a
|
|
122
|
+
* commit or a dirty working tree never orphans a cached run or baseline. */
|
|
123
|
+
git?: GitMetadata;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interface GitMetadata {
|
|
127
|
+
sha: string;
|
|
128
|
+
branch: string;
|
|
129
|
+
dirty: boolean;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface NoiseFloor {
|
|
133
|
+
/** `mad / median` of the reference workload's trial times, as a percent -
|
|
134
|
+
* how noisy this machine is right now, independent of what's being
|
|
135
|
+
* measured. */
|
|
136
|
+
floorPct: number;
|
|
137
|
+
referenceMedianNs: number;
|
|
138
|
+
samples: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
interface Environment {
|
|
142
|
+
cpuModel: string;
|
|
143
|
+
cores: number;
|
|
144
|
+
loadAvg1: number;
|
|
145
|
+
loadAvg5: number;
|
|
146
|
+
noise: NoiseFloor;
|
|
39
147
|
}
|
|
40
148
|
|
|
41
149
|
export interface Workload {
|
|
@@ -67,11 +175,23 @@ export interface Workload {
|
|
|
67
175
|
* on the task, its group, or the suite), vs. sharing its suite file's
|
|
68
176
|
* subprocess with other tasks. */
|
|
69
177
|
isolated?: boolean;
|
|
178
|
+
/** Structured parameters this task point represents (e.g. `{ size: 800,
|
|
179
|
+
* impl: "fast" }`), from `task(name, fn, { params })` or a `sweep()` point.
|
|
180
|
+
* Lets renderers pivot and `compare` match on them instead of only on the
|
|
181
|
+
* task name. Part of the workload id when present, so two points that
|
|
182
|
+
* share a task name (a `sweep()`'s whole point) don't collide. */
|
|
183
|
+
params?: Record<string, string | number | boolean>;
|
|
184
|
+
/** From `task.skip()` or a `group.skip()` this task was inside. The runner
|
|
185
|
+
* never measures it, so this workload has no matching `Measurement`; a
|
|
186
|
+
* renderer prints it as a "- skipped" row instead of omitting it, and
|
|
187
|
+
* `compare` treats it as `unchanged` (with a `skipped` warning) rather
|
|
188
|
+
* than silently passing or failing to match it. */
|
|
189
|
+
skipped?: boolean;
|
|
70
190
|
}
|
|
71
191
|
|
|
72
192
|
type Phase = "timing" | "cpu" | "heap" | "memstats";
|
|
73
193
|
|
|
74
|
-
interface
|
|
194
|
+
interface Measurement {
|
|
75
195
|
id: string;
|
|
76
196
|
workloadId: string;
|
|
77
197
|
phase: Phase;
|
|
@@ -86,7 +206,14 @@ interface Run {
|
|
|
86
206
|
jit?: JitTierBreakdown;
|
|
87
207
|
warnings: Warning[];
|
|
88
208
|
artifacts: ArtifactRef[];
|
|
89
|
-
|
|
209
|
+
baselineMeasurementId?: string;
|
|
210
|
+
/** True when this timing measurement's trials were run round-robin against
|
|
211
|
+
* the other commands in the same `time()` call (`--interleave`, default on
|
|
212
|
+
* for 2+ commands) rather than run to completion before the next command
|
|
213
|
+
* started, so drift over the run's wall-clock span (thermal throttling, a
|
|
214
|
+
* noisy neighbor process) lands on every command equally instead of
|
|
215
|
+
* favoring whichever ran first or last. */
|
|
216
|
+
interleaved?: boolean;
|
|
90
217
|
}
|
|
91
218
|
|
|
92
219
|
interface Trial {
|
|
@@ -110,6 +237,15 @@ interface TimingStats {
|
|
|
110
237
|
mild: number;
|
|
111
238
|
severe: number;
|
|
112
239
|
};
|
|
240
|
+
/** 75th percentile, ns. Optional: absent on documents saved before this
|
|
241
|
+
* field existed (`loadDocument` never backfills it). */
|
|
242
|
+
p75?: number;
|
|
243
|
+
/** 99th percentile, ns. Same caveat as `p75`. */
|
|
244
|
+
p99?: number;
|
|
245
|
+
/** Median absolute deviation, ns: the median of `|sample - median|` across
|
|
246
|
+
* all samples. A robust spread measure that (unlike stddev) isn't skewed
|
|
247
|
+
* by the long right tail typical of wall-clock timings. */
|
|
248
|
+
mad?: number;
|
|
113
249
|
}
|
|
114
250
|
|
|
115
251
|
interface Frame {
|
|
@@ -166,6 +302,11 @@ interface MemoryEvidence {
|
|
|
166
302
|
maxRssBytes?: number;
|
|
167
303
|
peakCommitBytes?: number;
|
|
168
304
|
pageFaults?: number;
|
|
305
|
+
/** Bytes allocated per call, from `ostia bench --alloc`: heap size delta
|
|
306
|
+
* (`bun:jsc`'s `heapStats().heapSize`, falling back to
|
|
307
|
+
* `process.memoryUsage().heapUsed`) around one `Bun.gc(true)`-bracketed
|
|
308
|
+
* batch, divided by the batch size. */
|
|
309
|
+
bytesPerOp?: number;
|
|
169
310
|
}
|
|
170
311
|
|
|
171
312
|
interface JitTierBreakdown {
|
|
@@ -183,7 +324,7 @@ interface JitTierBreakdown {
|
|
|
183
324
|
}[];
|
|
184
325
|
}
|
|
185
326
|
|
|
186
|
-
export type WarningCode = "slow-first-run" | "outliers-detected" | "fast-command" | "nonzero-exit" | "instrumented-timing" | "artifact-missing" | "empty-profile" | "below-timer-resolution" | "cache-fallback-rerun" | "low-sample-count";
|
|
327
|
+
export type WarningCode = "slow-first-run" | "outliers-detected" | "fast-command" | "nonzero-exit" | "instrumented-timing" | "artifact-missing" | "empty-profile" | "below-timer-resolution" | "cache-fallback-rerun" | "low-sample-count" | "thin-comparison" | "noisy-machine" | "skipped" | "jit-cold";
|
|
187
328
|
|
|
188
329
|
export interface Warning {
|
|
189
330
|
code: WarningCode;
|
|
@@ -201,13 +342,28 @@ interface ArtifactRef {
|
|
|
201
342
|
|
|
202
343
|
interface Comparison {
|
|
203
344
|
id: string;
|
|
204
|
-
|
|
205
|
-
|
|
345
|
+
baselineMeasurementId: string;
|
|
346
|
+
candidateMeasurementId: string;
|
|
206
347
|
timing?: {
|
|
207
348
|
medianDeltaPct: number;
|
|
208
349
|
meanDeltaPct: number;
|
|
350
|
+
/** Same value as `medianDeltaPct`, named for what it is used for: the
|
|
351
|
+
* effect size the verdict rule tests against `thresholds.timingPct`. */
|
|
352
|
+
effectPct: number;
|
|
353
|
+
/** 95% bootstrap confidence interval on the difference of medians,
|
|
354
|
+
* percent of the baseline median. Absent when either side had fewer
|
|
355
|
+
* than 5 samples (see the `thin-comparison` warning). */
|
|
356
|
+
ci95?: [number, number];
|
|
357
|
+
/** Two-sided Mann-Whitney U p-value, tie-corrected normal approximation.
|
|
358
|
+
* Same absence condition as `ci95`. */
|
|
359
|
+
pValue?: number;
|
|
360
|
+
/** Seed for the bootstrap's PRNG, so `ci95` is reproducible. */
|
|
361
|
+
seed?: number;
|
|
209
362
|
verdict: "improved" | "regressed" | "unchanged";
|
|
210
363
|
};
|
|
364
|
+
/** Attached when timing fell back to the point-estimate rule (thin
|
|
365
|
+
* samples) or otherwise carries a caveat about this comparison. */
|
|
366
|
+
warnings?: Warning[];
|
|
211
367
|
frames?: {
|
|
212
368
|
frameKey: string;
|
|
213
369
|
name: string;
|
|
@@ -228,15 +384,37 @@ interface Comparison {
|
|
|
228
384
|
frameSelfPct: number;
|
|
229
385
|
heapTypePct: number;
|
|
230
386
|
minFrameSelfUs: number;
|
|
387
|
+
alpha: number;
|
|
388
|
+
bootstrapIterations: number;
|
|
389
|
+
/** `max(timingPct, base.environment.noise.floorPct,
|
|
390
|
+
* cand.environment.noise.floorPct)` - the threshold timing was actually
|
|
391
|
+
* tested against, once machine noise widens it past `timingPct`. */
|
|
392
|
+
effectiveTimingPct: number;
|
|
231
393
|
};
|
|
232
394
|
verdict: "pass" | "fail";
|
|
233
395
|
}
|
|
234
396
|
|
|
397
|
+
export declare function keep(value: unknown): void;
|
|
398
|
+
|
|
235
399
|
interface BenchOptions {
|
|
236
400
|
suites: string[];
|
|
237
|
-
|
|
401
|
+
/** Wall-clock sampling budget per task, ms (default 500). */
|
|
402
|
+
budgetMs?: number;
|
|
403
|
+
/** Exact trial count per task. When set, the budget is ignored - the
|
|
404
|
+
* in-process equivalent of `time()`'s `samples`. */
|
|
405
|
+
samples?: number;
|
|
238
406
|
minSamples?: number;
|
|
239
407
|
gc?: boolean;
|
|
408
|
+
/** Capture one extra `phase: "cpu"` measurement per task (200ms of the
|
|
409
|
+
* task looped under the JSC sampling profiler, JIT tiers included), never
|
|
410
|
+
* mixed into the timing numbers. `TaskOptions.cpu` / `GroupOptions.cpu`
|
|
411
|
+
* override this per task or group. */
|
|
412
|
+
cpu?: boolean;
|
|
413
|
+
/** Capture one extra `phase: "memstats"` measurement per task: bytes
|
|
414
|
+
* allocated per call, from a `Bun.gc(true)`-bracketed batch.
|
|
415
|
+
* `TaskOptions.alloc` / `GroupOptions.alloc` override this per task or
|
|
416
|
+
* group. */
|
|
417
|
+
alloc?: boolean;
|
|
240
418
|
filter?: string;
|
|
241
419
|
/** Suite files to run at once, each still in its own child process (default:
|
|
242
420
|
* 1). Files are independent by design, so this is a wall-clock win for
|
|
@@ -270,27 +448,27 @@ interface BenchOptions {
|
|
|
270
448
|
* resolution condition Bun doesn't set by default (e.g. Svelte/Vue's
|
|
271
449
|
* `browser` vs `default` builds). */
|
|
272
450
|
bunFlags?: string[];
|
|
451
|
+
/** Measure this machine's noise floor before the first task per suite
|
|
452
|
+
* subprocess (default: true) and stamp it on the document as
|
|
453
|
+
* `environment`. Set false to skip the ~200ms reference measurement. */
|
|
454
|
+
noiseCheck?: boolean;
|
|
273
455
|
}
|
|
274
456
|
|
|
275
457
|
export declare function bench(opts: BenchOptions): Promise<ProfileDocument>;
|
|
276
458
|
|
|
277
|
-
interface Thresholds {
|
|
278
|
-
timingPct: number;
|
|
279
|
-
frameSelfPct: number;
|
|
280
|
-
heapTypePct: number;
|
|
281
|
-
minFrameSelfUs: number;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
export declare function compareDocuments(base: ProfileDocument, cand: ProfileDocument, thresholds?: Thresholds): Comparison[];
|
|
285
|
-
|
|
286
459
|
export declare function range(start: number, end: number, multiplier?: number): number[];
|
|
287
460
|
|
|
461
|
+
type Hook = () => unknown | Promise<unknown>;
|
|
462
|
+
|
|
288
463
|
export interface TaskOptions {
|
|
289
464
|
/** Marks this task as the Relative reference for its group in the table
|
|
290
465
|
* renderer, mirroring mitata's `baseline()`. At most one per group. */
|
|
291
466
|
baseline?: boolean;
|
|
292
|
-
/** Per-task time budget; overrides the suite-wide `--
|
|
293
|
-
|
|
467
|
+
/** Per-task time budget; overrides the suite-wide `--budget` / `budgetMs`. */
|
|
468
|
+
budgetMs?: number;
|
|
469
|
+
/** Per-task exact trial count; overrides the suite-wide `--samples` /
|
|
470
|
+
* `samples`. When set, the budget is ignored for this task. */
|
|
471
|
+
samples?: number;
|
|
294
472
|
/** Per-task hard floor on trials; overrides the suite-wide `--min-samples` /
|
|
295
473
|
* `minSamples`. */
|
|
296
474
|
minSamples?: number;
|
|
@@ -305,6 +483,30 @@ export interface TaskOptions {
|
|
|
305
483
|
/** Overrides the suite-wide `bench({ gc })` / `--gc` (and any
|
|
306
484
|
* `GroupOptions.gc`) for this task only. */
|
|
307
485
|
gc?: boolean;
|
|
486
|
+
/** Overrides the suite-wide `bench({ cpu })` / `--cpu` (and any
|
|
487
|
+
* `GroupOptions.cpu`) for this task only: after the timing measurement,
|
|
488
|
+
* capture one extra `phase: "cpu"` measurement (JIT tiers included) on
|
|
489
|
+
* the same workload, never mixed into the timing numbers. */
|
|
490
|
+
cpu?: boolean;
|
|
491
|
+
/** Overrides the suite-wide `bench({ alloc })` / `--alloc` (and any
|
|
492
|
+
* `GroupOptions.alloc`) for this task only: after the timing measurement,
|
|
493
|
+
* capture one extra `phase: "memstats"` measurement with bytes
|
|
494
|
+
* allocated per call. */
|
|
495
|
+
alloc?: boolean;
|
|
496
|
+
/** Structured parameters this task represents (e.g. `{ size: 800, impl:
|
|
497
|
+
* "fast" }`), written to `Workload.params` and folded into the workload id
|
|
498
|
+
* so points with the same task name don't collide. Inside `sweep()`, the
|
|
499
|
+
* current point is inherited automatically; an explicit `params` here
|
|
500
|
+
* merges over it (explicit keys win). */
|
|
501
|
+
params?: Record<string, string | number | boolean>;
|
|
502
|
+
/** Runs once, unmeasured, immediately before this task's warmup - in the
|
|
503
|
+
* task's own process, so it works with `isolate`. No per-trial hook: that
|
|
504
|
+
* would defeat batching. Use `gc` (Bun.gc between trials) or `isolate`
|
|
505
|
+
* (a fresh process per task) for per-trial concerns instead. */
|
|
506
|
+
before?: Hook;
|
|
507
|
+
/** Runs once, unmeasured, immediately after this task's last trial. Same
|
|
508
|
+
* process/no-per-trial caveats as `before`. */
|
|
509
|
+
after?: Hook;
|
|
308
510
|
}
|
|
309
511
|
|
|
310
512
|
export interface GroupOptions {
|
|
@@ -317,11 +519,57 @@ export interface GroupOptions {
|
|
|
317
519
|
/** Default `gc` for every task in this group, unless a task overrides it
|
|
318
520
|
* with its own `TaskOptions.gc`. */
|
|
319
521
|
gc?: boolean;
|
|
522
|
+
/** Default `cpu` for every task in this group, unless a task overrides it
|
|
523
|
+
* with its own `TaskOptions.cpu`. */
|
|
524
|
+
cpu?: boolean;
|
|
525
|
+
/** Default `alloc` for every task in this group, unless a task overrides
|
|
526
|
+
* it with its own `TaskOptions.alloc`. */
|
|
527
|
+
alloc?: boolean;
|
|
528
|
+
/** Runs once, unmeasured, before the group's first task's warmup (not
|
|
529
|
+
* before every task) - in whichever process runs that task, so it works
|
|
530
|
+
* with `isolate`. */
|
|
531
|
+
before?: Hook;
|
|
532
|
+
/** Runs once, unmeasured, after the group's last task's last trial. */
|
|
533
|
+
after?: Hook;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
interface GroupFn {
|
|
537
|
+
(name: string, fn: () => void, opts?: GroupOptions): void;
|
|
538
|
+
/** Registers every task inside as skipped: the runner never measures
|
|
539
|
+
* them, but the document still carries their workloads (marked
|
|
540
|
+
* `Workload.skipped`). */
|
|
541
|
+
skip: (name: string, fn: () => void, opts?: GroupOptions) => void;
|
|
542
|
+
/** When any task or group in the suite uses `.only`, the runner restricts
|
|
543
|
+
* the whole suite file to only those tasks (before `--filter` narrows
|
|
544
|
+
* further) and prints a one-line notice to stderr. */
|
|
545
|
+
only: (name: string, fn: () => void, opts?: GroupOptions) => void;
|
|
320
546
|
}
|
|
321
547
|
|
|
322
|
-
export declare
|
|
548
|
+
export declare const group: GroupFn;
|
|
549
|
+
|
|
550
|
+
interface TaskFn {
|
|
551
|
+
(name: string, fn: () => unknown | Promise<unknown>, opts?: TaskOptions): void;
|
|
552
|
+
/** Registers the task as skipped: the runner never measures it, but the
|
|
553
|
+
* document still carries its workload (marked `Workload.skipped`) so a
|
|
554
|
+
* renderer or `compare` can say so explicitly instead of the task simply
|
|
555
|
+
* being absent. */
|
|
556
|
+
skip: (name: string, fn: () => unknown | Promise<unknown>, opts?: TaskOptions) => void;
|
|
557
|
+
/** When any task or group in the suite uses `.only`, the runner restricts
|
|
558
|
+
* the whole suite file to only those tasks (before `--filter` narrows
|
|
559
|
+
* further) and prints a one-line notice to stderr. */
|
|
560
|
+
only: (name: string, fn: () => unknown | Promise<unknown>, opts?: TaskOptions) => void;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
export declare const task: TaskFn;
|
|
564
|
+
|
|
565
|
+
type SweepPoint<T extends Record<string, readonly unknown[]>> = {
|
|
566
|
+
[K in keyof T]: T[K][number];
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
export declare function sweep<T extends Record<string, readonly unknown[]>>(dims: T, fn: (point: SweepPoint<T>) => void): void;
|
|
323
570
|
|
|
324
|
-
export declare function
|
|
571
|
+
export declare function newDocument(workloads: Workload[], measurements: Measurement[], environment?: Environment): ProfileDocument;
|
|
572
|
+
export { newDocument as createDocument };
|
|
325
573
|
|
|
326
574
|
export declare function saveDocument(doc: ProfileDocument, path: string): Promise<void>;
|
|
327
575
|
|
|
@@ -349,14 +597,24 @@ export interface MinimalLine {
|
|
|
349
597
|
group?: string;
|
|
350
598
|
description?: string;
|
|
351
599
|
groupDescription?: string;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
600
|
+
/** From `task(name, fn, { params })` or a `sweep()` point. */
|
|
601
|
+
params?: Record<string, string | number | boolean>;
|
|
602
|
+
/** From `task.skip()` / `group.skip()`: no measurement was taken, so every
|
|
603
|
+
* stats field below is absent on this line. */
|
|
604
|
+
skipped?: true;
|
|
605
|
+
unit?: "ns";
|
|
606
|
+
samples?: number;
|
|
607
|
+
mean?: number;
|
|
608
|
+
median?: number;
|
|
609
|
+
stddev?: number;
|
|
610
|
+
stddevPct?: number;
|
|
611
|
+
min?: number;
|
|
612
|
+
max?: number;
|
|
613
|
+
/** 75th/99th percentile and median absolute deviation, ns. Absent on
|
|
614
|
+
* documents saved before these fields existed. */
|
|
615
|
+
p75?: number;
|
|
616
|
+
p99?: number;
|
|
617
|
+
mad?: number;
|
|
360
618
|
/** Median over the group's reference median (its baseline task, else its
|
|
361
619
|
* fastest). Only present when the document has more than one timing run. */
|
|
362
620
|
relative?: number;
|
|
@@ -372,5 +630,10 @@ export interface MinimalLine {
|
|
|
372
630
|
meanPct: number;
|
|
373
631
|
verdict: "improved" | "regressed" | "unchanged";
|
|
374
632
|
pass: boolean;
|
|
633
|
+
/** 95% bootstrap CI on the difference of medians and the Mann-Whitney
|
|
634
|
+
* p-value behind the verdict. Absent on a thin (<5 samples/side)
|
|
635
|
+
* comparison, which falls back to a point-estimate threshold. */
|
|
636
|
+
ci95?: [number, number];
|
|
637
|
+
pValue?: number;
|
|
375
638
|
};
|
|
376
639
|
}
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{c,b,_,L,s,H,R,J}from"./chunk-r5b8vf8w.js";import{n,r,t,x,V,G}from"./chunk-qbt85kmg.js";export{c as bench,b as compareDocuments,n as createDocument,H as defineConfig,V as group,x as keep,t as loadDocument,J as profile,_ as range,s as renderers,r as saveDocument,L as sweep,G as task,R as time};
|
package/package.json
CHANGED
package/runner.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{
|
|
4
|
-
`),2;let
|
|
5
|
-
`),2;let
|
|
6
|
-
`),
|
|
3
|
+
import{n,N,i,a,o,r,d,f,g,F,O,B,h,C,U,W,A,j}from"./chunk-qbt85kmg.js";import{heapStats as X}from"bun:jsc";var Y=100;function z(){try{return X().heapSize}catch{return process.memoryUsage().heapUsed}}async function Z(l,m=Y){let w=Bun.nanoseconds();Bun.gc(!0);let t=z();for(let u=0;u<m;u++){let p=l();if(p instanceof Promise)await p}Bun.gc(!0);let k=z(),c=Bun.nanoseconds()-w;return{memory:{origin:"heapStats",bytesPerOp:Math.max(0,(k-t)/m)},diagnosticWallNs:c}}var ee=200,te=20;async function q(l,m=ee){let w=m*1e6,t=async()=>{let p=Bun.nanoseconds();while(Bun.nanoseconds()-p<w){let b=l();if(b instanceof Promise)await b}},{cpu:k,jit:c,diagnosticWallNs:u}=await d(t);return{cpu:k,jit:c,diagnosticWallNs:u}}function K(l){let{llint:m,baseline:w,dfg:t,ftl:k}=l.tiers,c=m+w+t+k;if(c===0)return;let u=m/c*100,p=w/c*100,b=t/c*100,x=k/c*100;if(u+p<=te)return;return{code:"jit-cold",message:`${(u+p).toFixed(1)}% of CPU samples were in the llint/baseline tiers: the JIT never warmed this task up.`,data:{llintPct:u,baselinePct:p,dfgPct:b,ftlPct:x}}}async function ne(){let[l,m,w]=process.argv.slice(2);if(!l||!m)return process.stderr.write(`bench runner: usage: runner.ts <suiteFile> <outputPath> [optsJson]
|
|
4
|
+
`),2;let t=w?JSON.parse(w):{};for(let s of t.preload??[])await import(s);B(),await import(l);let k=O();if(k.length===0)return process.stderr.write(`bench runner: ${l} registered no tasks (no task() calls found).
|
|
5
|
+
`),2;let c=k.filter((s)=>s.only),u=c.length>0?c:k;if(c.length>0)process.stderr.write(`bench: ${c.length} task(s) selected by .only
|
|
6
|
+
`);let p=j(u,t.filter);if(t.taskIds){let s=new Set(t.taskIds);p=p.filter((e)=>s.has(h(e)))}if(p.length===0)return process.stderr.write(`bench runner: --filter ${JSON.stringify(t.filter)} matched zero of ${u.length} registered task(s) in ${l}.
|
|
7
|
+
`),2;if(t.planPath){let s=p.map((e)=>({id:h(e),isolate:C(e,t.isolate??!1)}));await Bun.write(t.planPath,JSON.stringify({tasks:s}))}let b=t.taskIds?p:p.filter((s)=>!C(s,t.isolate??!1)),S=b.some((s)=>!s.skipped)&&t.noiseCheck!==!1?f():void 0,R=S?g(S):void 0,v=new Map,E=new Map;b.forEach((s,e)=>{if(s.groupName===void 0||s.skipped)return;if(!v.has(s.groupName))v.set(s.groupName,e);E.set(s.groupName,e)});let J=[],P=[];for(let s=0;s<b.length;s++){let e=b[s],D=h(e),I=N(l,D,{label:D,baseline:e.baseline,group:e.groupName,description:e.opts?.description,groupDescription:e.groupDescription,isolated:t.markIsolated,params:e.params,skipped:e.skipped});if(J.push(I),e.skipped)continue;let Q=e.groupName!==void 0&&v.get(e.groupName)===s,V=e.groupName!==void 0&&E.get(e.groupName)===s;if(Q&&e.groupBefore)await e.groupBefore();if(e.opts?.before)await e.opts.before();let _=e.opts?.budgetMs??t.budgetMs,L=e.opts?.samples??t.samples,H=e.opts?.minSamples??t.minSamples,T={...t,..._!==void 0&&{budgetMs:_},...L!==void 0&&{samples:L},...H!==void 0&&{minSamples:H},gc:U(e,t.gc??!1)},M=await F(e.fn,T);if(P.push(i({workload:I,configFingerprint:o({budgetMs:T.budgetMs??null,samples:T.samples??null,minSamples:T.minSamples??null,gc:T.gc??!1}),trials:M.trials,timing:M.timing,warnings:R&&P.length===0?[...M.warnings,R]:M.warnings})),W(e,t.cpu??!1)){let y=await q(e.fn),G=K(y.jit);P.push(a({workload:I,phase:"cpu",configFingerprint:o({cpu:!0}),diagnosticWallNs:y.diagnosticWallNs,cpu:y.cpu,jit:y.jit,warnings:G?[G]:[],artifacts:[]}))}if(A(e,t.alloc??!1)){let y=await Z(e.fn);P.push(a({workload:I,phase:"memstats",configFingerprint:o({alloc:!0}),diagnosticWallNs:y.diagnosticWallNs,memory:y.memory,warnings:[],artifacts:[]}))}if(e.opts?.after)await e.opts.after();if(V&&e.groupAfter)await e.groupAfter()}return await r(n(J,P,S),m),0}ne().then((l)=>process.exit(l));
|
package/chunk-3qbcj1m9.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{h,e,r,u,T,i,b,I,s,x,t,l,p}from"./chunk-zrck2q0b.js";function Le(o){return o.startsWith("file://")?o.slice(7):o}function ae(o,U,c){let R=o.nodes,m=R.length,C=new Map,N=[],v=new Map,D=new Int32Array(m);for(let A=0;A<m;A++){let F=R[A],M=F.callFrame,H=Le(M.url),Y=C.get(M.functionName);if(Y===void 0)Y=new Map,C.set(M.functionName,Y);let q=Y.get(H);if(q===void 0)q=N.length,Y.set(H,q),N.push({key:e("fr",M.functionName,H),name:M.functionName,url:H||void 0,line:M.lineNumber>=0?M.lineNumber:void 0,col:M.columnNumber>=0?M.columnNumber:void 0});D[A]=q,v.set(F.id,A)}let W=Array(m);for(let A=0;A<m;A++){let F=R[A];W[A]={id:F.id,frameIx:D[v.get(F.id)],children:F.children??[]}}let O=new Float64Array(m),E=new Float64Array(m),{samples:j,timeDeltas:z}=o;for(let A=0;A<j.length;A++){let F=v.get(j[A]);if(F===void 0)continue;O[F]+=z[A]??0,E[F]+=1}let V=new Int32Array(m).fill(-1);for(let A=0;A<m;A++){let F=R[A].children;if(!F)continue;for(let M of F){let H=v.get(M);if(H!==void 0)V[H]=A}}let _=[],J=[];for(let A=m-1;A>=0;A--)if(V[A]===-1)J.push(A);while(J.length>0){let A=J.pop();_.push(A);let F=R[A].children;if(!F)continue;for(let M of F){let H=v.get(M);if(H!==void 0&&V[H]===A)J.push(H)}}let K=new Float64Array(m);for(let A=_.length-1;A>=0;A--){let F=_[A];K[F]+=O[F];let M=V[F];if(M>=0)K[M]+=K[F]}let G=Array(N.length),L=[];for(let A=0;A<m;A++){let F=W[A].frameIx,M=G[F];if(M)M.selfUs+=O[A],M.totalUs+=K[A],M.samples+=E[A];else{let H={frameIx:F,selfUs:O[A],totalUs:K[A],samples:E[A]};G[F]=H,L.push(H)}}return{origin:U,samplingIntervalUs:c,frames:N,nodes:W,totals:L.sort((A,F)=>F.selfUs-A.selfUs),samples:{nodeIds:o.samples,timeDeltasUs:o.timeDeltas}}}function He(o,U,c,R){let m=["--cpu-prof","--cpu-prof-dir",U,"--cpu-prof-name",c,"--cpu-prof-interval",String(R)],C=o[0];if(C==="bun"||C?.endsWith("/bun"))return[C,...m,...o.slice(1)];return o}async function ge(o){let U=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],R=c==="bun"||c?.endsWith("/bun"),m=He(o.argv,o.artifactDir,o.fileName,o.intervalUs),C=R?o.env:{...process.env,...o.env,BUN_OPTIONS:`--cpu-prof --cpu-prof-dir ${o.artifactDir} --cpu-prof-name ${o.fileName} --cpu-prof-interval ${o.intervalUs}`},N=Bun.nanoseconds(),D=await Bun.spawn(m,{cwd:o.cwd,env:C,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,W=Bun.nanoseconds()-N,O=Bun.file(U);if(!await O.exists())return{diagnosticWallNs:W,exitCode:D,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${U} after exit ${D}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:U,argv:o.argv}}]};let E=await O.json(),j=ae(E,"cpu-prof",o.intervalUs),z=E.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:W,exitCode:D,artifactPath:U,cpu:j,warnings:z}}function he(o,U="heap-prof"){let{node_fields:c,node_types:R}=o.snapshot.meta,m=c.indexOf("type"),C=c.indexOf("self_size"),N=c.length,v=R[0];if(m===-1||C===-1||!Array.isArray(v))return{origin:U,typeCounts:[],objectCount:o.snapshot.node_count};let D=v.length,W=Array(D),O=new Map,E=[],j=0,z=o.nodes,V=z.length;for(let L=0;L<V;L+=N){let A=z[L+m],F=z[L+C]??0;j+=F;let M;if(A>=0&&A<D){if(M=W[A],M===void 0)M={type:v[A],count:0,bytes:0},W[A]=M,E.push(M)}else{let H=`unknown(${A})`;if(M=O.get(H),M===void 0)M={type:H,count:0,bytes:0},O.set(H,M),E.push(M)}M.count++,M.bytes+=F}let _=E.sort((L,A)=>A.count-L.count),J=_.slice(0,20),K=_.slice(20),G=J.map(({type:L,count:A,bytes:F})=>({type:L,count:A,retainedBytes:F}));if(K.length>0){let L=0,A=0;for(let F of K)L+=F.count,A+=F.bytes;G.push({type:"other",count:L,retainedBytes:A})}return{origin:U,heapSizeBytes:j,objectCount:o.snapshot.node_count,typeCounts:G}}function Je(o,U,c){let R=["--heap-prof","--heap-prof-dir",U,"--heap-prof-name",c],m=o[0];if(m==="bun"||m?.endsWith("/bun"))return[m,...R,...o.slice(1)];return o}async function be(o){let U=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],R=c==="bun"||c?.endsWith("/bun"),m=Je(o.argv,o.artifactDir,o.fileName),C=R?o.env:{...process.env,...o.env,BUN_OPTIONS:`--heap-prof --heap-prof-dir ${o.artifactDir} --heap-prof-name ${o.fileName}`},N=Bun.nanoseconds(),D=await Bun.spawn(m,{cwd:o.cwd,env:C,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,W=Bun.nanoseconds()-N,O=Bun.file(U);if(!await O.exists())return{diagnosticWallNs:W,exitCode:D,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${U} after exit ${D}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:U,argv:o.argv}}]};let E=await O.json(),j=he(E,"heap-prof");return{diagnosticWallNs:W,exitCode:D,artifactPath:U,heap:j,warnings:[]}}import{Session as ze}from"inspector/promises";var Ve=1000;async function ye(o,U={}){let c=U.intervalUs??Ve,R=new ze;R.connect();let m=Bun.nanoseconds();try{await R.post("Profiler.enable"),await R.post("Profiler.setSamplingInterval",{interval:c}),await R.post("Profiler.start");let C=await o(),{profile:N}=await R.post("Profiler.stop"),v=Bun.nanoseconds()-m,D=ae(N,"inspector",c);return{result:C,cpu:D,diagnosticWallNs:v}}finally{R.disconnect()}}import{profile as Ge}from"bun:jsc";var Ke=new Map([["LLInt","llint"],["Baseline","baseline"],["DFG","dfg"],["FTL","ftl"]]),we=4294967295;function xe(o,U){let c=U??o.interval*1e6,R=new Map,m=[];function C(M,H,Y,q){let Q=R.get(M);if(Q===void 0)Q=new Map,R.set(M,Q);let X=H??"",ee=Q.get(X);if(ee===void 0)ee=m.length,Q.set(X,ee),m.push({key:e("fr",M,X),name:M,url:H,line:Y,col:q});return ee}function N(M){let H=M.line===we,Y=H?void 0:M.line-1,q=H||M.column===we?void 0:M.column-1;return C(M.name,M.sourceURL,Y,q)}let v=C("(root)",void 0,void 0,void 0),D=1,W={id:0,frameIx:v,children:new Map,selfUs:0,samples:0,totalUs:0},O=new Map([[0,W]]),E={llint:0,baseline:0,dfg:0,ftl:0},j=new Map,z=[],V=[];for(let M of o.traces){let H=M.frames,Y=W;for(let X=H.length-1;X>=0;X--){let ee=N(H[X]),re=Y.children.get(ee);if(!re)re={id:D++,frameIx:ee,children:new Map,selfUs:0,samples:0,totalUs:0},Y.children.set(ee,re),O.set(re.id,re);Y=re}Y.selfUs+=c,Y.samples+=1,z.push(Y.id),V.push(c);let q=H[0],Q=q&&Ke.get(q.category);if(Q){E[Q]++;let X=j.get(Q)??new Map;X.set(Y.frameIx,(X.get(Y.frameIx)??0)+1),j.set(Q,X)}}function _(M){let H=M.selfUs;for(let Y of M.children.values())H+=_(Y);return M.totalUs=H,H}_(W);let J=new Map;function K(M){let H=J.get(M.frameIx);if(H)H.selfUs+=M.selfUs,H.totalUs+=M.totalUs,H.samples+=M.samples;else J.set(M.frameIx,{frameIx:M.frameIx,selfUs:M.selfUs,totalUs:M.totalUs,samples:M.samples});for(let Y of M.children.values())K(Y)}K(W);let G=[...O.values()].map((M)=>({id:M.id,frameIx:M.frameIx,children:[...M.children.values()].map((H)=>H.id)})),L={origin:"jsc-profile",samplingIntervalUs:c,frames:m,nodes:G,totals:[...J.values()].sort((M,H)=>H.selfUs-M.selfUs),samples:{nodeIds:z,timeDeltasUs:V}},A=[...j.entries()].flatMap(([M,H])=>[...H.entries()].sort((Y,q)=>q[1]-Y[1]).slice(0,3).map(([Y,q])=>({tier:M,frameKey:m[Y].key,samples:q})));return{cpu:L,jit:{origin:"jsc-profile",tiers:E,topFramesByTier:A}}}var Ye=1000;async function Re(o,U={}){let c=U.intervalUs??Ye,R,m=Bun.nanoseconds(),C=await Ge(async()=>(R=await o(),R),c),N=Bun.nanoseconds()-m,{cpu:v,jit:D}=xe(C.stackTraces,c);return{result:R,cpu:v,jit:D,diagnosticWallNs:N}}async function le(o){let U=Bun.nanoseconds(),c=Bun.spawn(o.argv,{cwd:o.cwd,env:o.env,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),R=await c.exited,m=Bun.nanoseconds(),C=c.resourceUsage?.();return{wallNs:m-U,exitCode:R,userNs:C?Number(C.cpuTime.user)*1000:void 0,systemNs:C?Number(C.cpuTime.system)*1000:void 0,maxRssBytes:C?.maxRSS}}function Pe(o){return o.trim().split(/\s+/).filter(Boolean)}var qe=10,Qe=3000000000,Xe=3;async function g(o){let U=o.warmup??Xe;for(let O=0;O<U;O++)await le(o);let c=[],R=o.runs??o.minRuns??qe,m=o.runs!==void 0?0:o.minTotalNs??Qe,C=0,N=0;while(N<R||C<m){let O=await le(o);if(c.push({i:N,wallNs:O.wallNs,exitCode:O.exitCode,userNs:O.userNs,systemNs:O.systemNs,maxRssBytes:O.maxRssBytes}),C+=O.wallNs,N++,o.runs!==void 0&&N>=o.runs)break}let v=c.map((O)=>O.wallNs),D=l(v),W=p(D,c.map((O)=>O.exitCode));return{trials:c,timing:D,warnings:W}}var Te=new URL("./runner.ts",import.meta.url).pathname,Ze="node_modules/.cache/ostia";function w(){return Math.max(1,navigator.hardwareConcurrency||1)}async function en(o,U){let c=new Set;for(let R of o){let m=new Bun.Glob(R);for await(let C of m.scan({cwd:U,absolute:!1}))c.add(C)}return[...c].sort()}function nn(o){if(o===void 0)return;return o==="auto"?w():o}async function P(o,U,c=process.cwd()){return{suites:o.suites.length>0?o.suites:U?.suites?await en(U.suites,c):[],timeBudgetMs:o.timeBudgetMs??U?.timeBudgetMs,minSamples:o.minSamples??U?.minSamples,jobs:o.jobs??nn(U?.jobs),gc:o.gc||(U?.gc??!1),filter:o.filter??U?.filter,isolate:o.isolate||(U?.isolate??!1),preload:o.preload.length>0?o.preload:U?.preload??[],bunFlags:o.bunFlags,outDir:o.outDir??U?.outDir,cwd:c}}async function d(o){let c=`${o.outDir??Ze}/bench-tmp`,R=o.cwd??process.cwd(),m=Math.max(1,Math.floor(o.jobs??1)),C={timeBudgetMs:o.timeBudgetMs,minSamples:o.minSamples,gc:o.gc},N=o.suites.map((O)=>O.startsWith("/")?O:`${R}/${O}`),v=(o.preload??[]).map((O)=>O.startsWith("/")?O:`${R}/${O}`),D=o.bunFlags??[],W=async(O,E)=>{let j=new Set,z=0,V,_=async()=>{while(V===void 0&&z<O.length){let J=z++;try{let K=Bun.spawn(O[J],{cwd:R,stdout:"inherit",stderr:"inherit",stdin:"ignore"});j.add(K);let G=await K.exited;if(j.delete(K),G!==0)throw Error(`Bench suite failed: ${E(J)} (runner exited ${G})`)}catch(K){V??=K instanceof Error?K:Error(String(K));for(let G of j)G.kill()}}};if(await Promise.all(Array.from({length:Math.min(m,O.length)},_)),V)throw V};try{let O=N.map((F)=>`${c}/${e("bench-plan",F)}.json`),E=N.map((F)=>`${c}/${e("bench-primary",F)}.json`),j=N.map((F,M)=>["bun",...D,Te,F,E[M],JSON.stringify({...C,filter:o.filter,isolate:o.isolate,preload:v,planPath:O[M]})]);await W(j,(F)=>o.suites[F]);let z=await Promise.all(O.map(async(F)=>{let{tasks:M}=await Bun.file(F).json();return M})),V=await Promise.all(E.map(t)),_=[];for(let F=0;F<z.length;F++)for(let M of z[F])if(M.isolate)_.push({suiteIndex:F,taskIds:[M.id]});let J=_.map((F,M)=>`${c}/${e("bench-item",N[F.suiteIndex],M)}.json`),K=_.map((F,M)=>["bun",...D,Te,N[F.suiteIndex],J[M],JSON.stringify({...C,taskIds:F.taskIds,preload:v,markIsolated:!0})]);await W(K,(F)=>o.suites[_[F].suiteIndex]);let G=await Promise.all(J.map(t)),L=[],A=[];for(let F=0;F<z.length;F++){let M=V[F],H=0,Y=new Map;_.forEach((q,Q)=>{if(q.suiteIndex===F)Y.set(q.taskIds[0],G[Q])});for(let q of z[F])if(q.isolate){let Q=Y.get(q.id);L.push(Q.workloads[0]),A.push(Q.runs[0])}else L.push(M.workloads[H]),A.push(M.runs[H]),H++}return r(L,A)}finally{await Bun.spawn(["rm","-rf",c]).exited}}function S(o,U,c=8){if(c<=1)throw RangeError(`range: multiplier must be > 1, got ${c}`);if(o<=0)throw RangeError(`range: start must be > 0, got ${o}`);let R=[];for(let m=o;m<=U;m*=c)R.push(m);if(!R.includes(U))R.push(U);return R}var a={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000};function ce(o,U){if(o===0)return U===0?0:1/0;return(U-o)/o*100}function se(o,U,c){return o.runs.find((R)=>R.workloadId===U&&R.phase===c)}function f(o,U,c=a){let R=new Set(U.workloads.map((C)=>C.id)),m=[];for(let C of o.workloads){if(!R.has(C.id))continue;let N=y(o,U,C.id,c);if(N)m.push(N)}return m}function y(o,U,c,R=a){let m=se(o,c,"timing"),C=se(U,c,"timing"),N=se(o,c,"cpu"),v=se(U,c,"cpu"),D=se(o,c,"heap"),W=se(U,c,"heap"),O=m?.id??N?.id??D?.id,E=C?.id??v?.id??W?.id;if(!O||!E)return;let j=!1,z;if(m?.timing&&C?.timing){let J=ce(m.timing.median,C.timing.median),K=ce(m.timing.mean,C.timing.mean),G=J>R.timingPct?"regressed":J<-R.timingPct?"improved":"unchanged";if(G==="regressed")j=!0;z={medianDeltaPct:J,meanDeltaPct:K,verdict:G}}let V;if(N?.cpu&&v?.cpu){let J=new Map(N.cpu.totals.map((F)=>[N.cpu.frames[F.frameIx].key,F])),K=new Map(v.cpu.totals.map((F)=>[v.cpu.frames[F.frameIx].key,F])),G=new Map(N.cpu.frames.map((F)=>[F.key,F.name])),L=new Map(v.cpu.frames.map((F)=>[F.key,F.name]));V=[...new Set([...J.keys(),...K.keys()])].map((F)=>{let M=J.get(F)?.selfUs??0,H=K.get(F)?.selfUs??0;return{frameKey:F,name:L.get(F)??G.get(F)??F,baseSelfUs:M,candSelfUs:H,deltaPct:ce(M,H)}}).sort((F,M)=>Math.abs(M.deltaPct)-Math.abs(F.deltaPct));for(let F of V)if((F.baseSelfUs>=R.minFrameSelfUs||F.candSelfUs>=R.minFrameSelfUs)&&F.deltaPct>R.frameSelfPct)j=!0}let _;if(D?.heap&&W?.heap){let J=new Map(D.heap.typeCounts.map((L)=>[L.type,L])),K=new Map(W.heap.typeCounts.map((L)=>[L.type,L]));_=[...new Set([...J.keys(),...K.keys()])].map((L)=>{let A=J.get(L),F=K.get(L);return{type:L,baseCount:A?.count??0,candCount:F?.count??0,baseBytes:A?.retainedBytes,candBytes:F?.retainedBytes,deltaPct:ce(A?.count??0,F?.count??0)}}).sort((L,A)=>Math.abs(A.deltaPct)-Math.abs(L.deltaPct));for(let L of _)if(L.deltaPct>R.heapTypePct)j=!0}return{id:e("cmp",O,E),baselineRunId:O,candidateRunId:E,timing:z,frames:V,heapTypes:_,thresholds:R,verdict:j?"fail":"pass"}}function ne(o,U){if(U){let c=o.runs.find((R)=>R.id===U);return c?.cpu?[c]:[]}return o.runs.filter((c)=>c.phase==="cpu"&&c.cpu)}function oe(o){let U=o.nodes,c=U.length,R=tn(o),m=new Int32Array(c).fill(-1);for(let D=0;D<c;D++)for(let W of U[D].children){let O=R(W);if(O!==-1)m[O]=D}let C=[];for(let D=0;D<c;D++)if(m[D]===-1)C.push(D);let N=[],v=[];for(let D=C.length-1;D>=0;D--)v.push(C[D]);while(v.length>0){let D=v.pop();N.push(D);for(let W of U[D].children){let O=R(W);if(O!==-1&&m[O]===D)v.push(O)}}return{count:c,indexOf:R,parentIx:m,roots:C,order:N}}function tn(o){let U=o.nodes,c=U.length,R=1/0,m=-1/0,C=!0;for(let v=0;v<c;v++){let D=U[v].id;if(!Number.isInteger(D)){C=!1;break}if(D<R)R=D;if(D>m)m=D}if(C&&c>0&&m-R<c*4+64){let v=m-R+1,D=new Int32Array(v).fill(-1);for(let W=0;W<c;W++)D[U[W].id-R]=W;return(W)=>{let O=W-R;return O>=0&&O<v?D[O]:-1}}let N=new Map;for(let v=0;v<c;v++)N.set(U[v].id,v);return(v)=>N.get(v)??-1}function $e(o,U){let{count:c,indexOf:R,parentIx:m,order:C}=U,N=new Float64Array(c),v=new Float64Array(c),D=o.samples?.nodeIds??[],W=o.samples?.timeDeltasUs??[];for(let E=0;E<D.length;E++){let j=R(D[E]);if(j===-1)continue;N[j]+=W[E]??0,v[j]+=1}let O=new Float64Array(c);for(let E=C.length-1;E>=0;E--){let j=C[E];O[j]+=N[j];let z=m[j];if(z>=0)O[z]+=O[j]}return{selfUs:N,totalUs:O,samples:v}}var ke={name:"collapsed",async render(o,U={}){return{files:ne(o,U.runId).map((m)=>{let C=m.cpu,{nodes:N,frames:v}=C,D=oe(C),W=Array(D.count);for(let V of D.order){let _=v[N[V].frameIx].name||"(anonymous)",J=D.parentIx[V];W[V]=J===-1?_:`${W[J]};${_}`}let O=new Float64Array(D.count),E=[],j=C.samples?.nodeIds??[];for(let V=0;V<j.length;V++){let _=D.indexOf(j[V]);if(_===-1)continue;if(O[_]++===0)E.push(_)}let z=Array(E.length);for(let V=0;V<E.length;V++){let _=E[V];z[V]=`${W[_]} ${O[_]}`}return{path:`${m.id}.collapsed.txt`,content:z.join(`
|
|
3
|
-
`)+(z.length>0?`
|
|
4
|
-
`:"")}})}}};var Ie={name:"cpuprofile",async render(o,U={}){let c=ne(o,U.runId),R=[],m=[];for(let C of c){if(C.cpu?.origin!=="cpu-prof"&&C.cpu?.origin!=="inspector"){m.push(`${C.id} (origin ${C.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let N=C.artifacts.find((D)=>D.kind==="cpuprofile");if(!N){m.push(`${C.id} (no cpuprofile artifact recorded on this run)`);continue}let v=Bun.file(N.path);if(!await v.exists()){m.push(`${C.id} (artifact missing on disk: ${N.path})`);continue}R.push({path:`${C.id}.cpuprofile`,content:await v.text()})}if(R.length===0&&m.length>0)return{text:`No .cpuprofile artifacts available:
|
|
5
|
-
${m.map((C)=>` - ${C}`).join(`
|
|
6
|
-
`)}
|
|
7
|
-
`};return{files:R}}};var ve={name:"json",async render(o){return{text:x(o)}}};var Ce={name:"jsonl",async render(o){let{runs:U,...c}=o;return{text:`${[h(c),...U.map((m)=>h(m))].join(`
|
|
8
|
-
`)}
|
|
9
|
-
`}}};function te(o){return(o/1e6).toFixed(3)}function ue(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??o?.id??"unknown"}var Ne=10,Ue=10,De={name:"markdown",async render(o){let U=new Map(o.workloads.map((m)=>[m.id,m])),c=[];c.push("# Profile Report",""),c.push(`Bun ${o.bunVersion} \xB7 ostia ${o.toolVersion} \xB7 ${o.platform.os}/${o.platform.arch} \xB7 ${o.createdAt}`,"");let R=o.runs.filter((m)=>m.phase==="timing"&&m.timing!==void 0);if(R.length>0){c.push("## Timing",""),c.push("| Command | Mean \xB1 SD (ms) | Min\u2026Max (ms) | Median (ms) |","|---|---|---|---|");for(let C of R){let N=ue(U.get(C.workloadId)),v=C.timing;c.push(`| ${N} | ${te(v.mean)} \xB1 ${te(v.stddev)} | ${te(v.min)}\u2026${te(v.max)} | ${te(v.median)} |`)}c.push("");let m=R.filter((C)=>C.warnings.length>0);if(m.length>0){c.push("### Warnings","");for(let C of m){let N=ue(U.get(C.workloadId));for(let v of C.warnings)c.push(`- **${N}**: ${v.message} (\`${v.code}\`)`)}c.push("")}}for(let m of o.runs){if(m.phase!=="cpu"&&m.phase!=="heap")continue;let C=ue(U.get(m.workloadId));if(m.phase==="cpu"){if(c.push(`## CPU capture - ${C}`,""),c.push(`instrumented, diagnostic wall ${te(m.diagnosticWallNs??0)}ms`,""),m.cpu){c.push(`origin: \`${m.cpu.origin}\`, interval: ${m.cpu.samplingIntervalUs}\xB5s`,""),c.push("| Self % | Self (ms) | Total (ms) | Frame |","|---|---|---|---|");let N=m.cpu.totals.reduce((v,D)=>v+D.selfUs,0)||1;for(let v of m.cpu.totals.slice(0,Ne)){let D=m.cpu.frames[v.frameIx],W=(v.selfUs/N*100).toFixed(1);c.push(`| ${W}% | ${(v.selfUs/1000).toFixed(2)} | ${(v.totalUs/1000).toFixed(2)} | ${D?.name||"(anonymous)"} |`)}if(c.push(""),m.jit){let v=m.jit.tiers;c.push(`JIT tiers: LLInt ${v.llint} \xB7 Baseline ${v.baseline} \xB7 DFG ${v.dfg} \xB7 FTL ${v.ftl}`,"")}}}else if(c.push(`## Heap snapshot - ${C}`,""),c.push(`instrumented, diagnostic wall ${te(m.diagnosticWallNs??0)}ms`,""),m.heap){c.push(`${m.heap.objectCount??"?"} objects, ${((m.heap.heapSizeBytes??0)/1e6).toFixed(2)}MB`,""),c.push("| Count | Type |","|---|---|");for(let N of m.heap.typeCounts.slice(0,Ue))c.push(`| ${N.count} | ${N.type} |`);c.push("")}for(let N of m.artifacts)c.push(`- artifact: \`${N.path}\``);for(let N of m.warnings)c.push(`- ! ${N.message} (\`${N.code}\`)`);if(m.artifacts.length>0||m.warnings.length>0)c.push("")}if(o.comparisons&&o.comparisons.length>0){c.push("## Comparisons","");for(let m of o.comparisons){let C=o.runs.find((v)=>v.id===m.candidateRunId),N=ue(C?U.get(C.workloadId):void 0);if(c.push(`### ${m.verdict==="pass"?"\u2713":"\u2717"} ${N}`,""),m.timing){let v=m.timing.medianDeltaPct>0?"+":"";c.push(`- timing: ${v}${m.timing.medianDeltaPct.toFixed(1)}% median (**${m.timing.verdict}**)`)}for(let v of m.frames?.slice(0,Ne)??[]){if(Math.abs(v.deltaPct)<0.5)continue;let D=v.deltaPct>0?"+":"";c.push(`- frame \`${v.name}\`: ${D}${v.deltaPct.toFixed(1)}% self-time (${(v.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(v.candSelfUs/1000).toFixed(2)}ms)`)}for(let v of m.heapTypes?.slice(0,Ue)??[]){if(Math.abs(v.deltaPct)<0.5)continue;let D=v.deltaPct>0?"+":"";c.push(`- heap \`${v.type}\`: ${D}${v.deltaPct.toFixed(1)}% count (${v.baseCount} \u2192 ${v.candCount})`)}c.push("")}}return{text:c.join(`
|
|
10
|
-
`)}}};var rn=15;function me(o){return`n${o}`}function sn(o,U,c){return`${(o||"(anonymous)").replace(/"/g,"'")} (self ${(U/1000).toFixed(2)}ms, total ${(c/1000).toFixed(2)}ms)`}function on(o,U,c,R){let m=[];if(R<=0)return m;for(let C=0;C<U;C++){if(C===c)continue;let N=o[C];if(m.length===R&&N<=o[m[R-1]])continue;let v=m.length;while(v>0&&o[m[v-1]]<N)v--;if(m.splice(v,0,C),m.length>R)m.pop()}return m}var Fe={name:"mermaid",async render(o,U={}){let c=U.topN??rn;return{files:ne(o,U.runId).map((C)=>{let N=C.cpu,{nodes:v,frames:D}=N,W=oe(N),{selfUs:O,totalUs:E}=$e(N,W),{parentIx:j}=W,z=W.roots[0]??-1,V=on(O,W.count,z,c),_=new Set(z!==-1?[z]:[]),J=[];for(let G of V){J.length=0;for(let L=G;L!==-1;L=j[L])J.push(L);for(let L=J.length-1;L>=0;L--)_.add(J[L])}let K=["graph TD"];for(let G of _){let L=v[G].id;K.push(` ${me(L)}["${sn(D[v[G].frameIx].name,O[G],E[G])}"]`)}for(let G of _){let L=j[G];if(L!==-1&&_.has(L))K.push(` ${me(v[L].id)} --> ${me(v[G].id)}`)}return{path:`${C.id}.mermaid.md`,content:`${K.join(`
|
|
11
|
-
`)}
|
|
12
|
-
`}})}}};function Me(o){if(!o?.entry)return;if(o.entry.group!==void 0)return o.entry.group;let U=o.entry.task,c=U.lastIndexOf("/");return c===-1?void 0:U.slice(0,c)}function pe(o){let U=Math.min(...o.map((m)=>m.run.timing.median)),c=new Map;for(let m of o){let C=Me(m.workload);if(C===void 0)continue;let N=c.get(C);if(N)N.push(m);else c.set(C,[m])}let R=new Map;for(let m of o){let C=Me(m.workload);if(C===void 0){R.set(m,U);continue}let N=c.get(C)??[m],v=N.find((D)=>D.workload?.baseline);R.set(m,v?v.run.timing.median:Math.min(...N.map((D)=>D.run.timing.median)))}return R}function Z(o){return Number.isFinite(o)?Number(o.toPrecision(6)):o}function an(o,U){return o?.entry?.task??o?.label??o?.command?.join(" ")??U.workloadId}function cn(o){let U=new Map(o.workloads.map((C)=>[C.id,C])),c=o.runs.filter((C)=>C.phase==="timing"&&C.timing!==void 0).map((C)=>({run:C,workload:U.get(C.workloadId)})),R=c.length>1?pe(c):void 0,m=new Map((o.comparisons??[]).map((C)=>[C.candidateRunId,C]));return c.map((C)=>{let{run:N,workload:v}=C,D=N.timing,W={task:an(v,N),unit:"ns",samples:D.samples.length,mean:Z(D.mean),median:Z(D.median),stddev:Z(D.stddev),stddevPct:Z(D.mean===0?0:D.stddev/D.mean*100),min:Z(D.min),max:Z(D.max),warnings:N.warnings.map((E)=>E.data?{code:E.code,data:E.data}:{code:E.code})};if(v?.entry?.group!==void 0)W.group=v.entry.group;if(v?.description!==void 0)W.description=v.description;if(v?.groupDescription!==void 0)W.groupDescription=v.groupDescription;if(R)W.relative=Z(D.median/(R.get(C)??D.median));if(v?.baseline)W.baseline=!0;let O=m.get(N.id);if(O?.timing)W.delta={medianPct:Z(O.timing.medianDeltaPct),meanPct:Z(O.timing.meanDeltaPct),verdict:O.timing.verdict,pass:O.verdict==="pass"};return W})}var Se={name:"minimal",async render(o){let U=cn(o).map((c)=>JSON.stringify(c));return{text:U.length>0?`${U.join(`
|
|
13
|
-
`)}
|
|
14
|
-
`:""}}};var un="https://www.speedscope.app/file-format-schema.json";function Be(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??"profile"}var Oe={name:"speedscope",async render(o,U={}){let c=ne(o,U.runId),R=new Map(o.workloads.map((C)=>[C.id,C]));return{files:c.map((C)=>{let N=C.cpu,{nodes:v}=N,D=oe(N),W=N.samples?.nodeIds??[],O=N.samples?.timeDeltasUs??[],E=Array(D.count);for(let _ of D.order){let J=D.parentIx[_],K=v[_].frameIx;E[_]=J===-1?[K]:[...E[J],K]}let j=Array(W.length);for(let _=0;_<W.length;_++){let J=D.indexOf(W[_]);j[_]=J===-1?[]:E[J]}let z=0;for(let _=0;_<O.length;_++)z+=O[_];let V={$schema:un,exporter:"ostia",name:Be(R.get(C.workloadId)),activeProfileIndex:0,shared:{frames:N.frames.map((_)=>({name:_.name||"(anonymous)",file:_.url,line:_.line!==void 0?_.line+1:void 0}))},profiles:[{type:"sampled",name:Be(R.get(C.workloadId)),unit:"microseconds",startValue:0,endValue:z,samples:j,weights:O}]};return{path:`${C.id}.speedscope.json`,content:`${JSON.stringify(V,null,2)}
|
|
15
|
-
`}})}}};function ie(o){return(o/1e6).toFixed(3)}function de(o){return o.label??o.command?.join(" ")??o.entry?.task??o.id}var Ee={name:"table",async render(o){let U=o.runs.filter((E)=>E.phase==="timing"&&E.timing!==void 0),c=new Map(o.workloads.map((E)=>[E.id,E]));if(U.length===0){let E=We(o,c);return{text:E.length>0?`${E.join(`
|
|
16
|
-
`)}
|
|
17
|
-
`:`(no timing runs)
|
|
18
|
-
`}}let R=U.map((E)=>{let j=c.get(E.workloadId);return{run:E,workload:j,label:j?de(j):E.workloadId}}),m=R.length>1,C=pe(R),N=[],v=Math.max(7,...R.map((E)=>E.label.length)),D=m?`${"Command".padEnd(v)} Mean [ms] Min\u2026Max [ms] Relative`:`${"Command".padEnd(v)} Mean [ms] Min\u2026Max [ms]`;N.push(D),N.push("-".repeat(D.length));for(let E of R){let{run:j,label:z,workload:V}=E,_=j.timing,J=`${ie(_.mean)} \xB1 ${ie(_.stddev)}`,K=`${ie(_.min)}\u2026${ie(_.max)}`,G=`${z.padEnd(v)} ${J.padEnd(15)} ${K.padEnd(18)}`;if(m){let L=_.median/(C.get(E)??_.median);if(L===1)G+=V?.baseline?" 1.00\xD7 (baseline)":" 1.00\xD7";else if(L>1)G+=` ${L.toFixed(2)}\xD7 slower`;else G+=` ${(1/L).toFixed(2)}\xD7 faster`}N.push(G);for(let L of j.warnings)N.push(` ! ${L.message}`)}let W=ln(o,c);if(W.length>0)N.push(""),N.push(...W);let O=We(o,c);if(O.length>0)N.push(""),N.push(...O);return{text:`${N.join(`
|
|
19
|
-
`)}
|
|
20
|
-
`}}};function pn(o,U,c){let R=o.runs.find((C)=>C.id===c),m=R?U.get(R.workloadId):void 0;return m?de(m):c}function We(o,U){if(!o.comparisons||o.comparisons.length===0)return[];let c=[];for(let R of o.comparisons){let m=pn(o,U,R.candidateRunId),C=R.verdict==="pass"?"\u2713":"\u2717";if(c.push(`${C} ${m}`),R.timing){let N=R.timing.medianDeltaPct>0?"+":"";c.push(` timing: ${N}${R.timing.medianDeltaPct.toFixed(1)}% median (${R.timing.verdict})`)}if(R.frames)for(let N of R.frames.slice(0,Ae)){if(Math.abs(N.deltaPct)<0.5)continue;let v=N.deltaPct>0?"+":"";c.push(` frame ${N.name}: ${v}${N.deltaPct.toFixed(1)}% self-time (${(N.baseSelfUs/1000).toFixed(2)}ms -> ${(N.candSelfUs/1000).toFixed(2)}ms)`)}if(R.heapTypes)for(let N of R.heapTypes.slice(0,je)){if(Math.abs(N.deltaPct)<0.5)continue;let v=N.deltaPct>0?"+":"";c.push(` heap ${N.type}: ${v}${N.deltaPct.toFixed(1)}% count (${N.baseCount} -> ${N.candCount})`)}}return c}var Ae=5,je=5;function ln(o,U){let c=[];for(let R of o.runs){if(R.phase!=="cpu"&&R.phase!=="heap")continue;let m=U.get(R.workloadId),C=m?de(m):R.workloadId;if(R.phase==="cpu")if(R.cpu){c.push(`CPU capture - ${C} (instrumented, ${R.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${ie(R.diagnosticWallNs??0)}ms)`);let N=R.cpu.totals.reduce((v,D)=>v+D.selfUs,0)||1;for(let v of R.cpu.totals.slice(0,Ae)){let D=R.cpu.frames[v.frameIx],W=(v.selfUs/N*100).toFixed(1);c.push(` ${W.padStart(5)}% ${(v.selfUs/1000).toFixed(2).padStart(8)}ms self ${D?.name??"?"}`)}}else c.push(`CPU capture - ${C} (instrumented, no evidence captured)`);else if(R.heap){let N=((R.heap.heapSizeBytes??0)/1e6).toFixed(2);c.push(`Heap snapshot - ${C} (instrumented, ${R.heap.objectCount??"?"} objects, ${N}MB)`);for(let v of R.heap.typeCounts.slice(0,je))c.push(` ${String(v.count).padStart(6)} ${v.type}`)}else c.push(`Heap snapshot - ${C} (instrumented, no evidence captured)`);for(let N of R.artifacts)c.push(` artifact: ${N.path}`);for(let N of R.warnings)c.push(` ! ${N.message}`)}return c}var n={table:Ee,json:ve,markdown:De,jsonl:Ce,minimal:Se,collapsed:ke,mermaid:Fe,speedscope:Oe,cpuprofile:Ie};var mn="node_modules/.cache/ostia",fe=1000;async function k(o){let U=s({runs:o.runs??null,warmup:o.warmup??null,cpu:o.cpu??!1,heap:o.heap??!1,cpuIntervalUs:o.cpuIntervalUs??fe}),R=`${o.outDir??mn}/artifacts`,m=[],C=[];for(let N of o.commands){let v=Array.isArray(N)?N:Pe(N),D=u(v,Array.isArray(N)?void 0:N);m.push(D);let W=await g({argv:v,cwd:o.cwd,env:o.env,runs:o.runs,warmup:o.warmup}),O=i({workload:D,configFingerprint:U,trials:W.trials,timing:W.timing,warnings:W.warnings});if(C.push(O),o.cpu){let E=`${O.id}-cpu.cpuprofile`,j=await ge({argv:v,cwd:o.cwd,env:o.env,artifactDir:R,fileName:E,intervalUs:o.cpuIntervalUs??fe});C.push(await _e({workload:D,phase:"cpu",configFingerprint:U,diagnosticWallNs:j.diagnosticWallNs,exitCode:j.exitCode,cpu:j.cpu,artifactPath:j.artifactPath,artifactKind:"cpuprofile",warnings:j.warnings}))}if(o.heap){let E=`${O.id}-heap.heapsnapshot`,j=await be({argv:v,cwd:o.cwd,env:o.env,artifactDir:R,fileName:E});C.push(await _e({workload:D,phase:"heap",configFingerprint:U,diagnosticWallNs:j.diagnosticWallNs,exitCode:j.exitCode,heap:j.heap,artifactPath:j.artifactPath,artifactKind:"heapsnapshot",warnings:j.warnings}))}}return r(m,C)}async function _e(o){let U=`${o.workload.id}-${o.phase}-${o.configFingerprint}`,c=o.artifactPath?[await I(U,o.artifactKind,o.artifactPath)]:[];return b({workload:o.workload,phase:o.phase,configFingerprint:o.configFingerprint,diagnosticWallNs:o.diagnosticWallNs,exitCode:o.exitCode,cpu:o.cpu,heap:o.heap,warnings:o.warnings,artifacts:c})}async function B(o,U={}){let c=T(o),R=s({intervalUs:U.intervalUs??fe,origin:U.origin??"inspector"}),m=(W)=>W.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(U.origin==="jsc"){let{result:W,cpu:O,jit:E,diagnosticWallNs:j}=await Re(o,U),z=b({workload:c,phase:"cpu",configFingerprint:R,diagnosticWallNs:j,cpu:O,jit:E,warnings:m(O),artifacts:[]});return{result:W,run:z}}let{result:C,cpu:N,diagnosticWallNs:v}=await ye(o,U),D=b({workload:c,phase:"cpu",configFingerprint:R,diagnosticWallNs:v,cpu:N,warnings:m(N),artifacts:[]});return{result:C,run:D}}
|
|
21
|
-
export{w,P,d,a,f,y,g,S,n,k,B};
|
package/chunk-zrck2q0b.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
function h(n){return JSON.stringify(O(n))}function O(n){if(Array.isArray(n))return n.map(O);if(n!==null&&typeof n==="object"){let a={};for(let d of Object.keys(n).sort())a[d]=O(n[d]);return a}return n}function e(n,...a){let d=Bun.CryptoHasher.hash("sha256",h(a),"hex");return`${n}_${d.slice(0,16)}`}var c="0.1.0";function r(n,a){return{schemaVersion:1,toolVersion:c,bunVersion:Bun.version,platform:{os:process.platform,arch:process.arch},createdAt:new Date().toISOString(),workloads:n,runs:a}}function u(n,a){return{id:e("wl","subprocess",n,process.cwd()),kind:"subprocess",command:n,label:a}}function T(n,a){return{id:e("wl","inprocess",n.name,n.toString()),kind:"inprocess",label:a}}function C(n,a,d={}){return{id:e("wl","inprocess-entry",n,a),kind:"inprocess",entry:{file:n,task:a,...d.group!==void 0&&{group:d.group}},...d.label!==void 0&&{label:d.label},...d.baseline!==void 0&&{baseline:d.baseline},...d.description!==void 0&&{description:d.description},...d.groupDescription!==void 0&&{groupDescription:d.groupDescription},...d.isolated!==void 0&&{isolated:d.isolated}}}function i(n){return{id:e("run",n.workload.id,"timing",n.configFingerprint,Bun.version,c),workloadId:n.workload.id,phase:"timing",instrumented:!1,configFingerprint:n.configFingerprint,trials:n.trials,timing:n.timing,warnings:n.warnings,artifacts:[],memory:Q(n.trials)}}function Q(n){let a=n.map((d)=>d.maxRssBytes).filter((d)=>d!==void 0);if(a.length===0)return;return{origin:"resourceUsage",perTrial:n.map((d)=>({rssBytes:d.maxRssBytes})),maxRssBytes:Math.max(...a)}}function b(n){return{id:e("run",n.workload.id,n.phase,n.configFingerprint,Bun.version,c),workloadId:n.workload.id,phase:n.phase,instrumented:!0,configFingerprint:n.configFingerprint,trials:[{i:0,wallNs:n.diagnosticWallNs,exitCode:n.exitCode}],diagnosticWallNs:n.diagnosticWallNs,cpu:n.cpu,heap:n.heap,jit:n.jit,warnings:n.warnings,artifacts:n.artifacts}}async function I(n,a,d){let f=await Bun.file(d).arrayBuffer(),k=new Bun.CryptoHasher("sha256");return k.update(f),{id:e("art",n,a,d),kind:a,path:d,sha256:k.digest("hex"),bytes:f.byteLength}}function s(n){return e("cfg",n)}function x(n){return`${JSON.stringify(O(n),null,2)}
|
|
3
|
-
`}async function o(n,a){await Bun.write(a,x(n))}async function t(n){let a=await Bun.file(n).text();return JSON.parse(a)}var G=[],W;function U(n,a,d){let g=W;W={name:n,description:d?.description,isolate:d?.isolate,gc:d?.gc};try{a()}finally{W=g}}function M(n,a,d){G.push({groupName:W?.name,groupDescription:W?.description,groupIsolate:W?.isolate,groupGc:W?.gc,name:n,fn:a,baseline:d?.baseline,opts:d})}function N(){return G}function v(){G.length=0,W=void 0}function m(n){return n.groupName?`${n.groupName}/${n.name}`:n.name}function R(n,a){return n.opts?.isolate??n.groupIsolate??a}function D(n,a){return n.opts?.gc??n.groupGc??a}function F(n,a){if(!a)return[...n];let d=new RegExp(a);return n.filter((g)=>d.test(m(g)))}function l(n){if(n.length===0)throw Error("computeTimingStats: samples must be non-empty");let a=n.length,d=L(n),g=0;for(let y=0;y<a;y++)g+=n[y];let f=g/a,k=B(d,0.5),w=0;for(let y=0;y<a;y++){let S=n[y]-f;w+=S*S}let P=Math.sqrt(w/a),H=d[0],E=d[a-1],q=B(d,0.25),_=B(d,0.75),A=_-q,z=q-1.5*A,V=_+1.5*A,K=q-3*A,Z=_+3*A,J=0,j=0;for(let y=0;y<a;y++){let S=n[y];if(S<K||S>Z)j++;else if(S<z||S>V)J++}return{unit:"ns",samples:n,mean:f,median:k,stddev:P,min:H,max:E,outliers:{mild:J,severe:j}}}function L(n){let a=new Float64Array(n.length);return a.set(n),a.sort(),a}function B(n,a){let d=n.length;if(d===1)return n[0];let g=a*(d-1),f=Math.floor(g),k=Math.ceil(g);if(f===k)return n[f];let w=g-f;return n[f]*(1-w)+n[k]*w}var X=5000000,Y=200;function p(n,a,d="subprocess"){let g=[],f=n.samples[0];if(f!==void 0){let w=L(n.samples),P=B(w,0.25),E=B(w,0.75)-P;if(f>n.median+3*E&&E>0)g.push({code:"slow-first-run",message:`First run took ${(f/1e6).toFixed(2)}ms, much slower than the median ${(n.median/1e6).toFixed(2)}ms. Consider more warmup.`,data:{firstNs:f,medianNs:n.median}})}if(n.outliers.mild+n.outliers.severe>0)g.push({code:"outliers-detected",message:`${n.outliers.mild+n.outliers.severe} outlier(s) detected (${n.outliers.severe} severe, ${n.outliers.mild} mild).`,data:n.outliers});if(d==="subprocess"&&n.median<X)g.push({code:"fast-command",message:`Median run time (${(n.median/1e6).toFixed(3)}ms) is very fast; results may be dominated by spawn overhead.`,data:{medianNs:n.median}});if(d==="inprocess"&&n.median<Y)g.push({code:"below-timer-resolution",message:`Median run time (${n.median.toFixed(0)}ns) is close to timer resolution; consider a larger batch size or a coarser operation.`,data:{medianNs:n.median}});let k=a.filter((w)=>w!==void 0&&w!==0);if(k.length>0)g.push({code:"nonzero-exit",message:`${k.length} of ${a.length} trial(s) exited non-zero.`,data:{exitCodes:k}});return g}
|
|
4
|
-
export{h,e,c,r,u,T,C,i,b,I,s,x,o,t,l,p,U,M,N,v,m,R,D,F};
|