ostia 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.
- package/README.md +65 -3
- package/chunk-3rp84rbb.js +4 -0
- package/chunk-s1d2tx3w.js +21 -0
- package/cli.js +46 -28
- package/index.d.ts +62 -5
- package/index.js +1 -1
- package/package.json +1 -1
- package/runner.ts +4 -4
- package/chunk-m8zhsw7r.js +0 -19
- package/chunk-qh19pbhc.js +0 -4
package/README.md
CHANGED
|
@@ -133,15 +133,40 @@ Heap snapshot - bun fixtures/allocate.ts (instrumented, 2518 objects, 0.12MB)
|
|
|
133
133
|
|
|
134
134
|
In-process microbenchmarks registered with `group()` / `task()`. Each task samples
|
|
135
135
|
for `--time-budget` (default 500ms). `--min-samples` is a hard floor kept even when it
|
|
136
|
-
overruns the budget
|
|
137
|
-
budget
|
|
138
|
-
|
|
136
|
+
overruns the budget. Left unset, the floor is cost-aware in both directions: as many
|
|
137
|
+
trials as fit in the budget (capped at 20) so one slow task can't blow the suite's total,
|
|
138
|
+
but never below the floor a task's per-trial cost earns it - 3 at ≤1ms, two more per
|
|
139
|
+
decade of cost, 10 from about 3s up. Cheap tasks are time-bound and collect thousands of
|
|
140
|
+
trials either way; only the few expensive tasks in a suite pay for the extra rigor, and
|
|
141
|
+
those are exactly where a 3-sample mean is shakiest. Fast calls are batched so a trial
|
|
142
|
+
spans at least 1µs and a full budget yields about 10k trials at most.
|
|
143
|
+
|
|
144
|
+
| per-trial cost | fits in 500ms | default floor |
|
|
145
|
+
|---|---|---|
|
|
146
|
+
| 30ns | thousands | 20 (time-bound; ends in the tens of thousands) |
|
|
147
|
+
| 30ms | 16 | 16 |
|
|
148
|
+
| 140ms | 3 | 7 |
|
|
149
|
+
| 2.4s | 0 | 10 |
|
|
150
|
+
|
|
151
|
+
A run that ends below its cost-class floor (only possible with an explicit
|
|
152
|
+
`--min-samples` or per-task `minSamples`) carries a `low-sample-count` warning with
|
|
153
|
+
`{ samples, target, trialCostNs }`, so a renderer or an agent can flag a thin number
|
|
154
|
+
without re-deriving the policy from the raw sample array.
|
|
139
155
|
|
|
140
156
|
```sh
|
|
141
157
|
ostia bench bench/*.ts
|
|
142
158
|
ostia bench --time-budget 500 --min-samples 50 bench/stats.ts
|
|
159
|
+
ostia bench bench/*.ts --jobs auto # suite files in parallel, see below
|
|
160
|
+
ostia bench bench/*.ts --format minimal # one compact JSON object per task
|
|
143
161
|
```
|
|
144
162
|
|
|
163
|
+
`--jobs N|auto` runs that many suite files at once, each still in its own child process.
|
|
164
|
+
Files are independent by design, so for a multi-file suite this is close to a linear
|
|
165
|
+
wall-clock win - but concurrent CPU-bound processes contend for cores, caches and turbo
|
|
166
|
+
headroom, so numbers taken at `--jobs > 1` are noisier and not like-for-like with a
|
|
167
|
+
baseline measured at 1. It defaults to 1 for that reason; opt in for exploratory runs,
|
|
168
|
+
keep 1 for anything you `compare` or `ci` against.
|
|
169
|
+
|
|
145
170
|
```
|
|
146
171
|
Command Mean [ms] Min…Max [ms] Relative
|
|
147
172
|
--------------------------------------------------------------------------------------
|
|
@@ -176,8 +201,22 @@ ostia report out.json # table (default)
|
|
|
176
201
|
ostia report out.json --format markdown
|
|
177
202
|
ostia report out.json --format json
|
|
178
203
|
ostia report out.json --format jsonl
|
|
204
|
+
ostia report out.json --format minimal
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Minimal format - one JSON object per timing run, no header, no raw sample array, no prose.
|
|
208
|
+
Built to pipe straight into an LLM agent's context: the full document carries every
|
|
209
|
+
sample (tens of thousands for a fast task), which is tokens a reviewer never reads.
|
|
210
|
+
Numbers stay in ns so they line up with `compare` deltas and the JSON document.
|
|
211
|
+
|
|
212
|
+
```
|
|
213
|
+
{"task":"diffText()/append at end","group":"diffText()","samples":9282,"mean":50213.4,"median":49871,"stddev":2104.7,"stddevPct":4.19,"min":48120,"max":81002,"relative":1,"warnings":[],"unit":"ns"}
|
|
214
|
+
{"task":"repaint/4000 chars","group":"repaint","description":"full repaint every keystroke","samples":3,"mean":2.61e9,"median":2.4e9,"stddevPct":15.3,"relative":47800,"warnings":[{"code":"low-sample-count","data":{"samples":3,"target":10}}],"unit":"ns"}
|
|
179
215
|
```
|
|
180
216
|
|
|
217
|
+
`ostia compare ... --format minimal` adds `delta: { medianPct, meanPct, verdict, pass }` to
|
|
218
|
+
each line, so "did this PR regress" is `lines.some(l => l.delta?.verdict === "regressed")`.
|
|
219
|
+
|
|
181
220
|
Markdown:
|
|
182
221
|
|
|
183
222
|
```
|
|
@@ -383,6 +422,27 @@ group("parse", () => {
|
|
|
383
422
|
})
|
|
384
423
|
```
|
|
385
424
|
|
|
425
|
+
That is the whole registration surface: `group()` and `task()`. Presentation lives in
|
|
426
|
+
the renderers (`--format`), not in the suite file.
|
|
427
|
+
|
|
428
|
+
Both take an optional `description` that flows into the document
|
|
429
|
+
(`Workload.description` / `Workload.groupDescription`) and into `--format minimal`, so
|
|
430
|
+
what a number measures and why travels with the data instead of living only in a
|
|
431
|
+
source comment a reader has to go find:
|
|
432
|
+
|
|
433
|
+
```ts
|
|
434
|
+
group(
|
|
435
|
+
"repaint",
|
|
436
|
+
() => {
|
|
437
|
+
task("1,000 chars", () => repaint(doc1k))
|
|
438
|
+
task("4,000 chars", () => repaint(doc4k), {
|
|
439
|
+
description: "worst case: full repaint every keystroke at the max document size",
|
|
440
|
+
})
|
|
441
|
+
},
|
|
442
|
+
{ description: "editor repaint cost as document size grows" },
|
|
443
|
+
)
|
|
444
|
+
```
|
|
445
|
+
|
|
386
446
|
Mark one task per group as the `Relative` reference with `{ baseline: true }`
|
|
387
447
|
(mirrors mitata's `baseline()`); otherwise `Relative` defaults to the fastest
|
|
388
448
|
task in the group:
|
|
@@ -402,6 +462,7 @@ const doc = await bench({
|
|
|
402
462
|
suites: ["suite.ts"],
|
|
403
463
|
timeBudgetMs: 500,
|
|
404
464
|
minSamples: 50,
|
|
465
|
+
jobs: 1, // suite files at once; > 1 trades fidelity for wall time
|
|
405
466
|
})
|
|
406
467
|
```
|
|
407
468
|
|
|
@@ -435,6 +496,7 @@ Pure functions of a `ProfileDocument`. Each returns `{ text? }` and/or `{ files?
|
|
|
435
496
|
| `markdown` | agent- and human-readable report |
|
|
436
497
|
| `json` | pretty JSON document |
|
|
437
498
|
| `jsonl` | one metadata line, then one line per run |
|
|
499
|
+
| `minimal` | one compact line per timing run, no sample array; for LLM/CI consumption |
|
|
438
500
|
| `collapsed` | folded stacks (`name;name;name count`) |
|
|
439
501
|
| `mermaid` | top-N call tree |
|
|
440
502
|
| `speedscope` | speedscope.app JSON |
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
function g(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",g(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 R(n,a){return{id:e("wl","inprocess",n.name,n.toString()),kind:"inprocess",label:a}}function P(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}}}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:U(n.trials)}}function U(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 h(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 T(n,a,d){let p=await Bun.file(d).arrayBuffer(),k=new Bun.CryptoHasher("sha256");return k.update(p),{id:e("art",n,a,d),kind:a,path:d,sha256:k.digest("hex"),bytes:p.byteLength}}function s(n){return e("cfg",n)}function y(n){return`${JSON.stringify(O(n),null,2)}
|
|
3
|
+
`}async function o(n,a){await Bun.write(a,y(n))}async function t(n){let a=await Bun.file(n).text();return JSON.parse(a)}var _=[],S;function F(n,a,d){let f=S;S={name:n,description:d?.description};try{a()}finally{S=f}}function v(n,a,d){_.push({groupName:S?.name,groupDescription:S?.description,name:n,fn:a,baseline:d?.baseline,opts:d})}function C(){return _}function N(){_.length=0,S=void 0}function x(n){return n.groupName?`${n.groupName}/${n.name}`:n.name}function D(n,a){if(!a)return[...n];let d=new RegExp(a);return n.filter((f)=>d.test(x(f)))}function l(n){if(n.length===0)throw Error("computeTimingStats: samples must be non-empty");let a=n.length,d=L(n),f=0;for(let b=0;b<a;b++)f+=n[b];let p=f/a,k=B(d,0.5),w=0;for(let b=0;b<a;b++){let W=n[b]-p;w+=W*W}let M=Math.sqrt(w/a),H=d[0],E=d[a-1],A=B(d,0.25),q=B(d,0.75),I=q-A,z=A-1.5*I,V=q+1.5*I,G=A-3*I,K=q+3*I,J=0,j=0;for(let b=0;b<a;b++){let W=n[b];if(W<G||W>K)j++;else if(W<z||W>V)J++}return{unit:"ns",samples:n,mean:p,median:k,stddev:M,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 f=a*(d-1),p=Math.floor(f),k=Math.ceil(f);if(p===k)return n[p];let w=f-p;return n[p]*(1-w)+n[k]*w}var Z=5000000,Q=200;function m(n,a,d="subprocess"){let f=[],p=n.samples[0];if(p!==void 0){let w=L(n.samples),M=B(w,0.25),E=B(w,0.75)-M;if(p>n.median+3*E&&E>0)f.push({code:"slow-first-run",message:`First run took ${(p/1e6).toFixed(2)}ms, much slower than the median ${(n.median/1e6).toFixed(2)}ms. Consider more warmup.`,data:{firstNs:p,medianNs:n.median}})}if(n.outliers.mild+n.outliers.severe>0)f.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<Z)f.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<Q)f.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)f.push({code:"nonzero-exit",message:`${k.length} of ${a.length} trial(s) exited non-zero.`,data:{exitCodes:k}});return f}
|
|
4
|
+
export{g,e,c,r,u,R,P,i,h,T,s,y,o,t,l,m,F,v,C,N,x,D};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{g,e,r,u,R,i,h,T,s,y,t,l,m}from"./chunk-3rp84rbb.js";function Ae(o){return o.startsWith("file://")?o.slice(7):o}function oe(o,D,c){let C=o.nodes,x=C.length,v=new Map,N=[],P=new Map,U=new Int32Array(x);for(let W=0;W<x;W++){let O=C[W],S=O.callFrame,_=Ae(S.url),K=v.get(S.functionName);if(K===void 0)K=new Map,v.set(S.functionName,K);let G=K.get(_);if(G===void 0)G=N.length,K.set(_,G),N.push({key:e("fr",S.functionName,_),name:S.functionName,url:_||void 0,line:S.lineNumber>=0?S.lineNumber:void 0,col:S.columnNumber>=0?S.columnNumber:void 0});U[W]=G,P.set(O.id,W)}let M=Array(x);for(let W=0;W<x;W++){let O=C[W];M[W]={id:O.id,frameIx:U[P.get(O.id)],children:O.children??[]}}let F=new Float64Array(x),B=new Float64Array(x),{samples:A,timeDeltas:J}=o;for(let W=0;W<A.length;W++){let O=P.get(A[W]);if(O===void 0)continue;F[O]+=J[W]??0,B[O]+=1}let H=new Int32Array(x).fill(-1);for(let W=0;W<x;W++){let O=C[W].children;if(!O)continue;for(let S of O){let _=P.get(S);if(_!==void 0)H[_]=W}}let E=[],L=[];for(let W=x-1;W>=0;W--)if(H[W]===-1)L.push(W);while(L.length>0){let W=L.pop();E.push(W);let O=C[W].children;if(!O)continue;for(let S of O){let _=P.get(S);if(_!==void 0&&H[_]===W)L.push(_)}}let V=new Float64Array(x);for(let W=E.length-1;W>=0;W--){let O=E[W];V[O]+=F[O];let S=H[O];if(S>=0)V[S]+=V[O]}let z=Array(N.length),j=[];for(let W=0;W<x;W++){let O=M[W].frameIx,S=z[O];if(S)S.selfUs+=F[W],S.totalUs+=V[W],S.samples+=B[W];else{let _={frameIx:O,selfUs:F[W],totalUs:V[W],samples:B[W]};z[O]=_,j.push(_)}}return{origin:D,samplingIntervalUs:c,frames:N,nodes:M,totals:j.sort((W,O)=>O.selfUs-W.selfUs),samples:{nodeIds:o.samples,timeDeltasUs:o.timeDeltas}}}function je(o,D,c,C){let x=["--cpu-prof","--cpu-prof-dir",D,"--cpu-prof-name",c,"--cpu-prof-interval",String(C)],v=o[0];if(v==="bun"||v?.endsWith("/bun"))return[v,...x,...o.slice(1)];return o}async function de(o){let D=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],C=c==="bun"||c?.endsWith("/bun"),x=je(o.argv,o.artifactDir,o.fileName,o.intervalUs),v=C?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(),U=await Bun.spawn(x,{cwd:o.cwd,env:v,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,M=Bun.nanoseconds()-N,F=Bun.file(D);if(!await F.exists())return{diagnosticWallNs:M,exitCode:U,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${D} after exit ${U}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:D,argv:o.argv}}]};let B=await F.json(),A=oe(B,"cpu-prof",o.intervalUs),J=B.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:M,exitCode:U,artifactPath:D,cpu:A,warnings:J}}function fe(o,D="heap-prof"){let{node_fields:c,node_types:C}=o.snapshot.meta,x=c.indexOf("type"),v=c.indexOf("self_size"),N=c.length,P=C[0];if(x===-1||v===-1||!Array.isArray(P))return{origin:D,typeCounts:[],objectCount:o.snapshot.node_count};let U=P.length,M=Array(U),F=new Map,B=[],A=0,J=o.nodes,H=J.length;for(let j=0;j<H;j+=N){let W=J[j+x],O=J[j+v]??0;A+=O;let S;if(W>=0&&W<U){if(S=M[W],S===void 0)S={type:P[W],count:0,bytes:0},M[W]=S,B.push(S)}else{let _=`unknown(${W})`;if(S=F.get(_),S===void 0)S={type:_,count:0,bytes:0},F.set(_,S),B.push(S)}S.count++,S.bytes+=O}let E=B.sort((j,W)=>W.count-j.count),L=E.slice(0,20),V=E.slice(20),z=L.map(({type:j,count:W,bytes:O})=>({type:j,count:W,retainedBytes:O}));if(V.length>0){let j=0,W=0;for(let O of V)j+=O.count,W+=O.bytes;z.push({type:"other",count:j,retainedBytes:W})}return{origin:D,heapSizeBytes:A,objectCount:o.snapshot.node_count,typeCounts:z}}function _e(o,D,c){let C=["--heap-prof","--heap-prof-dir",D,"--heap-prof-name",c],x=o[0];if(x==="bun"||x?.endsWith("/bun"))return[x,...C,...o.slice(1)];return o}async function ge(o){let D=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],C=c==="bun"||c?.endsWith("/bun"),x=_e(o.argv,o.artifactDir,o.fileName),v=C?o.env:{...process.env,...o.env,BUN_OPTIONS:`--heap-prof --heap-prof-dir ${o.artifactDir} --heap-prof-name ${o.fileName}`},N=Bun.nanoseconds(),U=await Bun.spawn(x,{cwd:o.cwd,env:v,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,M=Bun.nanoseconds()-N,F=Bun.file(D);if(!await F.exists())return{diagnosticWallNs:M,exitCode:U,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${D} after exit ${U}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:D,argv:o.argv}}]};let B=await F.json(),A=fe(B,"heap-prof");return{diagnosticWallNs:M,exitCode:U,artifactPath:D,heap:A,warnings:[]}}import{Session as Le}from"inspector/promises";var He=1000;async function he(o,D={}){let c=D.intervalUs??He,C=new Le;C.connect();let x=Bun.nanoseconds();try{await C.post("Profiler.enable"),await C.post("Profiler.setSamplingInterval",{interval:c}),await C.post("Profiler.start");let v=await o(),{profile:N}=await C.post("Profiler.stop"),P=Bun.nanoseconds()-x,U=oe(N,"inspector",c);return{result:v,cpu:U,diagnosticWallNs:P}}finally{C.disconnect()}}import{profile as ze}from"bun:jsc";var Je=new Map([["LLInt","llint"],["Baseline","baseline"],["DFG","dfg"],["FTL","ftl"]]),be=4294967295;function ye(o,D){let c=D??o.interval*1e6,C=new Map,x=[];function v(S,_,K,G){let q=C.get(S);if(q===void 0)q=new Map,C.set(S,q);let Y=_??"",X=q.get(Y);if(X===void 0)X=x.length,q.set(Y,X),x.push({key:e("fr",S,Y),name:S,url:_,line:K,col:G});return X}function N(S){let _=S.line===be,K=_?void 0:S.line-1,G=_||S.column===be?void 0:S.column-1;return v(S.name,S.sourceURL,K,G)}let P=v("(root)",void 0,void 0,void 0),U=1,M={id:0,frameIx:P,children:new Map,selfUs:0,samples:0,totalUs:0},F=new Map([[0,M]]),B={llint:0,baseline:0,dfg:0,ftl:0},A=new Map,J=[],H=[];for(let S of o.traces){let _=S.frames,K=M;for(let Y=_.length-1;Y>=0;Y--){let X=N(_[Y]),ne=K.children.get(X);if(!ne)ne={id:U++,frameIx:X,children:new Map,selfUs:0,samples:0,totalUs:0},K.children.set(X,ne),F.set(ne.id,ne);K=ne}K.selfUs+=c,K.samples+=1,J.push(K.id),H.push(c);let G=_[0],q=G&&Je.get(G.category);if(q){B[q]++;let Y=A.get(q)??new Map;Y.set(K.frameIx,(Y.get(K.frameIx)??0)+1),A.set(q,Y)}}function E(S){let _=S.selfUs;for(let K of S.children.values())_+=E(K);return S.totalUs=_,_}E(M);let L=new Map;function V(S){let _=L.get(S.frameIx);if(_)_.selfUs+=S.selfUs,_.totalUs+=S.totalUs,_.samples+=S.samples;else L.set(S.frameIx,{frameIx:S.frameIx,selfUs:S.selfUs,totalUs:S.totalUs,samples:S.samples});for(let K of S.children.values())V(K)}V(M);let z=[...F.values()].map((S)=>({id:S.id,frameIx:S.frameIx,children:[...S.children.values()].map((_)=>_.id)})),j={origin:"jsc-profile",samplingIntervalUs:c,frames:x,nodes:z,totals:[...L.values()].sort((S,_)=>_.selfUs-S.selfUs),samples:{nodeIds:J,timeDeltasUs:H}},W=[...A.entries()].flatMap(([S,_])=>[..._.entries()].sort((K,G)=>G[1]-K[1]).slice(0,3).map(([K,G])=>({tier:S,frameKey:x[K].key,samples:G})));return{cpu:j,jit:{origin:"jsc-profile",tiers:B,topFramesByTier:W}}}var Ve=1000;async function we(o,D={}){let c=D.intervalUs??Ve,C,x=Bun.nanoseconds(),v=await ze(async()=>(C=await o(),C),c),N=Bun.nanoseconds()-x,{cpu:P,jit:U}=ye(v.stackTraces,c);return{result:C,cpu:P,jit:U,diagnosticWallNs:N}}async function ue(o){let D=Bun.nanoseconds(),c=Bun.spawn(o.argv,{cwd:o.cwd,env:o.env,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),C=await c.exited,x=Bun.nanoseconds(),v=c.resourceUsage?.();return{wallNs:x-D,exitCode:C,userNs:v?Number(v.cpuTime.user)*1000:void 0,systemNs:v?Number(v.cpuTime.system)*1000:void 0,maxRssBytes:v?.maxRSS}}function Re(o){return o.trim().split(/\s+/).filter(Boolean)}var Ke=10,Ge=3000000000,Ye=3;async function f(o){let D=o.warmup??Ye;for(let F=0;F<D;F++)await ue(o);let c=[],C=o.runs??o.minRuns??Ke,x=o.runs!==void 0?0:o.minTotalNs??Ge,v=0,N=0;while(N<C||v<x){let F=await ue(o);if(c.push({i:N,wallNs:F.wallNs,exitCode:F.exitCode,userNs:F.userNs,systemNs:F.systemNs,maxRssBytes:F.maxRssBytes}),v+=F.wallNs,N++,o.runs!==void 0&&N>=o.runs)break}let P=c.map((F)=>F.wallNs),U=l(P),M=m(U,c.map((F)=>F.exitCode));return{trials:c,timing:U,warnings:M}}var qe=new URL("./runner.ts",import.meta.url).pathname,Qe="node_modules/.cache/ostia";function k(){return Math.max(1,navigator.hardwareConcurrency||1)}async function p(o){let c=`${o.outDir??Qe}/bench-tmp`,C=o.cwd??process.cwd(),x=Math.max(1,Math.floor(o.jobs??1)),v={timeBudgetMs:o.timeBudgetMs,minSamples:o.minSamples,gc:o.gc,filter:o.filter},N=Array(o.suites.length),P=new Set,U=0,M,F=async(H)=>{let E=o.suites[H],L=E.startsWith("/")?E:`${C}/${E}`,V=`${c}/${e("bench-out",L)}.json`,z=Bun.spawn(["bun",qe,L,V,JSON.stringify(v)],{cwd:C,stdout:"inherit",stderr:"inherit",stdin:"ignore"});P.add(z);let j=await z.exited;if(P.delete(z),j!==0)throw Error(`Bench suite failed: ${E} (runner exited ${j})`);N[H]=await t(V)},B=async()=>{while(M===void 0&&U<o.suites.length){let H=U++;try{await F(H)}catch(E){M??=E instanceof Error?E:Error(String(E));for(let L of P)L.kill()}}};try{if(await Promise.all(Array.from({length:Math.min(x,o.suites.length)},B)),M)throw M}finally{await Bun.spawn(["rm","-rf",c]).exited}let A=[],J=[];for(let H of N)A.push(...H.workloads),J.push(...H.runs);return r(A,J)}var a={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000};function ie(o,D){if(o===0)return D===0?0:1/0;return(D-o)/o*100}function te(o,D,c){return o.runs.find((C)=>C.workloadId===D&&C.phase===c)}function d(o,D,c=a){let C=new Set(D.workloads.map((v)=>v.id)),x=[];for(let v of o.workloads){if(!C.has(v.id))continue;let N=b(o,D,v.id,c);if(N)x.push(N)}return x}function b(o,D,c,C=a){let x=te(o,c,"timing"),v=te(D,c,"timing"),N=te(o,c,"cpu"),P=te(D,c,"cpu"),U=te(o,c,"heap"),M=te(D,c,"heap"),F=x?.id??N?.id??U?.id,B=v?.id??P?.id??M?.id;if(!F||!B)return;let A=!1,J;if(x?.timing&&v?.timing){let L=ie(x.timing.median,v.timing.median),V=ie(x.timing.mean,v.timing.mean),z=L>C.timingPct?"regressed":L<-C.timingPct?"improved":"unchanged";if(z==="regressed")A=!0;J={medianDeltaPct:L,meanDeltaPct:V,verdict:z}}let H;if(N?.cpu&&P?.cpu){let L=new Map(N.cpu.totals.map((O)=>[N.cpu.frames[O.frameIx].key,O])),V=new Map(P.cpu.totals.map((O)=>[P.cpu.frames[O.frameIx].key,O])),z=new Map(N.cpu.frames.map((O)=>[O.key,O.name])),j=new Map(P.cpu.frames.map((O)=>[O.key,O.name]));H=[...new Set([...L.keys(),...V.keys()])].map((O)=>{let S=L.get(O)?.selfUs??0,_=V.get(O)?.selfUs??0;return{frameKey:O,name:j.get(O)??z.get(O)??O,baseSelfUs:S,candSelfUs:_,deltaPct:ie(S,_)}}).sort((O,S)=>Math.abs(S.deltaPct)-Math.abs(O.deltaPct));for(let O of H)if((O.baseSelfUs>=C.minFrameSelfUs||O.candSelfUs>=C.minFrameSelfUs)&&O.deltaPct>C.frameSelfPct)A=!0}let E;if(U?.heap&&M?.heap){let L=new Map(U.heap.typeCounts.map((j)=>[j.type,j])),V=new Map(M.heap.typeCounts.map((j)=>[j.type,j]));E=[...new Set([...L.keys(),...V.keys()])].map((j)=>{let W=L.get(j),O=V.get(j);return{type:j,baseCount:W?.count??0,candCount:O?.count??0,baseBytes:W?.retainedBytes,candBytes:O?.retainedBytes,deltaPct:ie(W?.count??0,O?.count??0)}}).sort((j,W)=>Math.abs(W.deltaPct)-Math.abs(j.deltaPct));for(let j of E)if(j.deltaPct>C.heapTypePct)A=!0}return{id:e("cmp",F,B),baselineRunId:F,candidateRunId:B,timing:J,frames:H,heapTypes:E,thresholds:C,verdict:A?"fail":"pass"}}function Z(o,D){if(D){let c=o.runs.find((C)=>C.id===D);return c?.cpu?[c]:[]}return o.runs.filter((c)=>c.phase==="cpu"&&c.cpu)}function re(o){let D=o.nodes,c=D.length,C=Xe(o),x=new Int32Array(c).fill(-1);for(let U=0;U<c;U++)for(let M of D[U].children){let F=C(M);if(F!==-1)x[F]=U}let v=[];for(let U=0;U<c;U++)if(x[U]===-1)v.push(U);let N=[],P=[];for(let U=v.length-1;U>=0;U--)P.push(v[U]);while(P.length>0){let U=P.pop();N.push(U);for(let M of D[U].children){let F=C(M);if(F!==-1&&x[F]===U)P.push(F)}}return{count:c,indexOf:C,parentIx:x,roots:v,order:N}}function Xe(o){let D=o.nodes,c=D.length,C=1/0,x=-1/0,v=!0;for(let P=0;P<c;P++){let U=D[P].id;if(!Number.isInteger(U)){v=!1;break}if(U<C)C=U;if(U>x)x=U}if(v&&c>0&&x-C<c*4+64){let P=x-C+1,U=new Int32Array(P).fill(-1);for(let M=0;M<c;M++)U[D[M].id-C]=M;return(M)=>{let F=M-C;return F>=0&&F<P?U[F]:-1}}let N=new Map;for(let P=0;P<c;P++)N.set(D[P].id,P);return(P)=>N.get(P)??-1}function xe(o,D){let{count:c,indexOf:C,parentIx:x,order:v}=D,N=new Float64Array(c),P=new Float64Array(c),U=o.samples?.nodeIds??[],M=o.samples?.timeDeltasUs??[];for(let B=0;B<U.length;B++){let A=C(U[B]);if(A===-1)continue;N[A]+=M[B]??0,P[A]+=1}let F=new Float64Array(c);for(let B=v.length-1;B>=0;B--){let A=v[B];F[A]+=N[A];let J=x[A];if(J>=0)F[J]+=F[A]}return{selfUs:N,totalUs:F,samples:P}}var Pe={name:"collapsed",async render(o,D={}){return{files:Z(o,D.runId).map((x)=>{let v=x.cpu,{nodes:N,frames:P}=v,U=re(v),M=Array(U.count);for(let H of U.order){let E=P[N[H].frameIx].name||"(anonymous)",L=U.parentIx[H];M[H]=L===-1?E:`${M[L]};${E}`}let F=new Float64Array(U.count),B=[],A=v.samples?.nodeIds??[];for(let H=0;H<A.length;H++){let E=U.indexOf(A[H]);if(E===-1)continue;if(F[E]++===0)B.push(E)}let J=Array(B.length);for(let H=0;H<B.length;H++){let E=B[H];J[H]=`${M[E]} ${F[E]}`}return{path:`${x.id}.collapsed.txt`,content:J.join(`
|
|
3
|
+
`)+(J.length>0?`
|
|
4
|
+
`:"")}})}}};var Te={name:"cpuprofile",async render(o,D={}){let c=Z(o,D.runId),C=[],x=[];for(let v of c){if(v.cpu?.origin!=="cpu-prof"&&v.cpu?.origin!=="inspector"){x.push(`${v.id} (origin ${v.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let N=v.artifacts.find((U)=>U.kind==="cpuprofile");if(!N){x.push(`${v.id} (no cpuprofile artifact recorded on this run)`);continue}let P=Bun.file(N.path);if(!await P.exists()){x.push(`${v.id} (artifact missing on disk: ${N.path})`);continue}C.push({path:`${v.id}.cpuprofile`,content:await P.text()})}if(C.length===0&&x.length>0)return{text:`No .cpuprofile artifacts available:
|
|
5
|
+
${x.map((v)=>` - ${v}`).join(`
|
|
6
|
+
`)}
|
|
7
|
+
`};return{files:C}}};var $e={name:"json",async render(o){return{text:y(o)}}};var ke={name:"jsonl",async render(o){let{runs:D,...c}=o;return{text:`${[g(c),...D.map((x)=>g(x))].join(`
|
|
8
|
+
`)}
|
|
9
|
+
`}}};function ee(o){return(o/1e6).toFixed(3)}function ae(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??o?.id??"unknown"}var ve=10,Ce=10,Ne={name:"markdown",async render(o){let D=new Map(o.workloads.map((x)=>[x.id,x])),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 C=o.runs.filter((x)=>x.phase==="timing"&&x.timing!==void 0);if(C.length>0){c.push("## Timing",""),c.push("| Command | Mean \xB1 SD (ms) | Min\u2026Max (ms) | Median (ms) |","|---|---|---|---|");for(let v of C){let N=ae(D.get(v.workloadId)),P=v.timing;c.push(`| ${N} | ${ee(P.mean)} \xB1 ${ee(P.stddev)} | ${ee(P.min)}\u2026${ee(P.max)} | ${ee(P.median)} |`)}c.push("");let x=C.filter((v)=>v.warnings.length>0);if(x.length>0){c.push("### Warnings","");for(let v of x){let N=ae(D.get(v.workloadId));for(let P of v.warnings)c.push(`- **${N}**: ${P.message} (\`${P.code}\`)`)}c.push("")}}for(let x of o.runs){if(x.phase!=="cpu"&&x.phase!=="heap")continue;let v=ae(D.get(x.workloadId));if(x.phase==="cpu"){if(c.push(`## CPU capture - ${v}`,""),c.push(`instrumented, diagnostic wall ${ee(x.diagnosticWallNs??0)}ms`,""),x.cpu){c.push(`origin: \`${x.cpu.origin}\`, interval: ${x.cpu.samplingIntervalUs}\xB5s`,""),c.push("| Self % | Self (ms) | Total (ms) | Frame |","|---|---|---|---|");let N=x.cpu.totals.reduce((P,U)=>P+U.selfUs,0)||1;for(let P of x.cpu.totals.slice(0,ve)){let U=x.cpu.frames[P.frameIx],M=(P.selfUs/N*100).toFixed(1);c.push(`| ${M}% | ${(P.selfUs/1000).toFixed(2)} | ${(P.totalUs/1000).toFixed(2)} | ${U?.name||"(anonymous)"} |`)}if(c.push(""),x.jit){let P=x.jit.tiers;c.push(`JIT tiers: LLInt ${P.llint} \xB7 Baseline ${P.baseline} \xB7 DFG ${P.dfg} \xB7 FTL ${P.ftl}`,"")}}}else if(c.push(`## Heap snapshot - ${v}`,""),c.push(`instrumented, diagnostic wall ${ee(x.diagnosticWallNs??0)}ms`,""),x.heap){c.push(`${x.heap.objectCount??"?"} objects, ${((x.heap.heapSizeBytes??0)/1e6).toFixed(2)}MB`,""),c.push("| Count | Type |","|---|---|");for(let N of x.heap.typeCounts.slice(0,Ce))c.push(`| ${N.count} | ${N.type} |`);c.push("")}for(let N of x.artifacts)c.push(`- artifact: \`${N.path}\``);for(let N of x.warnings)c.push(`- ! ${N.message} (\`${N.code}\`)`);if(x.artifacts.length>0||x.warnings.length>0)c.push("")}if(o.comparisons&&o.comparisons.length>0){c.push("## Comparisons","");for(let x of o.comparisons){let v=o.runs.find((P)=>P.id===x.candidateRunId),N=ae(v?D.get(v.workloadId):void 0);if(c.push(`### ${x.verdict==="pass"?"\u2713":"\u2717"} ${N}`,""),x.timing){let P=x.timing.medianDeltaPct>0?"+":"";c.push(`- timing: ${P}${x.timing.medianDeltaPct.toFixed(1)}% median (**${x.timing.verdict}**)`)}for(let P of x.frames?.slice(0,ve)??[]){if(Math.abs(P.deltaPct)<0.5)continue;let U=P.deltaPct>0?"+":"";c.push(`- frame \`${P.name}\`: ${U}${P.deltaPct.toFixed(1)}% self-time (${(P.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(P.candSelfUs/1000).toFixed(2)}ms)`)}for(let P of x.heapTypes?.slice(0,Ce)??[]){if(Math.abs(P.deltaPct)<0.5)continue;let U=P.deltaPct>0?"+":"";c.push(`- heap \`${P.type}\`: ${U}${P.deltaPct.toFixed(1)}% count (${P.baseCount} \u2192 ${P.candCount})`)}c.push("")}}return{text:c.join(`
|
|
10
|
+
`)}}};var Ze=15;function pe(o){return`n${o}`}function en(o,D,c){return`${(o||"(anonymous)").replace(/"/g,"'")} (self ${(D/1000).toFixed(2)}ms, total ${(c/1000).toFixed(2)}ms)`}function nn(o,D,c,C){let x=[];if(C<=0)return x;for(let v=0;v<D;v++){if(v===c)continue;let N=o[v];if(x.length===C&&N<=o[x[C-1]])continue;let P=x.length;while(P>0&&o[x[P-1]]<N)P--;if(x.splice(P,0,v),x.length>C)x.pop()}return x}var Ie={name:"mermaid",async render(o,D={}){let c=D.topN??Ze;return{files:Z(o,D.runId).map((v)=>{let N=v.cpu,{nodes:P,frames:U}=N,M=re(N),{selfUs:F,totalUs:B}=xe(N,M),{parentIx:A}=M,J=M.roots[0]??-1,H=nn(F,M.count,J,c),E=new Set(J!==-1?[J]:[]),L=[];for(let z of H){L.length=0;for(let j=z;j!==-1;j=A[j])L.push(j);for(let j=L.length-1;j>=0;j--)E.add(L[j])}let V=["graph TD"];for(let z of E){let j=P[z].id;V.push(` ${pe(j)}["${en(U[P[z].frameIx].name,F[z],B[z])}"]`)}for(let z of E){let j=A[z];if(j!==-1&&E.has(j))V.push(` ${pe(P[j].id)} --> ${pe(P[z].id)}`)}return{path:`${v.id}.mermaid.md`,content:`${V.join(`
|
|
11
|
+
`)}
|
|
12
|
+
`}})}}};function Ue(o){if(!o?.entry)return;if(o.entry.group!==void 0)return o.entry.group;let D=o.entry.task,c=D.lastIndexOf("/");return c===-1?void 0:D.slice(0,c)}function ce(o){let D=Math.min(...o.map((x)=>x.run.timing.median)),c=new Map;for(let x of o){let v=Ue(x.workload);if(v===void 0)continue;let N=c.get(v);if(N)N.push(x);else c.set(v,[x])}let C=new Map;for(let x of o){let v=Ue(x.workload);if(v===void 0){C.set(x,D);continue}let N=c.get(v)??[x],P=N.find((U)=>U.workload?.baseline);C.set(x,P?P.run.timing.median:Math.min(...N.map((U)=>U.run.timing.median)))}return C}function Q(o){return Number.isFinite(o)?Number(o.toPrecision(6)):o}function tn(o,D){return o?.entry?.task??o?.label??o?.command?.join(" ")??D.workloadId}function rn(o){let D=new Map(o.workloads.map((v)=>[v.id,v])),c=o.runs.filter((v)=>v.phase==="timing"&&v.timing!==void 0).map((v)=>({run:v,workload:D.get(v.workloadId)})),C=c.length>1?ce(c):void 0,x=new Map((o.comparisons??[]).map((v)=>[v.candidateRunId,v]));return c.map((v)=>{let{run:N,workload:P}=v,U=N.timing,M={task:tn(P,N),unit:"ns",samples:U.samples.length,mean:Q(U.mean),median:Q(U.median),stddev:Q(U.stddev),stddevPct:Q(U.mean===0?0:U.stddev/U.mean*100),min:Q(U.min),max:Q(U.max),warnings:N.warnings.map((B)=>B.data?{code:B.code,data:B.data}:{code:B.code})};if(P?.entry?.group!==void 0)M.group=P.entry.group;if(P?.description!==void 0)M.description=P.description;if(P?.groupDescription!==void 0)M.groupDescription=P.groupDescription;if(C)M.relative=Q(U.median/(C.get(v)??U.median));if(P?.baseline)M.baseline=!0;let F=x.get(N.id);if(F?.timing)M.delta={medianPct:Q(F.timing.medianDeltaPct),meanPct:Q(F.timing.meanDeltaPct),verdict:F.timing.verdict,pass:F.verdict==="pass"};return M})}var De={name:"minimal",async render(o){let D=rn(o).map((c)=>JSON.stringify(c));return{text:D.length>0?`${D.join(`
|
|
13
|
+
`)}
|
|
14
|
+
`:""}}};var sn="https://www.speedscope.app/file-format-schema.json";function Fe(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??"profile"}var Me={name:"speedscope",async render(o,D={}){let c=Z(o,D.runId),C=new Map(o.workloads.map((v)=>[v.id,v]));return{files:c.map((v)=>{let N=v.cpu,{nodes:P}=N,U=re(N),M=N.samples?.nodeIds??[],F=N.samples?.timeDeltasUs??[],B=Array(U.count);for(let E of U.order){let L=U.parentIx[E],V=P[E].frameIx;B[E]=L===-1?[V]:[...B[L],V]}let A=Array(M.length);for(let E=0;E<M.length;E++){let L=U.indexOf(M[E]);A[E]=L===-1?[]:B[L]}let J=0;for(let E=0;E<F.length;E++)J+=F[E];let H={$schema:sn,exporter:"ostia",name:Fe(C.get(v.workloadId)),activeProfileIndex:0,shared:{frames:N.frames.map((E)=>({name:E.name||"(anonymous)",file:E.url,line:E.line!==void 0?E.line+1:void 0}))},profiles:[{type:"sampled",name:Fe(C.get(v.workloadId)),unit:"microseconds",startValue:0,endValue:J,samples:A,weights:F}]};return{path:`${v.id}.speedscope.json`,content:`${JSON.stringify(H,null,2)}
|
|
15
|
+
`}})}}};function se(o){return(o/1e6).toFixed(3)}function le(o){return o.label??o.command?.join(" ")??o.entry?.task??o.id}var Be={name:"table",async render(o){let D=o.runs.filter((B)=>B.phase==="timing"&&B.timing!==void 0),c=new Map(o.workloads.map((B)=>[B.id,B]));if(D.length===0){let B=Se(o,c);return{text:B.length>0?`${B.join(`
|
|
16
|
+
`)}
|
|
17
|
+
`:`(no timing runs)
|
|
18
|
+
`}}let C=D.map((B)=>{let A=c.get(B.workloadId);return{run:B,workload:A,label:A?le(A):B.workloadId}}),x=C.length>1,v=ce(C),N=[],P=Math.max(7,...C.map((B)=>B.label.length)),U=x?`${"Command".padEnd(P)} Mean [ms] Min\u2026Max [ms] Relative`:`${"Command".padEnd(P)} Mean [ms] Min\u2026Max [ms]`;N.push(U),N.push("-".repeat(U.length));for(let B of C){let{run:A,label:J,workload:H}=B,E=A.timing,L=`${se(E.mean)} \xB1 ${se(E.stddev)}`,V=`${se(E.min)}\u2026${se(E.max)}`,z=`${J.padEnd(P)} ${L.padEnd(15)} ${V.padEnd(18)}`;if(x){let j=E.median/(v.get(B)??E.median);if(j===1)z+=H?.baseline?" 1.00\xD7 (baseline)":" 1.00\xD7";else if(j>1)z+=` ${j.toFixed(2)}\xD7 slower`;else z+=` ${(1/j).toFixed(2)}\xD7 faster`}N.push(z);for(let j of A.warnings)N.push(` ! ${j.message}`)}let M=an(o,c);if(M.length>0)N.push(""),N.push(...M);let F=Se(o,c);if(F.length>0)N.push(""),N.push(...F);return{text:`${N.join(`
|
|
19
|
+
`)}
|
|
20
|
+
`}}};function on(o,D,c){let C=o.runs.find((v)=>v.id===c),x=C?D.get(C.workloadId):void 0;return x?le(x):c}function Se(o,D){if(!o.comparisons||o.comparisons.length===0)return[];let c=[];for(let C of o.comparisons){let x=on(o,D,C.candidateRunId),v=C.verdict==="pass"?"\u2713":"\u2717";if(c.push(`${v} ${x}`),C.timing){let N=C.timing.medianDeltaPct>0?"+":"";c.push(` timing: ${N}${C.timing.medianDeltaPct.toFixed(1)}% median (${C.timing.verdict})`)}if(C.frames)for(let N of C.frames.slice(0,We)){if(Math.abs(N.deltaPct)<0.5)continue;let P=N.deltaPct>0?"+":"";c.push(` frame ${N.name}: ${P}${N.deltaPct.toFixed(1)}% self-time (${(N.baseSelfUs/1000).toFixed(2)}ms -> ${(N.candSelfUs/1000).toFixed(2)}ms)`)}if(C.heapTypes)for(let N of C.heapTypes.slice(0,Oe)){if(Math.abs(N.deltaPct)<0.5)continue;let P=N.deltaPct>0?"+":"";c.push(` heap ${N.type}: ${P}${N.deltaPct.toFixed(1)}% count (${N.baseCount} -> ${N.candCount})`)}}return c}var We=5,Oe=5;function an(o,D){let c=[];for(let C of o.runs){if(C.phase!=="cpu"&&C.phase!=="heap")continue;let x=D.get(C.workloadId),v=x?le(x):C.workloadId;if(C.phase==="cpu")if(C.cpu){c.push(`CPU capture - ${v} (instrumented, ${C.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${se(C.diagnosticWallNs??0)}ms)`);let N=C.cpu.totals.reduce((P,U)=>P+U.selfUs,0)||1;for(let P of C.cpu.totals.slice(0,We)){let U=C.cpu.frames[P.frameIx],M=(P.selfUs/N*100).toFixed(1);c.push(` ${M.padStart(5)}% ${(P.selfUs/1000).toFixed(2).padStart(8)}ms self ${U?.name??"?"}`)}}else c.push(`CPU capture - ${v} (instrumented, no evidence captured)`);else if(C.heap){let N=((C.heap.heapSizeBytes??0)/1e6).toFixed(2);c.push(`Heap snapshot - ${v} (instrumented, ${C.heap.objectCount??"?"} objects, ${N}MB)`);for(let P of C.heap.typeCounts.slice(0,Oe))c.push(` ${String(P.count).padStart(6)} ${P.type}`)}else c.push(`Heap snapshot - ${v} (instrumented, no evidence captured)`);for(let N of C.artifacts)c.push(` artifact: ${N.path}`);for(let N of C.warnings)c.push(` ! ${N.message}`)}return c}var n={table:Be,json:$e,markdown:Ne,jsonl:ke,minimal:De,collapsed:Pe,mermaid:Ie,speedscope:Me,cpuprofile:Te};var cn="node_modules/.cache/ostia",me=1000;async function w(o){let D=s({runs:o.runs??null,warmup:o.warmup??null,cpu:o.cpu??!1,heap:o.heap??!1,cpuIntervalUs:o.cpuIntervalUs??me}),C=`${o.outDir??cn}/artifacts`,x=[],v=[];for(let N of o.commands){let P=Array.isArray(N)?N:Re(N),U=u(P,Array.isArray(N)?void 0:N);x.push(U);let M=await f({argv:P,cwd:o.cwd,env:o.env,runs:o.runs,warmup:o.warmup}),F=i({workload:U,configFingerprint:D,trials:M.trials,timing:M.timing,warnings:M.warnings});if(v.push(F),o.cpu){let B=`${F.id}-cpu.cpuprofile`,A=await de({argv:P,cwd:o.cwd,env:o.env,artifactDir:C,fileName:B,intervalUs:o.cpuIntervalUs??me});v.push(await Ee({workload:U,phase:"cpu",configFingerprint:D,diagnosticWallNs:A.diagnosticWallNs,exitCode:A.exitCode,cpu:A.cpu,artifactPath:A.artifactPath,artifactKind:"cpuprofile",warnings:A.warnings}))}if(o.heap){let B=`${F.id}-heap.heapsnapshot`,A=await ge({argv:P,cwd:o.cwd,env:o.env,artifactDir:C,fileName:B});v.push(await Ee({workload:U,phase:"heap",configFingerprint:D,diagnosticWallNs:A.diagnosticWallNs,exitCode:A.exitCode,heap:A.heap,artifactPath:A.artifactPath,artifactKind:"heapsnapshot",warnings:A.warnings}))}}return r(x,v)}async function Ee(o){let D=`${o.workload.id}-${o.phase}-${o.configFingerprint}`,c=o.artifactPath?[await T(D,o.artifactKind,o.artifactPath)]:[];return h({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 I(o,D={}){let c=R(o),C=s({intervalUs:D.intervalUs??me,origin:D.origin??"inspector"}),x=(M)=>M.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(D.origin==="jsc"){let{result:M,cpu:F,jit:B,diagnosticWallNs:A}=await we(o,D),J=h({workload:c,phase:"cpu",configFingerprint:C,diagnosticWallNs:A,cpu:F,jit:B,warnings:x(F),artifacts:[]});return{result:M,run:J}}let{result:v,cpu:N,diagnosticWallNs:P}=await he(o,D),U=h({workload:c,phase:"cpu",configFingerprint:C,diagnosticWallNs:P,cpu:N,warnings:x(N),artifacts:[]});return{result:v,run:U}}
|
|
21
|
+
export{k,p,a,d,b,f,n,w,I};
|
package/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{
|
|
4
|
-
`)}var
|
|
3
|
+
import{k,p,a,d,b,f,n,w}from"./chunk-s1d2tx3w.js";import{e,c,r,u,i,s,o,t}from"./chunk-3rp84rbb.js";function q(m){return e("cache",m.workloadId,m.phase,m.configFingerprint,m.bunVersion,m.toolVersion,m.instrumented,m.inputsDigest??null)}async function J(m,l=process.cwd()){if(m.length===0)return;let h=new Set;for(let x of m){let C=new Bun.Glob(x);for await(let y of C.scan({cwd:l,absolute:!1}))h.add(y)}let P=[...h].sort(),g=await Promise.all(P.map(async(x)=>{let C=await Bun.file(`${l}/${x}`).arrayBuffer();return{path:x,sha256:Bun.CryptoHasher.hash("sha256",C,"hex")}}));return e("inputs",g)}function _(m,l){return`${m}/cache/${l}.json`}async function L(m,l){let h=Bun.file(_(m,l));if(!await h.exists())return;return await h.json()}async function M(m,l,h){await Bun.write(_(m,l),`${JSON.stringify(h,null,2)}
|
|
4
|
+
`)}var X="node_modules/.cache/ostia",Q=".ostia/baselines",Y={runs:null,warmup:3,outDir:X,baselineDir:Q,baseline:"main",cpuIntervalUs:1000,thresholds:a,workloads:[]};async function W(m="ostia.config.json"){let l=Bun.file(m);if(!await l.exists())return;let h=await l.json();return{...Y,...h,thresholds:{...a,...h.thresholds??{}}}}function V(m,l){return`${m.baselineDir}/${l??m.baseline}.json`}class T extends Error{path;constructor(m){super(`No baseline document at ${m}. Create one with: ostia run --export-json ${m} <command...>`);this.path=m}}async function z(m){let{config:l}=m,h=V(l,m.baselineName);if(!await Bun.file(h).exists())throw new T(h);let g=await t(h),x=[],C=0,y=0,F=0;for(let R of l.workloads){let A=u(R.command,R.label),Z=await J(R.inputs??[]),v=s({runs:l.runs,warmup:l.warmup}),U=q({workloadId:A.id,phase:"timing",configFingerprint:v,bunVersion:Bun.version,toolVersion:c,instrumented:!1,inputsDigest:Z}),H=m.full?void 0:await L(l.outDir,U),S,B;if(H)S=H,B="cached",y++;else{C++;let O=await f({argv:R.command,runs:l.runs??void 0,warmup:l.warmup});S=i({workload:A,configFingerprint:v,trials:O.trials,timing:O.timing,warnings:O.warnings}),await M(l.outDir,U,S),B="executed",F++}x.push({workload:A,status:B,run:S})}let D=r(x.map((R)=>R.workload),x.map((R)=>R.run)),N=0,E=0,j=0;for(let R of x){let A=b(g,D,R.workload.id,l.thresholds);if(!A){j++;continue}if(R.comparison=A,A.verdict==="pass")N++;else E++}return D.comparisons=x.map((R)=>R.comparison).filter((R)=>R!==void 0),{document:D,summary:{total:l.workloads.length,affected:C,cached:y,executed:F,passed:N,regressed:E,missingBaseline:j,results:x}}}function K(m){let l=[];if(l.push(`${m.total} workloads`),l.push(`${m.affected} affected by this change`),l.push(`${m.cached} cached`),l.push(`${m.executed} executed`),m.missingBaseline>0)l.push(`${m.missingBaseline} skipped (no matching baseline workload)`);let h=m.results.filter((P)=>P.comparison?.verdict==="fail").map((P)=>{let g=P.comparison.timing,x=P.workload.label??P.workload.command?.join(" ")??P.workload.id;return g?`${g.medianDeltaPct>0?"+":""}${g.medianDeltaPct.toFixed(1)}% median on ${x}`:x});return l.push(`${m.passed} passed ${m.regressed} regressed${h.length>0?` (${h.join(", ")})`:""}`),l.push(""),l.push(`Profile CI: ${m.regressed>0?"\u2717":"\u2713"}`),`${l.join(`
|
|
5
5
|
`)}
|
|
6
|
-
`}async function
|
|
7
|
-
`)}else if(
|
|
6
|
+
`}async function I(m,l){if(m.text)process.stdout.write(m.text);if(!m.files||m.files.length===0)return;if(l)for(let h of m.files){let P=h.path?`${l}/${h.path}`:l;await Bun.write(P,h.content),process.stdout.write(`wrote ${P}
|
|
7
|
+
`)}else if(m.files.length===1)process.stdout.write(m.files[0].content);else for(let h of m.files)process.stdout.write(`--- ${h.path??"(unnamed)"} ---
|
|
8
8
|
${h.content}
|
|
9
|
-
`)}var
|
|
9
|
+
`)}var ee=`ostia run [flags] <command...>
|
|
10
10
|
|
|
11
11
|
Run one or more commands N times with warmup and report timing statistics.
|
|
12
12
|
|
|
@@ -18,7 +18,7 @@ Flags:
|
|
|
18
18
|
--cpu-interval USEC CPU sampling interval in microseconds (default: 1000)
|
|
19
19
|
--out-dir PATH directory for captured artifacts (default: node_modules/.cache/ostia)
|
|
20
20
|
--export-json PATH write the full ProfileDocument to PATH
|
|
21
|
-
--format FORMAT table | json (default: table)
|
|
21
|
+
--format FORMAT table | json | jsonl | markdown | minimal (default: table)
|
|
22
22
|
--quiet suppress the rendered report (still writes --export-json)
|
|
23
23
|
--help show this message
|
|
24
24
|
|
|
@@ -30,7 +30,7 @@ Examples:
|
|
|
30
30
|
ostia run --runs 25 --warmup 3 "bun a.ts" "bun b.ts"
|
|
31
31
|
ostia run --cpu --heap "bun src/server.ts"
|
|
32
32
|
ostia run --format json "bun a.ts"
|
|
33
|
-
`,
|
|
33
|
+
`,te=`ostia bench [flags] <suite.ts...>
|
|
34
34
|
|
|
35
35
|
Run in-process benchmark suites (registered via group()/task()). Each suite file runs
|
|
36
36
|
in its own spawned child process (isolated from CLI startup state).
|
|
@@ -38,14 +38,27 @@ in its own spawned child process (isolated from CLI startup state).
|
|
|
38
38
|
Flags:
|
|
39
39
|
--time-budget MS sampling budget per task; always runs at least this long (default: 500)
|
|
40
40
|
--min-samples N hard floor on samples per task, kept even when it overruns the
|
|
41
|
-
budget. Default: cost-aware - as many as fit in the budget,
|
|
42
|
-
|
|
41
|
+
budget. Default: cost-aware - as many as fit in the budget (max 20),
|
|
42
|
+
but never below the floor the task's per-trial cost earns it: 3 at
|
|
43
|
+
<=1ms, +2 per decade of cost, 10 from ~3s up. Cheap tasks are
|
|
44
|
+
time-bound and collect thousands either way; only the few expensive
|
|
45
|
+
tasks in a suite pay for the extra rigor. A run that ends below its
|
|
46
|
+
cost-class floor (only possible with an explicit --min-samples or
|
|
47
|
+
per-task minSamples) carries a "low-sample-count" warning.
|
|
48
|
+
--jobs N|auto suite files to run at once, each still in its own process (default: 1).
|
|
49
|
+
Concurrent CPU-bound processes contend for cores, caches and turbo
|
|
50
|
+
headroom, so numbers taken at --jobs > 1 are noisier and not
|
|
51
|
+
like-for-like with a baseline measured at 1. "auto" = CPU count.
|
|
43
52
|
--gc Bun.gc(true) between trials (default: off - hides allocation cost)
|
|
44
53
|
--filter REGEX only run tasks whose "group/name" id matches this regex (substring,
|
|
45
54
|
case-sensitive; unmatched tasks are skipped, not timed)
|
|
46
55
|
--out-dir PATH directory for scratch IPC files (default: node_modules/.cache/ostia)
|
|
47
56
|
--export-json PATH write the full ProfileDocument to PATH
|
|
48
|
-
--format FORMAT table | json (default: table)
|
|
57
|
+
--format FORMAT table | json | jsonl | markdown | minimal (default: table)
|
|
58
|
+
"minimal" is one compact JSON object per task with no raw sample
|
|
59
|
+
array: {task, group, description, samples, mean, median, stddevPct,
|
|
60
|
+
relative, warnings[{code,data}]} in ns - built to pipe into an LLM
|
|
61
|
+
agent's context.
|
|
49
62
|
--quiet suppress the rendered report (still writes --export-json)
|
|
50
63
|
--help show this message
|
|
51
64
|
|
|
@@ -54,31 +67,35 @@ Suite files register tasks like:
|
|
|
54
67
|
group("parse", () => {
|
|
55
68
|
task("small input", () => parse(smallBuf))
|
|
56
69
|
task("full pipeline", () => build(), { timeBudgetMs: 2000, minSamples: 10 })
|
|
57
|
-
})
|
|
70
|
+
}, { description: "parser throughput on representative inputs" })
|
|
58
71
|
Per-task options override --time-budget / --min-samples for that task only.
|
|
72
|
+
Optional { description } on group() and task() flows into the document (Workload.description
|
|
73
|
+
/ Workload.groupDescription) so the intent travels with the numbers.
|
|
59
74
|
|
|
60
75
|
Examples:
|
|
61
76
|
ostia bench benches/parse.ts
|
|
62
77
|
ostia bench --time-budget 1000 --min-samples 50 benches/*.ts
|
|
63
78
|
ostia bench benches/*.ts --filter parse
|
|
64
|
-
|
|
79
|
+
ostia bench benches/*.ts --jobs auto --format minimal
|
|
80
|
+
`,G=`ostia compare <base.json> <candidate.json>
|
|
65
81
|
ostia compare <candidate.json> --baseline <path.json>
|
|
66
82
|
|
|
67
83
|
Compare two ProfileDocuments (matched by workload id) and rank timing/frame/heap deltas.
|
|
68
84
|
|
|
69
85
|
Flags:
|
|
70
86
|
--export-json PATH write the resulting document (with comparisons) to PATH
|
|
71
|
-
--format FORMAT table | json (default: table)
|
|
87
|
+
--format FORMAT table | json | jsonl | markdown | minimal (default: table)
|
|
88
|
+
"minimal" adds delta: {medianPct, verdict, pass} to each task line
|
|
72
89
|
--quiet suppress the rendered report (still writes --export-json)
|
|
73
90
|
--help show this message
|
|
74
91
|
|
|
75
92
|
Examples:
|
|
76
93
|
ostia compare before.json after.json
|
|
77
94
|
ostia compare after.json --baseline .ostia/baselines/main.json
|
|
78
|
-
`,
|
|
95
|
+
`,re=`ostia report <document.json> [--format table|json|markdown|jsonl|minimal]
|
|
79
96
|
|
|
80
97
|
Render a saved ProfileDocument.
|
|
81
|
-
`,
|
|
98
|
+
`,se=`ostia viz <document.json> --format FORMAT [--run <id>] [--out-dir PATH]
|
|
82
99
|
|
|
83
100
|
Render CPU evidence from a saved ProfileDocument as a visualization artifact. Files,
|
|
84
101
|
not a GUI - hand the output to speedscope.app, flamegraph.pl, or
|
|
@@ -99,7 +116,7 @@ Flags:
|
|
|
99
116
|
Examples:
|
|
100
117
|
ostia viz run.json --format speedscope --out-dir node_modules/.cache/ostia/viz
|
|
101
118
|
ostia viz run.json --format collapsed | flamegraph.pl > flame.svg
|
|
102
|
-
`,
|
|
119
|
+
`,ne=`ostia ci [--full] [--baseline NAME]
|
|
103
120
|
|
|
104
121
|
Load ostia.config.json, run configured workloads (reusing cached results when their
|
|
105
122
|
fingerprint is unchanged), compare against the named baseline, and gate on regressions.
|
|
@@ -112,21 +129,22 @@ Flags:
|
|
|
112
129
|
--help show this message
|
|
113
130
|
|
|
114
131
|
Exit codes: 0 pass, 1 regression, 2 harness error (missing config/baseline, spawn failure).
|
|
115
|
-
`;function
|
|
132
|
+
`;function oe(m){let l=[],h,P,g=!1,x=!1,C,y,F,D="table",N=!1,E=!1;for(let j=0;j<m.length;j++){let R=m[j];switch(R){case"--runs":h=Number(m[++j]);break;case"--warmup":P=Number(m[++j]);break;case"--cpu":g=!0;break;case"--heap":x=!0;break;case"--cpu-interval":C=Number(m[++j]);break;case"--out-dir":y=m[++j];break;case"--export-json":F=m[++j];break;case"--format":D=m[++j];break;case"--quiet":N=!0;break;case"--help":case"-h":E=!0;break;default:l.push(R)}}return{commands:l,runs:h,warmup:P,cpu:g,heap:x,cpuIntervalUs:C,outDir:y,exportJson:F,format:D,quiet:N,help:E}}async function ae(m){let l=oe(m);if(l.help||l.commands.length===0)return process.stdout.write(ee),l.help?0:2;if(!(l.format in n))return process.stderr.write(`Unknown --format "${l.format}". Expected one of: ${Object.keys(n).join(", ")}
|
|
116
133
|
`),2;let h;try{h=await w({commands:l.commands,runs:l.runs,warmup:l.warmup,cpu:l.cpu,heap:l.heap,cpuIntervalUs:l.cpuIntervalUs,outDir:l.outDir})}catch(g){return process.stderr.write(`Run failed: ${g instanceof Error?g.message:String(g)}
|
|
117
|
-
`),2}if(l.exportJson)await o(h,l.exportJson);if(!l.quiet){let
|
|
118
|
-
`),2;
|
|
119
|
-
`),2
|
|
120
|
-
`),2}
|
|
121
|
-
`),2}let g=await n[l.format].render(
|
|
122
|
-
`),2;let h;
|
|
134
|
+
`),2}if(l.exportJson)await o(h,l.exportJson);if(!l.quiet){let x=await n[l.format].render(h,{});await I(x)}return h.runs.some((g)=>g.trials.some((x)=>x.exitCode!==void 0&&x.exitCode!==0))?1:0}function ie(m){let l=[],h,P,g,x=!1,C,y,F,D="table",N=!1,E=!1;for(let j=0;j<m.length;j++){let R=m[j];switch(R){case"--time-budget":h=Number(m[++j]);break;case"--min-samples":P=Number(m[++j]);break;case"--jobs":{let A=m[++j];g=A==="auto"?k():Number(A);break}case"--gc":x=!0;break;case"--filter":C=m[++j];break;case"--out-dir":y=m[++j];break;case"--export-json":F=m[++j];break;case"--format":D=m[++j];break;case"--quiet":N=!0;break;case"--help":case"-h":E=!0;break;default:l.push(R)}}return{suites:l,timeBudgetMs:h,minSamples:P,jobs:g,gc:x,filter:C,outDir:y,exportJson:F,format:D,quiet:N,help:E}}async function ue(m){let l=ie(m);if(l.help||l.suites.length===0)return process.stdout.write(te),l.help?0:2;if(!(l.format in n))return process.stderr.write(`Unknown --format "${l.format}". Expected one of: ${Object.keys(n).join(", ")}
|
|
135
|
+
`),2;if(l.jobs!==void 0&&!(l.jobs>=1))return process.stderr.write(`--jobs expects a positive integer or "auto".
|
|
136
|
+
`),2;let h;try{h=await p({suites:l.suites,timeBudgetMs:l.timeBudgetMs,minSamples:l.minSamples,jobs:l.jobs,gc:l.gc,filter:l.filter,outDir:l.outDir})}catch(P){return process.stderr.write(`Bench failed: ${P instanceof Error?P.message:String(P)}
|
|
137
|
+
`),2}if(l.exportJson)await o(h,l.exportJson);if(!l.quiet){let g=await n[l.format].render(h,{});await I(g)}return 0}function le(m){let l=[],h,P,g="table",x=!1,C=!1;for(let y=0;y<m.length;y++){let F=m[y];switch(F){case"--baseline":h=m[++y];break;case"--export-json":P=m[++y];break;case"--format":g=m[++y];break;case"--quiet":x=!0;break;case"--help":case"-h":C=!0;break;default:l.push(F)}}return{paths:l,baseline:h,exportJson:P,format:g,quiet:x,help:C}}async function ce(m){let l=le(m);if(l.help)return process.stdout.write(G),0;let h,P;if(l.baseline)h=l.baseline,P=l.paths[0];else h=l.paths[0],P=l.paths[1];if(!h||!P)return process.stdout.write(G),2;let g,x;try{[g,x]=await Promise.all([t(h),t(P)])}catch(D){return process.stderr.write(`Failed to load documents: ${D instanceof Error?D.message:String(D)}
|
|
138
|
+
`),2}let C=d(g,x),y={...x,comparisons:C};if(l.exportJson)await o(y,l.exportJson);if(!l.quiet){let N=await n[l.format].render(y,{});await I(N)}return C.some((D)=>D.verdict==="fail")?1:0}function de(m){let l,h="table",P=!1;for(let g=0;g<m.length;g++){let x=m[g];switch(x){case"--format":h=m[++g];break;case"--help":case"-h":P=!0;break;default:l=x}}return{path:l,format:h,help:P}}async function me(m){let l=de(m);if(l.help||!l.path)return process.stdout.write(re),l.help?0:2;let h;try{h=await t(l.path)}catch(x){return process.stderr.write(`Failed to load ${l.path}: ${x instanceof Error?x.message:String(x)}
|
|
139
|
+
`),2}let g=await n[l.format].render(h,{});return await I(g),0}var pe={ascii:"table"};function fe(m){let l,h,P,g,x=!1;for(let C=0;C<m.length;C++){let y=m[C];switch(y){case"--format":{let F=m[++C]??"";h=pe[F]??F;break}case"--run":P=m[++C];break;case"--out-dir":g=m[++C];break;case"--help":case"-h":x=!0;break;default:l=y}}return{path:l,format:h,runId:P,outDir:g,help:x}}async function he(m){let l=fe(m);if(l.help||!l.path||!l.format)return process.stdout.write(se),l.help?0:2;if(!(l.format in n))return process.stderr.write(`Unknown --format "${l.format}". Expected one of: ${Object.keys(n).join(", ")}, ascii
|
|
140
|
+
`),2;let h;try{h=await t(l.path)}catch(x){return process.stderr.write(`Failed to load ${l.path}: ${x instanceof Error?x.message:String(x)}
|
|
123
141
|
`),2}let g=await n[l.format].render(h,{runId:l.runId});if(!g.text&&(!g.files||g.files.length===0))return process.stderr.write(l.runId?`No CPU evidence found for run "${l.runId}".
|
|
124
142
|
`:`No CPU evidence found in this document (no cpu-phase runs). Capture some with "ostia run --cpu ...".
|
|
125
|
-
`),2;return await
|
|
143
|
+
`),2;return await I(g,l.outDir),0}function ge(m){let l=!1,h,P,g=!1,x=!1;for(let C=0;C<m.length;C++)switch(m[C]){case"--full":l=!0;break;case"--baseline":h=m[++C];break;case"--export-json":P=m[++C];break;case"--quiet":g=!0;break;case"--help":case"-h":x=!0;break}return{full:l,baseline:h,exportJson:P,quiet:g,help:x}}async function be(m){let l=ge(m);if(l.help)return process.stdout.write(ne),0;let h=await W();if(!h)return process.stderr.write(`No ostia.config.json found. "ostia ci" needs configured workloads.
|
|
126
144
|
`),2;if(h.workloads.length===0)return process.stderr.write(`ostia.config.json has no "workloads" configured.
|
|
127
|
-
`),2;let
|
|
145
|
+
`),2;let P;try{P=await z({config:h,full:l.full,baselineName:l.baseline})}catch(g){if(g instanceof T)return process.stderr.write(`${g.message}
|
|
128
146
|
`),2;return process.stderr.write(`CI run failed: ${g instanceof Error?g.message:String(g)}
|
|
129
|
-
`),2}if(l.exportJson)await o(
|
|
147
|
+
`),2}if(l.exportJson)await o(P.document,l.exportJson);if(!l.quiet)process.stdout.write(K(P.summary));return P.summary.regressed>0?1:0}async function we(){let[m,...l]=process.argv.slice(2);switch(m){case"run":return ae(l);case"bench":return ue(l);case"compare":return ce(l);case"report":return me(l);case"ci":return be(l);case"viz":return he(l);case void 0:case"--help":case"-h":return process.stdout.write(`ostia - Bun-native profile IR engine
|
|
130
148
|
|
|
131
149
|
Commands:
|
|
132
150
|
run Run commands N times and report timing/CPU/heap
|
|
@@ -137,5 +155,5 @@ Commands:
|
|
|
137
155
|
viz Render CPU evidence as collapsed/mermaid/speedscope/cpuprofile
|
|
138
156
|
|
|
139
157
|
Run "ostia <command> --help" for details.
|
|
140
|
-
`),
|
|
141
|
-
`),2}}if(import.meta.main)
|
|
158
|
+
`),m===void 0?2:0;default:return process.stderr.write(`Unknown subcommand "${m}". Run "ostia --help".
|
|
159
|
+
`),2}}if(import.meta.main)we().then((m)=>process.exit(m));
|
package/index.d.ts
CHANGED
|
@@ -38,20 +38,31 @@ export interface ProfileDocument {
|
|
|
38
38
|
comparisons?: Comparison[];
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
interface Workload {
|
|
41
|
+
export interface Workload {
|
|
42
42
|
id: string;
|
|
43
43
|
kind: "subprocess" | "inprocess";
|
|
44
44
|
label?: string;
|
|
45
45
|
command?: string[];
|
|
46
46
|
shell?: string;
|
|
47
|
+
/** `task` is the "group/name" id the bench registry assigns; `group` is the
|
|
48
|
+
* enclosing `group()` name when there is one. Renderers prefer `group` over
|
|
49
|
+
* splitting `task` on "/", so task names may contain slashes. */
|
|
47
50
|
entry?: {
|
|
48
51
|
file: string;
|
|
49
52
|
task: string;
|
|
53
|
+
group?: string;
|
|
50
54
|
};
|
|
51
55
|
/** Marks this task as the in-run Relative reference for its group (see
|
|
52
56
|
* `task(name, fn, { baseline: true })`). At most one per group is
|
|
53
57
|
* meaningful; renderers use the first they encounter. */
|
|
54
58
|
baseline?: boolean;
|
|
59
|
+
/** What this task measures and why, from `task(name, fn, { description })`.
|
|
60
|
+
* Travels with the data so a reader of the document has intent, not just
|
|
61
|
+
* numbers. */
|
|
62
|
+
description?: string;
|
|
63
|
+
/** The enclosing group's `group(name, fn, { description })`. Repeated on every
|
|
64
|
+
* workload in the group so each record is self-contained. */
|
|
65
|
+
groupDescription?: string;
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
type Phase = "timing" | "cpu" | "heap" | "memstats";
|
|
@@ -168,9 +179,9 @@ interface JitTierBreakdown {
|
|
|
168
179
|
}[];
|
|
169
180
|
}
|
|
170
181
|
|
|
171
|
-
type WarningCode = "slow-first-run" | "outliers-detected" | "fast-command" | "nonzero-exit" | "instrumented-timing" | "artifact-missing" | "empty-profile" | "below-timer-resolution" | "cache-fallback-rerun";
|
|
182
|
+
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";
|
|
172
183
|
|
|
173
|
-
interface Warning {
|
|
184
|
+
export interface Warning {
|
|
174
185
|
code: WarningCode;
|
|
175
186
|
message: string;
|
|
176
187
|
data?: Record<string, unknown>;
|
|
@@ -223,6 +234,12 @@ interface BenchOptions {
|
|
|
223
234
|
minSamples?: number;
|
|
224
235
|
gc?: boolean;
|
|
225
236
|
filter?: string;
|
|
237
|
+
/** Suite files to run at once, each still in its own child process (default:
|
|
238
|
+
* 1). Files are independent by design, so this is a wall-clock win for
|
|
239
|
+
* multi-file suites, but concurrent CPU-bound processes contend for cores,
|
|
240
|
+
* caches, memory bandwidth and turbo headroom: timings taken under `jobs > 1`
|
|
241
|
+
* are noisier and not like-for-like with a baseline measured at 1. */
|
|
242
|
+
jobs?: number;
|
|
226
243
|
outDir?: string;
|
|
227
244
|
cwd?: string;
|
|
228
245
|
}
|
|
@@ -238,9 +255,18 @@ export interface TaskOptions {
|
|
|
238
255
|
/** Per-task hard floor on trials; overrides the suite-wide `--min-samples` /
|
|
239
256
|
* `minSamples`. */
|
|
240
257
|
minSamples?: number;
|
|
258
|
+
/** What this task measures and why. Flows into `Workload.description` so the
|
|
259
|
+
* intent travels with the numbers instead of living only in a source comment. */
|
|
260
|
+
description?: string;
|
|
241
261
|
}
|
|
242
262
|
|
|
243
|
-
export
|
|
263
|
+
export interface GroupOptions {
|
|
264
|
+
/** What this group measures and why. Flows into `Workload.groupDescription`
|
|
265
|
+
* on every task in the group. */
|
|
266
|
+
description?: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export declare function group(name: string, fn: () => void, opts?: GroupOptions): void;
|
|
244
270
|
|
|
245
271
|
export declare function task(name: string, fn: () => unknown | Promise<unknown>, opts?: TaskOptions): void;
|
|
246
272
|
|
|
@@ -259,7 +285,7 @@ export declare function loadDocument(path: string): Promise<ProfileDocument>;
|
|
|
259
285
|
|
|
260
286
|
export declare const renderers: Record<FormatName, Renderer<any>>;
|
|
261
287
|
|
|
262
|
-
type FormatName = "table" | "json" | "markdown" | "jsonl" | "collapsed" | "mermaid" | "speedscope" | "cpuprofile";
|
|
288
|
+
type FormatName = "table" | "json" | "markdown" | "jsonl" | "minimal" | "collapsed" | "mermaid" | "speedscope" | "cpuprofile";
|
|
263
289
|
|
|
264
290
|
interface RenderResult {
|
|
265
291
|
text?: string;
|
|
@@ -273,3 +299,34 @@ interface Renderer<O = unknown> {
|
|
|
273
299
|
name: FormatName;
|
|
274
300
|
render(doc: ProfileDocument, options: O): Promise<RenderResult>;
|
|
275
301
|
}
|
|
302
|
+
|
|
303
|
+
export interface MinimalLine {
|
|
304
|
+
task: string;
|
|
305
|
+
group?: string;
|
|
306
|
+
description?: string;
|
|
307
|
+
groupDescription?: string;
|
|
308
|
+
unit: "ns";
|
|
309
|
+
samples: number;
|
|
310
|
+
mean: number;
|
|
311
|
+
median: number;
|
|
312
|
+
stddev: number;
|
|
313
|
+
stddevPct: number;
|
|
314
|
+
min: number;
|
|
315
|
+
max: number;
|
|
316
|
+
/** Median over the group's reference median (its baseline task, else its
|
|
317
|
+
* fastest). Only present when the document has more than one timing run. */
|
|
318
|
+
relative?: number;
|
|
319
|
+
baseline?: true;
|
|
320
|
+
warnings: {
|
|
321
|
+
code: string;
|
|
322
|
+
data?: Record<string, unknown>;
|
|
323
|
+
}[];
|
|
324
|
+
/** From `comparisons` when present (ostia compare / ci): the change against
|
|
325
|
+
* the baseline document for this task. */
|
|
326
|
+
delta?: {
|
|
327
|
+
medianPct: number;
|
|
328
|
+
meanPct: number;
|
|
329
|
+
verdict: "improved" | "regressed" | "unchanged";
|
|
330
|
+
pass: boolean;
|
|
331
|
+
};
|
|
332
|
+
}
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{p,d,n,w,I}from"./chunk-s1d2tx3w.js";import{o,t,F,v}from"./chunk-3rp84rbb.js";export{p as bench,d as compareDocuments,F as group,t as loadDocument,I as profile,n as renderers,w as run,o as saveDocument,v as task};
|
package/package.json
CHANGED
package/runner.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{r,
|
|
4
|
-
`),2;let
|
|
5
|
-
`),2;let
|
|
6
|
-
`),2;let
|
|
3
|
+
import{r,P,i,s,o,l,m,C,N,x,D}from"./chunk-3rp84rbb.js";var J=500,z=20,A=3,H=10,j=2,v=0.1,X=1000,q=1e4;function G(n){let e=Math.log10(Math.max(1,n)/1e6),a=Math.round(A+j*e);return Math.min(H,Math.max(A,a))}function K(n,e){let a=Math.floor(e/n);return Math.min(z,Math.max(a,G(n)))}var y=0;function S(n){if(typeof n==="number")y+=n;else if(n!==void 0&&n!==null)y+=1}function B(n){return n!==null&&typeof n==="object"&&typeof n.then==="function"}function L(n,e){return Math.max(1,Math.ceil(X/n),Math.ceil(e/(n*q)))}async function U(n,e={}){let a=(e.timeBudgetMs??J)*1e6,b=a*(e.warmupFraction??v),T=Bun.nanoseconds(),f=0,h=0;while(h<b){let c=n();S(B(c)?await c:c),f++,h=Bun.nanoseconds()-T}let p;if(f>0)p=Math.max(1,h/f);else{let c=Bun.nanoseconds(),g=n();S(B(g)?await g:g),p=Math.max(1,Bun.nanoseconds()-c)}let t=L(p,a);if(t>1){let c=Bun.nanoseconds();for(let g=0;g<t;g++){let w=n();S(B(w)?await w:w)}p=Math.max(1,(Bun.nanoseconds()-c)/t),t=L(p,a)}let d=p*t,k=e.minSamples??K(d,a),u=[],M=Bun.nanoseconds(),F=0,O=0;while(O<k||F<a){let c=Bun.nanoseconds();for(let w=0;w<t;w++){let _=n();S(B(_)?await _:_)}let g=Bun.nanoseconds();if(u.push({i:O,wallNs:(g-c)/t}),O++,F=Bun.nanoseconds()-M,e.gc)Bun.gc(!0)}let W=u.map((c)=>c.wallNs),I=l(W),E=m(I,[],"inprocess"),R=G(d);if(u.length<R)E.push({code:"low-sample-count",message:`Only ${u.length} sample(s) at ~${Q(d)} per trial; ${R} is the floor for this cost class. Raise minSamples or the time budget for a steadier number.`,data:{samples:u.length,target:R,trialCostNs:d}});return{trials:u,timing:I,warnings:E}}function Q(n){if(n>=1e9)return`${(n/1e9).toFixed(2)}s`;if(n>=1e6)return`${(n/1e6).toFixed(1)}ms`;if(n>=1000)return`${(n/1000).toFixed(1)}\xB5s`;return`${n.toFixed(0)}ns`}async function V(){let[n,e,a]=process.argv.slice(2);if(!n||!e)return process.stderr.write(`bench runner: usage: runner.ts <suiteFile> <outputPath> [optsJson]
|
|
4
|
+
`),2;let b=a?JSON.parse(a):{};N(),await import(n);let T=C();if(T.length===0)return process.stderr.write(`bench runner: ${n} registered no tasks (no task() calls found).
|
|
5
|
+
`),2;let f=D(T,b.filter);if(f.length===0)return process.stderr.write(`bench runner: --filter ${JSON.stringify(b.filter)} matched zero of ${T.length} registered tasks in ${n}.
|
|
6
|
+
`),2;let h=[],p=[];for(let t of f){let d=x(t),k=P(n,d,{label:d,baseline:t.baseline,group:t.groupName,description:t.opts?.description,groupDescription:t.groupDescription});h.push(k);let u={...b,...t.opts?.timeBudgetMs!==void 0&&{timeBudgetMs:t.opts.timeBudgetMs},...t.opts?.minSamples!==void 0&&{minSamples:t.opts.minSamples}},M=await U(t.fn,u);p.push(i({workload:k,configFingerprint:s({timeBudgetMs:u.timeBudgetMs??null,minSamples:u.minSamples??null,gc:u.gc??!1}),trials:M.trials,timing:M.timing,warnings:M.warnings}))}return await o(r(h,p),e),0}V().then((n)=>process.exit(n));
|
package/chunk-m8zhsw7r.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{g,e,r,u,k,i,h,P,s,y,t,l,p}from"./chunk-qh19pbhc.js";function Be(o){return o.startsWith("file://")?o.slice(7):o}function re(o,v,c){let T=o.nodes,x=T.length,C=new Map,N=[],R=new Map,U=new Int32Array(x);for(let D=0;D<x;D++){let M=T[D],F=M.callFrame,L=Be(F.url),J=C.get(F.functionName);if(J===void 0)J=new Map,C.set(F.functionName,J);let K=J.get(L);if(K===void 0)K=N.length,J.set(L,K),N.push({key:e("fr",F.functionName,L),name:F.functionName,url:L||void 0,line:F.lineNumber>=0?F.lineNumber:void 0,col:F.columnNumber>=0?F.columnNumber:void 0});U[D]=K,R.set(M.id,D)}let B=Array(x);for(let D=0;D<x;D++){let M=T[D];B[D]={id:M.id,frameIx:U[R.get(M.id)],children:M.children??[]}}let S=new Float64Array(x),A=new Float64Array(x),{samples:O,timeDeltas:W}=o;for(let D=0;D<O.length;D++){let M=R.get(O[D]);if(M===void 0)continue;S[M]+=W[D]??0,A[M]+=1}let j=new Int32Array(x).fill(-1);for(let D=0;D<x;D++){let M=T[D].children;if(!M)continue;for(let F of M){let L=R.get(F);if(L!==void 0)j[L]=D}}let E=[],H=[];for(let D=x-1;D>=0;D--)if(j[D]===-1)H.push(D);while(H.length>0){let D=H.pop();E.push(D);let M=T[D].children;if(!M)continue;for(let F of M){let L=R.get(F);if(L!==void 0&&j[L]===D)H.push(L)}}let z=new Float64Array(x);for(let D=E.length-1;D>=0;D--){let M=E[D];z[M]+=S[M];let F=j[M];if(F>=0)z[F]+=z[M]}let V=Array(N.length),_=[];for(let D=0;D<x;D++){let M=B[D].frameIx,F=V[M];if(F)F.selfUs+=S[D],F.totalUs+=z[D],F.samples+=A[D];else{let L={frameIx:M,selfUs:S[D],totalUs:z[D],samples:A[D]};V[M]=L,_.push(L)}}return{origin:v,samplingIntervalUs:c,frames:N,nodes:B,totals:_.sort((D,M)=>M.selfUs-D.selfUs),samples:{nodeIds:o.samples,timeDeltasUs:o.timeDeltas}}}function Oe(o,v,c,T){let x=["--cpu-prof","--cpu-prof-dir",v,"--cpu-prof-name",c,"--cpu-prof-interval",String(T)],C=o[0];if(C==="bun"||C?.endsWith("/bun"))return[C,...x,...o.slice(1)];return o}async function pe(o){let v=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],T=c==="bun"||c?.endsWith("/bun"),x=Oe(o.argv,o.artifactDir,o.fileName,o.intervalUs),C=T?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(),U=await Bun.spawn(x,{cwd:o.cwd,env:C,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,B=Bun.nanoseconds()-N,S=Bun.file(v);if(!await S.exists())return{diagnosticWallNs:B,exitCode:U,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${v} after exit ${U}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:v,argv:o.argv}}]};let A=await S.json(),O=re(A,"cpu-prof",o.intervalUs),W=A.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:B,exitCode:U,artifactPath:v,cpu:O,warnings:W}}function le(o,v="heap-prof"){let{node_fields:c,node_types:T}=o.snapshot.meta,x=c.indexOf("type"),C=c.indexOf("self_size"),N=c.length,R=T[0];if(x===-1||C===-1||!Array.isArray(R))return{origin:v,typeCounts:[],objectCount:o.snapshot.node_count};let U=R.length,B=Array(U),S=new Map,A=[],O=0,W=o.nodes,j=W.length;for(let _=0;_<j;_+=N){let D=W[_+x],M=W[_+C]??0;O+=M;let F;if(D>=0&&D<U){if(F=B[D],F===void 0)F={type:R[D],count:0,bytes:0},B[D]=F,A.push(F)}else{let L=`unknown(${D})`;if(F=S.get(L),F===void 0)F={type:L,count:0,bytes:0},S.set(L,F),A.push(F)}F.count++,F.bytes+=M}let E=A.sort((_,D)=>D.count-_.count),H=E.slice(0,20),z=E.slice(20),V=H.map(({type:_,count:D,bytes:M})=>({type:_,count:D,retainedBytes:M}));if(z.length>0){let _=0,D=0;for(let M of z)_+=M.count,D+=M.bytes;V.push({type:"other",count:_,retainedBytes:D})}return{origin:v,heapSizeBytes:O,objectCount:o.snapshot.node_count,typeCounts:V}}function We(o,v,c){let T=["--heap-prof","--heap-prof-dir",v,"--heap-prof-name",c],x=o[0];if(x==="bun"||x?.endsWith("/bun"))return[x,...T,...o.slice(1)];return o}async function me(o){let v=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],T=c==="bun"||c?.endsWith("/bun"),x=We(o.argv,o.artifactDir,o.fileName),C=T?o.env:{...process.env,...o.env,BUN_OPTIONS:`--heap-prof --heap-prof-dir ${o.artifactDir} --heap-prof-name ${o.fileName}`},N=Bun.nanoseconds(),U=await Bun.spawn(x,{cwd:o.cwd,env:C,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,B=Bun.nanoseconds()-N,S=Bun.file(v);if(!await S.exists())return{diagnosticWallNs:B,exitCode:U,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${v} after exit ${U}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:v,argv:o.argv}}]};let A=await S.json(),O=le(A,"heap-prof");return{diagnosticWallNs:B,exitCode:U,artifactPath:v,heap:O,warnings:[]}}import{Session as Ee}from"inspector/promises";var Ae=1000;async function fe(o,v={}){let c=v.intervalUs??Ae,T=new Ee;T.connect();let x=Bun.nanoseconds();try{await T.post("Profiler.enable"),await T.post("Profiler.setSamplingInterval",{interval:c}),await T.post("Profiler.start");let C=await o(),{profile:N}=await T.post("Profiler.stop"),R=Bun.nanoseconds()-x,U=re(N,"inspector",c);return{result:C,cpu:U,diagnosticWallNs:R}}finally{T.disconnect()}}import{profile as je}from"bun:jsc";var _e=new Map([["LLInt","llint"],["Baseline","baseline"],["DFG","dfg"],["FTL","ftl"]]),de=4294967295;function ge(o,v){let c=v??o.interval*1e6,T=new Map,x=[];function C(F,L,J,K){let Y=T.get(F);if(Y===void 0)Y=new Map,T.set(F,Y);let G=L??"",q=Y.get(G);if(q===void 0)q=x.length,Y.set(G,q),x.push({key:e("fr",F,G),name:F,url:L,line:J,col:K});return q}function N(F){let L=F.line===de,J=L?void 0:F.line-1,K=L||F.column===de?void 0:F.column-1;return C(F.name,F.sourceURL,J,K)}let R=C("(root)",void 0,void 0,void 0),U=1,B={id:0,frameIx:R,children:new Map,selfUs:0,samples:0,totalUs:0},S=new Map([[0,B]]),A={llint:0,baseline:0,dfg:0,ftl:0},O=new Map,W=[],j=[];for(let F of o.traces){let L=F.frames,J=B;for(let G=L.length-1;G>=0;G--){let q=N(L[G]),Z=J.children.get(q);if(!Z)Z={id:U++,frameIx:q,children:new Map,selfUs:0,samples:0,totalUs:0},J.children.set(q,Z),S.set(Z.id,Z);J=Z}J.selfUs+=c,J.samples+=1,W.push(J.id),j.push(c);let K=L[0],Y=K&&_e.get(K.category);if(Y){A[Y]++;let G=O.get(Y)??new Map;G.set(J.frameIx,(G.get(J.frameIx)??0)+1),O.set(Y,G)}}function E(F){let L=F.selfUs;for(let J of F.children.values())L+=E(J);return F.totalUs=L,L}E(B);let H=new Map;function z(F){let L=H.get(F.frameIx);if(L)L.selfUs+=F.selfUs,L.totalUs+=F.totalUs,L.samples+=F.samples;else H.set(F.frameIx,{frameIx:F.frameIx,selfUs:F.selfUs,totalUs:F.totalUs,samples:F.samples});for(let J of F.children.values())z(J)}z(B);let V=[...S.values()].map((F)=>({id:F.id,frameIx:F.frameIx,children:[...F.children.values()].map((L)=>L.id)})),_={origin:"jsc-profile",samplingIntervalUs:c,frames:x,nodes:V,totals:[...H.values()].sort((F,L)=>L.selfUs-F.selfUs),samples:{nodeIds:W,timeDeltasUs:j}},D=[...O.entries()].flatMap(([F,L])=>[...L.entries()].sort((J,K)=>K[1]-J[1]).slice(0,3).map(([J,K])=>({tier:F,frameKey:x[J].key,samples:K})));return{cpu:_,jit:{origin:"jsc-profile",tiers:A,topFramesByTier:D}}}var Le=1000;async function he(o,v={}){let c=v.intervalUs??Le,T,x=Bun.nanoseconds(),C=await je(async()=>(T=await o(),T),c),N=Bun.nanoseconds()-x,{cpu:R,jit:U}=ge(C.stackTraces,c);return{result:T,cpu:R,jit:U,diagnosticWallNs:N}}async function ie(o){let v=Bun.nanoseconds(),c=Bun.spawn(o.argv,{cwd:o.cwd,env:o.env,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),T=await c.exited,x=Bun.nanoseconds(),C=c.resourceUsage?.();return{wallNs:x-v,exitCode:T,userNs:C?Number(C.cpuTime.user)*1000:void 0,systemNs:C?Number(C.cpuTime.system)*1000:void 0,maxRssBytes:C?.maxRSS}}function be(o){return o.trim().split(/\s+/).filter(Boolean)}var He=10,ze=3000000000,Je=3;async function f(o){let v=o.warmup??Je;for(let S=0;S<v;S++)await ie(o);let c=[],T=o.runs??o.minRuns??He,x=o.runs!==void 0?0:o.minTotalNs??ze,C=0,N=0;while(N<T||C<x){let S=await ie(o);if(c.push({i:N,wallNs:S.wallNs,exitCode:S.exitCode,userNs:S.userNs,systemNs:S.systemNs,maxRssBytes:S.maxRssBytes}),C+=S.wallNs,N++,o.runs!==void 0&&N>=o.runs)break}let R=c.map((S)=>S.wallNs),U=l(R),B=p(U,c.map((S)=>S.exitCode));return{trials:c,timing:U,warnings:B}}var Ve=new URL("./runner.ts",import.meta.url).pathname,Ke="node_modules/.cache/ostia";async function m(o){let c=`${o.outDir??Ke}/bench-tmp`,T=o.cwd??process.cwd(),x={timeBudgetMs:o.timeBudgetMs,minSamples:o.minSamples,gc:o.gc,filter:o.filter},C=[],N=[];try{for(let R of o.suites){let U=R.startsWith("/")?R:`${T}/${R}`,B=`${c}/${e("bench-out",U)}.json`,A=await Bun.spawn(["bun",Ve,U,B,JSON.stringify(x)],{cwd:T,stdout:"inherit",stderr:"inherit",stdin:"ignore"}).exited;if(A!==0)throw Error(`Bench suite failed: ${R} (runner exited ${A})`);let O=await t(B);C.push(...O.workloads),N.push(...O.runs)}}finally{await Bun.spawn(["rm","-rf",c]).exited}return r(C,N)}var a={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000};function se(o,v){if(o===0)return v===0?0:1/0;return(v-o)/o*100}function ee(o,v,c){return o.runs.find((T)=>T.workloadId===v&&T.phase===c)}function d(o,v,c=a){let T=new Set(v.workloads.map((C)=>C.id)),x=[];for(let C of o.workloads){if(!T.has(C.id))continue;let N=b(o,v,C.id,c);if(N)x.push(N)}return x}function b(o,v,c,T=a){let x=ee(o,c,"timing"),C=ee(v,c,"timing"),N=ee(o,c,"cpu"),R=ee(v,c,"cpu"),U=ee(o,c,"heap"),B=ee(v,c,"heap"),S=x?.id??N?.id??U?.id,A=C?.id??R?.id??B?.id;if(!S||!A)return;let O=!1,W;if(x?.timing&&C?.timing){let H=se(x.timing.median,C.timing.median),z=se(x.timing.mean,C.timing.mean),V=H>T.timingPct?"regressed":H<-T.timingPct?"improved":"unchanged";if(V==="regressed")O=!0;W={medianDeltaPct:H,meanDeltaPct:z,verdict:V}}let j;if(N?.cpu&&R?.cpu){let H=new Map(N.cpu.totals.map((M)=>[N.cpu.frames[M.frameIx].key,M])),z=new Map(R.cpu.totals.map((M)=>[R.cpu.frames[M.frameIx].key,M])),V=new Map(N.cpu.frames.map((M)=>[M.key,M.name])),_=new Map(R.cpu.frames.map((M)=>[M.key,M.name]));j=[...new Set([...H.keys(),...z.keys()])].map((M)=>{let F=H.get(M)?.selfUs??0,L=z.get(M)?.selfUs??0;return{frameKey:M,name:_.get(M)??V.get(M)??M,baseSelfUs:F,candSelfUs:L,deltaPct:se(F,L)}}).sort((M,F)=>Math.abs(F.deltaPct)-Math.abs(M.deltaPct));for(let M of j)if((M.baseSelfUs>=T.minFrameSelfUs||M.candSelfUs>=T.minFrameSelfUs)&&M.deltaPct>T.frameSelfPct)O=!0}let E;if(U?.heap&&B?.heap){let H=new Map(U.heap.typeCounts.map((_)=>[_.type,_])),z=new Map(B.heap.typeCounts.map((_)=>[_.type,_]));E=[...new Set([...H.keys(),...z.keys()])].map((_)=>{let D=H.get(_),M=z.get(_);return{type:_,baseCount:D?.count??0,candCount:M?.count??0,baseBytes:D?.retainedBytes,candBytes:M?.retainedBytes,deltaPct:se(D?.count??0,M?.count??0)}}).sort((_,D)=>Math.abs(D.deltaPct)-Math.abs(_.deltaPct));for(let _ of E)if(_.deltaPct>T.heapTypePct)O=!0}return{id:e("cmp",S,A),baselineRunId:S,candidateRunId:A,timing:W,frames:j,heapTypes:E,thresholds:T,verdict:O?"fail":"pass"}}function Q(o,v){if(v){let c=o.runs.find((T)=>T.id===v);return c?.cpu?[c]:[]}return o.runs.filter((c)=>c.phase==="cpu"&&c.cpu)}function ne(o){let v=o.nodes,c=v.length,T=Ge(o),x=new Int32Array(c).fill(-1);for(let U=0;U<c;U++)for(let B of v[U].children){let S=T(B);if(S!==-1)x[S]=U}let C=[];for(let U=0;U<c;U++)if(x[U]===-1)C.push(U);let N=[],R=[];for(let U=C.length-1;U>=0;U--)R.push(C[U]);while(R.length>0){let U=R.pop();N.push(U);for(let B of v[U].children){let S=T(B);if(S!==-1&&x[S]===U)R.push(S)}}return{count:c,indexOf:T,parentIx:x,roots:C,order:N}}function Ge(o){let v=o.nodes,c=v.length,T=1/0,x=-1/0,C=!0;for(let R=0;R<c;R++){let U=v[R].id;if(!Number.isInteger(U)){C=!1;break}if(U<T)T=U;if(U>x)x=U}if(C&&c>0&&x-T<c*4+64){let R=x-T+1,U=new Int32Array(R).fill(-1);for(let B=0;B<c;B++)U[v[B].id-T]=B;return(B)=>{let S=B-T;return S>=0&&S<R?U[S]:-1}}let N=new Map;for(let R=0;R<c;R++)N.set(v[R].id,R);return(R)=>N.get(R)??-1}function ye(o,v){let{count:c,indexOf:T,parentIx:x,order:C}=v,N=new Float64Array(c),R=new Float64Array(c),U=o.samples?.nodeIds??[],B=o.samples?.timeDeltasUs??[];for(let A=0;A<U.length;A++){let O=T(U[A]);if(O===-1)continue;N[O]+=B[A]??0,R[O]+=1}let S=new Float64Array(c);for(let A=C.length-1;A>=0;A--){let O=C[A];S[O]+=N[O];let W=x[O];if(W>=0)S[W]+=S[O]}return{selfUs:N,totalUs:S,samples:R}}var we={name:"collapsed",async render(o,v={}){return{files:Q(o,v.runId).map((x)=>{let C=x.cpu,{nodes:N,frames:R}=C,U=ne(C),B=Array(U.count);for(let j of U.order){let E=R[N[j].frameIx].name||"(anonymous)",H=U.parentIx[j];B[j]=H===-1?E:`${B[H]};${E}`}let S=new Float64Array(U.count),A=[],O=C.samples?.nodeIds??[];for(let j=0;j<O.length;j++){let E=U.indexOf(O[j]);if(E===-1)continue;if(S[E]++===0)A.push(E)}let W=Array(A.length);for(let j=0;j<A.length;j++){let E=A[j];W[j]=`${B[E]} ${S[E]}`}return{path:`${x.id}.collapsed.txt`,content:W.join(`
|
|
3
|
-
`)+(W.length>0?`
|
|
4
|
-
`:"")}})}}};var xe={name:"cpuprofile",async render(o,v={}){let c=Q(o,v.runId),T=[],x=[];for(let C of c){if(C.cpu?.origin!=="cpu-prof"&&C.cpu?.origin!=="inspector"){x.push(`${C.id} (origin ${C.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let N=C.artifacts.find((U)=>U.kind==="cpuprofile");if(!N){x.push(`${C.id} (no cpuprofile artifact recorded on this run)`);continue}let R=Bun.file(N.path);if(!await R.exists()){x.push(`${C.id} (artifact missing on disk: ${N.path})`);continue}T.push({path:`${C.id}.cpuprofile`,content:await R.text()})}if(T.length===0&&x.length>0)return{text:`No .cpuprofile artifacts available:
|
|
5
|
-
${x.map((C)=>` - ${C}`).join(`
|
|
6
|
-
`)}
|
|
7
|
-
`};return{files:T}}};var Re={name:"json",async render(o){return{text:y(o)}}};var Pe={name:"jsonl",async render(o){let{runs:v,...c}=o;return{text:`${[g(c),...v.map((x)=>g(x))].join(`
|
|
8
|
-
`)}
|
|
9
|
-
`}}};function X(o){return(o/1e6).toFixed(3)}function oe(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??o?.id??"unknown"}var Te=10,$e=10,Ce={name:"markdown",async render(o){let v=new Map(o.workloads.map((x)=>[x.id,x])),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 T=o.runs.filter((x)=>x.phase==="timing"&&x.timing!==void 0);if(T.length>0){c.push("## Timing",""),c.push("| Command | Mean \xB1 SD (ms) | Min\u2026Max (ms) | Median (ms) |","|---|---|---|---|");for(let C of T){let N=oe(v.get(C.workloadId)),R=C.timing;c.push(`| ${N} | ${X(R.mean)} \xB1 ${X(R.stddev)} | ${X(R.min)}\u2026${X(R.max)} | ${X(R.median)} |`)}c.push("");let x=T.filter((C)=>C.warnings.length>0);if(x.length>0){c.push("### Warnings","");for(let C of x){let N=oe(v.get(C.workloadId));for(let R of C.warnings)c.push(`- **${N}**: ${R.message} (\`${R.code}\`)`)}c.push("")}}for(let x of o.runs){if(x.phase!=="cpu"&&x.phase!=="heap")continue;let C=oe(v.get(x.workloadId));if(x.phase==="cpu"){if(c.push(`## CPU capture - ${C}`,""),c.push(`instrumented, diagnostic wall ${X(x.diagnosticWallNs??0)}ms`,""),x.cpu){c.push(`origin: \`${x.cpu.origin}\`, interval: ${x.cpu.samplingIntervalUs}\xB5s`,""),c.push("| Self % | Self (ms) | Total (ms) | Frame |","|---|---|---|---|");let N=x.cpu.totals.reduce((R,U)=>R+U.selfUs,0)||1;for(let R of x.cpu.totals.slice(0,Te)){let U=x.cpu.frames[R.frameIx],B=(R.selfUs/N*100).toFixed(1);c.push(`| ${B}% | ${(R.selfUs/1000).toFixed(2)} | ${(R.totalUs/1000).toFixed(2)} | ${U?.name||"(anonymous)"} |`)}if(c.push(""),x.jit){let R=x.jit.tiers;c.push(`JIT tiers: LLInt ${R.llint} \xB7 Baseline ${R.baseline} \xB7 DFG ${R.dfg} \xB7 FTL ${R.ftl}`,"")}}}else if(c.push(`## Heap snapshot - ${C}`,""),c.push(`instrumented, diagnostic wall ${X(x.diagnosticWallNs??0)}ms`,""),x.heap){c.push(`${x.heap.objectCount??"?"} objects, ${((x.heap.heapSizeBytes??0)/1e6).toFixed(2)}MB`,""),c.push("| Count | Type |","|---|---|");for(let N of x.heap.typeCounts.slice(0,$e))c.push(`| ${N.count} | ${N.type} |`);c.push("")}for(let N of x.artifacts)c.push(`- artifact: \`${N.path}\``);for(let N of x.warnings)c.push(`- ! ${N.message} (\`${N.code}\`)`);if(x.artifacts.length>0||x.warnings.length>0)c.push("")}if(o.comparisons&&o.comparisons.length>0){c.push("## Comparisons","");for(let x of o.comparisons){let C=o.runs.find((R)=>R.id===x.candidateRunId),N=oe(C?v.get(C.workloadId):void 0);if(c.push(`### ${x.verdict==="pass"?"\u2713":"\u2717"} ${N}`,""),x.timing){let R=x.timing.medianDeltaPct>0?"+":"";c.push(`- timing: ${R}${x.timing.medianDeltaPct.toFixed(1)}% median (**${x.timing.verdict}**)`)}for(let R of x.frames?.slice(0,Te)??[]){if(Math.abs(R.deltaPct)<0.5)continue;let U=R.deltaPct>0?"+":"";c.push(`- frame \`${R.name}\`: ${U}${R.deltaPct.toFixed(1)}% self-time (${(R.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(R.candSelfUs/1000).toFixed(2)}ms)`)}for(let R of x.heapTypes?.slice(0,$e)??[]){if(Math.abs(R.deltaPct)<0.5)continue;let U=R.deltaPct>0?"+":"";c.push(`- heap \`${R.type}\`: ${U}${R.deltaPct.toFixed(1)}% count (${R.baseCount} \u2192 ${R.candCount})`)}c.push("")}}return{text:c.join(`
|
|
10
|
-
`)}}};var Ye=15;function ae(o){return`n${o}`}function qe(o,v,c){return`${(o||"(anonymous)").replace(/"/g,"'")} (self ${(v/1000).toFixed(2)}ms, total ${(c/1000).toFixed(2)}ms)`}function Qe(o,v,c,T){let x=[];if(T<=0)return x;for(let C=0;C<v;C++){if(C===c)continue;let N=o[C];if(x.length===T&&N<=o[x[T-1]])continue;let R=x.length;while(R>0&&o[x[R-1]]<N)R--;if(x.splice(R,0,C),x.length>T)x.pop()}return x}var Ie={name:"mermaid",async render(o,v={}){let c=v.topN??Ye;return{files:Q(o,v.runId).map((C)=>{let N=C.cpu,{nodes:R,frames:U}=N,B=ne(N),{selfUs:S,totalUs:A}=ye(N,B),{parentIx:O}=B,W=B.roots[0]??-1,j=Qe(S,B.count,W,c),E=new Set(W!==-1?[W]:[]),H=[];for(let V of j){H.length=0;for(let _=V;_!==-1;_=O[_])H.push(_);for(let _=H.length-1;_>=0;_--)E.add(H[_])}let z=["graph TD"];for(let V of E){let _=R[V].id;z.push(` ${ae(_)}["${qe(U[R[V].frameIx].name,S[V],A[V])}"]`)}for(let V of E){let _=O[V];if(_!==-1&&E.has(_))z.push(` ${ae(R[_].id)} --> ${ae(R[V].id)}`)}return{path:`${C.id}.mermaid.md`,content:`${z.join(`
|
|
11
|
-
`)}
|
|
12
|
-
`}})}}};var Xe="https://www.speedscope.app/file-format-schema.json";function Ne(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??"profile"}var ke={name:"speedscope",async render(o,v={}){let c=Q(o,v.runId),T=new Map(o.workloads.map((C)=>[C.id,C]));return{files:c.map((C)=>{let N=C.cpu,{nodes:R}=N,U=ne(N),B=N.samples?.nodeIds??[],S=N.samples?.timeDeltasUs??[],A=Array(U.count);for(let E of U.order){let H=U.parentIx[E],z=R[E].frameIx;A[E]=H===-1?[z]:[...A[H],z]}let O=Array(B.length);for(let E=0;E<B.length;E++){let H=U.indexOf(B[E]);O[E]=H===-1?[]:A[H]}let W=0;for(let E=0;E<S.length;E++)W+=S[E];let j={$schema:Xe,exporter:"ostia",name:Ne(T.get(C.workloadId)),activeProfileIndex:0,shared:{frames:N.frames.map((E)=>({name:E.name||"(anonymous)",file:E.url,line:E.line!==void 0?E.line+1:void 0}))},profiles:[{type:"sampled",name:Ne(T.get(C.workloadId)),unit:"microseconds",startValue:0,endValue:W,samples:O,weights:S}]};return{path:`${C.id}.speedscope.json`,content:`${JSON.stringify(j,null,2)}
|
|
13
|
-
`}})}}};function te(o){return(o/1e6).toFixed(3)}function ce(o){return o.label??o.command?.join(" ")??o.entry?.task??o.id}function Ue(o){let v=o?.entry?.task;if(!v)return;let c=v.lastIndexOf("/");return c===-1?void 0:v.slice(0,c)}var Fe={name:"table",async render(o){let v=o.runs.filter((W)=>W.phase==="timing"&&W.timing!==void 0),c=new Map(o.workloads.map((W)=>[W.id,W]));if(v.length===0){let W=ve(o,c);return{text:W.length>0?`${W.join(`
|
|
14
|
-
`)}
|
|
15
|
-
`:`(no timing runs)
|
|
16
|
-
`}}let T=v.map((W)=>{let j=c.get(W.workloadId);return{run:W,workload:j,label:j?ce(j):W.workloadId}}),x=Math.min(...T.map((W)=>W.run.timing.median)),C=T.length>1,N=new Map;for(let W of T){let j=Ue(W.workload);if(j===void 0)continue;let E=N.get(j);if(E)E.push(W);else N.set(j,[W])}let R=(W)=>{let j=N.get(Ue(W.workload)??"");if(!j||j.length<=1)return x;let E=j.find((H)=>H.workload?.baseline);return E?E.run.timing.median:Math.min(...j.map((H)=>H.run.timing.median))},U=[],B=Math.max(7,...T.map((W)=>W.label.length)),S=C?`${"Command".padEnd(B)} Mean [ms] Min\u2026Max [ms] Relative`:`${"Command".padEnd(B)} Mean [ms] Min\u2026Max [ms]`;U.push(S),U.push("-".repeat(S.length));for(let W of T){let{run:j,label:E,workload:H}=W,z=j.timing,V=`${te(z.mean)} \xB1 ${te(z.stddev)}`,_=`${te(z.min)}\u2026${te(z.max)}`,D=`${E.padEnd(B)} ${V.padEnd(15)} ${_.padEnd(18)}`;if(C){let M=z.median/R(W);if(M===1)D+=H?.baseline?" 1.00\xD7 (baseline)":" 1.00\xD7";else if(M>1)D+=` ${M.toFixed(2)}\xD7 slower`;else D+=` ${(1/M).toFixed(2)}\xD7 faster`}U.push(D);for(let M of j.warnings)U.push(` ! ${M.message}`)}let A=en(o,c);if(A.length>0)U.push(""),U.push(...A);let O=ve(o,c);if(O.length>0)U.push(""),U.push(...O);return{text:`${U.join(`
|
|
17
|
-
`)}
|
|
18
|
-
`}}};function Ze(o,v,c){let T=o.runs.find((C)=>C.id===c),x=T?v.get(T.workloadId):void 0;return x?ce(x):c}function ve(o,v){if(!o.comparisons||o.comparisons.length===0)return[];let c=[];for(let T of o.comparisons){let x=Ze(o,v,T.candidateRunId),C=T.verdict==="pass"?"\u2713":"\u2717";if(c.push(`${C} ${x}`),T.timing){let N=T.timing.medianDeltaPct>0?"+":"";c.push(` timing: ${N}${T.timing.medianDeltaPct.toFixed(1)}% median (${T.timing.verdict})`)}if(T.frames)for(let N of T.frames.slice(0,De)){if(Math.abs(N.deltaPct)<0.5)continue;let R=N.deltaPct>0?"+":"";c.push(` frame ${N.name}: ${R}${N.deltaPct.toFixed(1)}% self-time (${(N.baseSelfUs/1000).toFixed(2)}ms -> ${(N.candSelfUs/1000).toFixed(2)}ms)`)}if(T.heapTypes)for(let N of T.heapTypes.slice(0,Me)){if(Math.abs(N.deltaPct)<0.5)continue;let R=N.deltaPct>0?"+":"";c.push(` heap ${N.type}: ${R}${N.deltaPct.toFixed(1)}% count (${N.baseCount} -> ${N.candCount})`)}}return c}var De=5,Me=5;function en(o,v){let c=[];for(let T of o.runs){if(T.phase!=="cpu"&&T.phase!=="heap")continue;let x=v.get(T.workloadId),C=x?ce(x):T.workloadId;if(T.phase==="cpu")if(T.cpu){c.push(`CPU capture - ${C} (instrumented, ${T.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${te(T.diagnosticWallNs??0)}ms)`);let N=T.cpu.totals.reduce((R,U)=>R+U.selfUs,0)||1;for(let R of T.cpu.totals.slice(0,De)){let U=T.cpu.frames[R.frameIx],B=(R.selfUs/N*100).toFixed(1);c.push(` ${B.padStart(5)}% ${(R.selfUs/1000).toFixed(2).padStart(8)}ms self ${U?.name??"?"}`)}}else c.push(`CPU capture - ${C} (instrumented, no evidence captured)`);else if(T.heap){let N=((T.heap.heapSizeBytes??0)/1e6).toFixed(2);c.push(`Heap snapshot - ${C} (instrumented, ${T.heap.objectCount??"?"} objects, ${N}MB)`);for(let R of T.heap.typeCounts.slice(0,Me))c.push(` ${String(R.count).padStart(6)} ${R.type}`)}else c.push(`Heap snapshot - ${C} (instrumented, no evidence captured)`);for(let N of T.artifacts)c.push(` artifact: ${N.path}`);for(let N of T.warnings)c.push(` ! ${N.message}`)}return c}var n={table:Fe,json:Re,markdown:Ce,jsonl:Pe,collapsed:we,mermaid:Ie,speedscope:ke,cpuprofile:xe};var nn="node_modules/.cache/ostia",ue=1000;async function w(o){let v=s({runs:o.runs??null,warmup:o.warmup??null,cpu:o.cpu??!1,heap:o.heap??!1,cpuIntervalUs:o.cpuIntervalUs??ue}),T=`${o.outDir??nn}/artifacts`,x=[],C=[];for(let N of o.commands){let R=Array.isArray(N)?N:be(N),U=u(R,Array.isArray(N)?void 0:N);x.push(U);let B=await f({argv:R,cwd:o.cwd,env:o.env,runs:o.runs,warmup:o.warmup}),S=i({workload:U,configFingerprint:v,trials:B.trials,timing:B.timing,warnings:B.warnings});if(C.push(S),o.cpu){let A=`${S.id}-cpu.cpuprofile`,O=await pe({argv:R,cwd:o.cwd,env:o.env,artifactDir:T,fileName:A,intervalUs:o.cpuIntervalUs??ue});C.push(await Se({workload:U,phase:"cpu",configFingerprint:v,diagnosticWallNs:O.diagnosticWallNs,exitCode:O.exitCode,cpu:O.cpu,artifactPath:O.artifactPath,artifactKind:"cpuprofile",warnings:O.warnings}))}if(o.heap){let A=`${S.id}-heap.heapsnapshot`,O=await me({argv:R,cwd:o.cwd,env:o.env,artifactDir:T,fileName:A});C.push(await Se({workload:U,phase:"heap",configFingerprint:v,diagnosticWallNs:O.diagnosticWallNs,exitCode:O.exitCode,heap:O.heap,artifactPath:O.artifactPath,artifactKind:"heapsnapshot",warnings:O.warnings}))}}return r(x,C)}async function Se(o){let v=`${o.workload.id}-${o.phase}-${o.configFingerprint}`,c=o.artifactPath?[await P(v,o.artifactKind,o.artifactPath)]:[];return h({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 I(o,v={}){let c=k(o),T=s({intervalUs:v.intervalUs??ue,origin:v.origin??"inspector"}),x=(B)=>B.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(v.origin==="jsc"){let{result:B,cpu:S,jit:A,diagnosticWallNs:O}=await he(o,v),W=h({workload:c,phase:"cpu",configFingerprint:T,diagnosticWallNs:O,cpu:S,jit:A,warnings:x(S),artifacts:[]});return{result:B,run:W}}let{result:C,cpu:N,diagnosticWallNs:R}=await fe(o,v),U=h({workload:c,phase:"cpu",configFingerprint:T,diagnosticWallNs:R,cpu:N,warnings:x(N),artifacts:[]});return{result:C,run:U}}
|
|
19
|
-
export{m,a,d,b,f,n,w,I};
|
package/chunk-qh19pbhc.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
function g(n){return JSON.stringify(W(n))}function W(n){if(Array.isArray(n))return n.map(W);if(n!==null&&typeof n==="object"){let a={};for(let d of Object.keys(n).sort())a[d]=W(n[d]);return a}return n}function e(n,...a){let d=Bun.CryptoHasher.hash("sha256",g(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 k(n,a){return{id:e("wl","inprocess",n.name,n.toString()),kind:"inprocess",label:a}}function R(n,a,d,m){return{id:e("wl","inprocess-entry",n,a),kind:"inprocess",entry:{file:n,task:a},label:d,baseline:m}}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:G(n.trials)}}function G(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 h(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 P(n,a,d){let f=await Bun.file(d).arrayBuffer(),w=new Bun.CryptoHasher("sha256");return w.update(f),{id:e("art",n,a,d),kind:a,path:d,sha256:w.digest("hex"),bytes:f.byteLength}}function s(n){return e("cfg",n)}function y(n){return`${JSON.stringify(W(n),null,2)}
|
|
3
|
-
`}async function o(n,a){await Bun.write(a,y(n))}async function t(n){let a=await Bun.file(n).text();return JSON.parse(a)}var _=[],B;function F(n,a){let d=B;B=n;try{a()}finally{B=d}}function D(n,a,d){_.push({groupName:B,name:n,fn:a,baseline:d?.baseline,opts:d})}function T(){return _}function C(){_.length=0,B=void 0}function x(n){return n.groupName?`${n.groupName}/${n.name}`:n.name}function N(n,a){if(!a)return[...n];let d=new RegExp(a);return n.filter((m)=>d.test(x(m)))}function l(n){if(n.length===0)throw Error("computeTimingStats: samples must be non-empty");let a=n.length,d=L(n),m=0;for(let v=0;v<a;v++)m+=n[v];let f=m/a,w=I(d,0.5),b=0;for(let v=0;v<a;v++){let S=n[v]-f;b+=S*S}let A=Math.sqrt(b/a),H=d[0],O=d[a-1],E=I(d,0.25),q=I(d,0.75),M=q-E,z=E-1.5*M,V=q+1.5*M,K=E-3*M,U=q+3*M,J=0,j=0;for(let v=0;v<a;v++){let S=n[v];if(S<K||S>U)j++;else if(S<z||S>V)J++}return{unit:"ns",samples:n,mean:f,median:w,stddev:A,min:H,max:O,outliers:{mild:J,severe:j}}}function L(n){let a=new Float64Array(n.length);return a.set(n),a.sort(),a}function I(n,a){let d=n.length;if(d===1)return n[0];let m=a*(d-1),f=Math.floor(m),w=Math.ceil(m);if(f===w)return n[f];let b=m-f;return n[f]*(1-b)+n[w]*b}var Z=5000000,Q=200;function p(n,a,d="subprocess"){let m=[],f=n.samples[0];if(f!==void 0){let b=L(n.samples),A=I(b,0.25),O=I(b,0.75)-A;if(f>n.median+3*O&&O>0)m.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)m.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<Z)m.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<Q)m.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 w=a.filter((b)=>b!==void 0&&b!==0);if(w.length>0)m.push({code:"nonzero-exit",message:`${w.length} of ${a.length} trial(s) exited non-zero.`,data:{exitCodes:w}});return m}
|
|
4
|
-
export{g,e,c,r,u,k,R,i,h,P,s,y,o,t,l,p,F,D,T,C,x,N};
|