ostia 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -34,7 +34,7 @@ Find a CPU hotspot (profiler runs as a separate labeled trial, never mixed into
34
34
  timing numbers above):
35
35
 
36
36
  ```sh
37
- ostia run --runs 5 --cpu --cpu-interval 200 --export-json .ostia/doc.json fixtures/work.ts
37
+ ostia run --runs 5 --cpu --cpu-interval 200 --export-json node_modules/.cache/ostia/doc.json fixtures/work.ts
38
38
  ```
39
39
 
40
40
  ```
@@ -45,10 +45,16 @@ bun fixtures/work.ts 275.815 ± 2.853 273.334…281.384
45
45
  CPU capture - bun fixtures/work.ts (instrumented, 200µs interval, diagnostic wall 297.578ms)
46
46
  100.0% 284.19ms self hashLoop
47
47
  0.0% 0.00ms self (root)
48
- artifact: .ostia/artifacts/<run-id>-cpu.cpuprofile
48
+ artifact: node_modules/.cache/ostia/artifacts/<run-id>-cpu.cpuprofile
49
49
  ```
50
50
 
51
- Gate a change against a local baseline (baselines are gitignored under `.ostia/`):
51
+ Scratch/artifact output defaults to `node_modules/.cache/ostia` (already gitignored
52
+ everywhere, no setup needed - same convention as Babel/ESLint/Jest caches). Baselines are
53
+ the one exception: they default to `.ostia/baselines/` at the repo root instead, since
54
+ they need to survive `node_modules` reinstalls between branches and CI jobs, so gitignore
55
+ `.ostia/` if you use `ostia ci`.
56
+
57
+ Gate a change against a local baseline:
52
58
 
53
59
  ```sh
54
60
  bun run baseline # on known-good: measure ostia.config.json -> .ostia/baselines/main.json
@@ -120,13 +126,16 @@ Heap snapshot - bun fixtures/allocate.ts (instrumented, 2518 objects, 0.12MB)
120
126
  321 closure
121
127
  216 object shape
122
128
  104 hidden
123
- artifact: .ostia/artifacts/<run-id>-heap.heapsnapshot
129
+ artifact: node_modules/.cache/ostia/artifacts/<run-id>-heap.heapsnapshot
124
130
  ```
125
131
 
126
132
  ### `ostia bench`
127
133
 
128
- In-process microbenchmarks registered with `group()` / `task()`. Time budget + min
129
- samples (mitata-shaped); batches when a call is too fast for `Bun.nanoseconds()`.
134
+ In-process microbenchmarks registered with `group()` / `task()`. Each task samples
135
+ for `--time-budget` (default 500ms). `--min-samples` is a hard floor kept even when it
136
+ overruns the budget; left unset, the floor is cost-aware (as many trials as fit in the
137
+ budget, clamped to 3..20) so one slow task can't blow the suite's total. Fast calls are
138
+ batched so a trial spans at least 1µs and a full budget yields about 10k trials at most.
130
139
 
131
140
  ```sh
132
141
  ostia bench bench/*.ts
@@ -189,9 +198,9 @@ Turn CPU evidence into files for other tools. Formats: `collapsed`, `mermaid`,
189
198
  `speedscope`, `cpuprofile` (pass-through of a real CDP artifact when present).
190
199
 
191
200
  ```sh
192
- ostia viz .ostia/doc.json --format collapsed
193
- ostia viz .ostia/doc.json --format mermaid
194
- ostia viz .ostia/doc.json --format speedscope > flame.json
201
+ ostia viz doc.json --format collapsed
202
+ ostia viz doc.json --format mermaid
203
+ ostia viz doc.json --format speedscope > flame.json
195
204
  ```
196
205
 
197
206
  Collapsed stacks (one line per stack; feeds `flamegraph.pl` and friends):
@@ -267,6 +276,10 @@ Exit codes: `0` pass, `1` regression, `2` harness error (missing config/baseline
267
276
 
268
277
  `inputs` is optional. Workloads with no `inputs` always rerun (cache fails conservative).
269
278
 
279
+ Two directory options, both optional: `outDir` (default `node_modules/.cache/ostia`) for
280
+ scratch/cache/artifacts, and `baselineDir` (default `.ostia/baselines`) for baselines. They're
281
+ independent - `baselineDir` doesn't move just because you override `outDir`.
282
+
270
283
  #### Baselines (local and CI)
271
284
 
272
285
  Baselines are JSON under `.ostia/baselines/` (gitignored). `ostia ci` only needs the file
@@ -329,7 +342,7 @@ const doc = await run({
329
342
  cpu: true,
330
343
  heap: false,
331
344
  cpuIntervalUs: 200,
332
- outDir: ".ostia",
345
+ outDir: "node_modules/.cache/ostia", // default; artifacts land under here
333
346
  })
334
347
  ```
335
348
 
@@ -365,6 +378,19 @@ import { group, task } from "ostia"
365
378
  group("parse", () => {
366
379
  task("small input", () => parse(smallBuf))
367
380
  task("large input", () => parse(largeBuf))
381
+ // Per-task options override the suite-wide time budget / min samples.
382
+ task("full pipeline", () => build(), { timeBudgetMs: 2000, minSamples: 10 })
383
+ })
384
+ ```
385
+
386
+ Mark one task per group as the `Relative` reference with `{ baseline: true }`
387
+ (mirrors mitata's `baseline()`); otherwise `Relative` defaults to the fastest
388
+ task in the group:
389
+
390
+ ```ts
391
+ group("parse", () => {
392
+ task("current impl", () => parse(buf), { baseline: true })
393
+ task("candidate impl", () => parseFast(buf))
368
394
  })
369
395
  ```
370
396
 
@@ -395,8 +421,8 @@ const diffs = compareDocuments(baselineDoc, candidateDoc, {
395
421
  ### `saveDocument` / `loadDocument`
396
422
 
397
423
  ```ts
398
- await saveDocument(doc, ".ostia/doc.json")
399
- const loaded: ProfileDocument = await loadDocument(".ostia/doc.json")
424
+ await saveDocument(doc, "doc.json")
425
+ const loaded: ProfileDocument = await loadDocument("doc.json")
400
426
  ```
401
427
 
402
428
  ### `renderers`
@@ -0,0 +1,19 @@
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};
@@ -0,0 +1,4 @@
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};
package/cli.js CHANGED
@@ -1,29 +1,12 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
- function q(e){return JSON.stringify(W(e))}function W(e){if(Array.isArray(e))return e.map(W);if(e!==null&&typeof e==="object"){let n={};for(let t of Object.keys(e).sort())n[t]=W(e[t]);return n}return e}function T(e,...n){let t=Bun.CryptoHasher.hash("sha256",q(n),"hex");return`${e}_${t.slice(0,16)}`}function Ye(e){return e.startsWith("file://")?e.slice(7):e}function K(e,n,t){let s=e.nodes,r=s.length,o=new Map,i=[],a=new Map,c=new Int32Array(r);for(let m=0;m<r;m++){let g=s[m],f=g.callFrame,y=Ye(f.url),C=o.get(f.functionName);if(C===void 0)C=new Map,o.set(f.functionName,C);let N=C.get(y);if(N===void 0)N=i.length,C.set(y,N),i.push({key:T("fr",f.functionName,y),name:f.functionName,url:y||void 0,line:f.lineNumber>=0?f.lineNumber:void 0,col:f.columnNumber>=0?f.columnNumber:void 0});c[m]=N,a.set(g.id,m)}let l=Array(r);for(let m=0;m<r;m++){let g=s[m];l[m]={id:g.id,frameIx:c[a.get(g.id)],children:g.children??[]}}let u=new Float64Array(r),p=new Float64Array(r),d=e.samples,b=e.timeDeltas;for(let m=0;m<d.length;m++){let g=a.get(d[m]);if(g===void 0)continue;u[g]+=b[m]??0,p[g]+=1}let x=new Int32Array(r).fill(-1);for(let m=0;m<r;m++){let g=s[m].children;if(!g)continue;for(let f of g){let y=a.get(f);if(y!==void 0)x[y]=m}}let w=[],R=[];for(let m=r-1;m>=0;m--)if(x[m]===-1)R.push(m);while(R.length>0){let m=R.pop();w.push(m);let g=s[m].children;if(!g)continue;for(let f of g){let y=a.get(f);if(y!==void 0&&x[y]===m)R.push(y)}}let k=new Float64Array(r);for(let m=w.length-1;m>=0;m--){let g=w[m];k[g]+=u[g];let f=x[g];if(f>=0)k[f]+=k[g]}let P=Array(i.length),h=[];for(let m=0;m<r;m++){let g=l[m].frameIx,f=P[g];if(f)f.selfUs+=u[m],f.totalUs+=k[m],f.samples+=p[m];else{let y={frameIx:g,selfUs:u[m],totalUs:k[m],samples:p[m]};P[g]=y,h.push(y)}}return{origin:n,samplingIntervalUs:t,frames:i,nodes:l,totals:h.sort((m,g)=>g.selfUs-m.selfUs),samples:{nodeIds:e.samples,timeDeltasUs:e.timeDeltas}}}function Qe(e,n,t,s){let r=["--cpu-prof","--cpu-prof-dir",n,"--cpu-prof-name",t,"--cpu-prof-interval",String(s)],o=e[0];if(o==="bun"||o?.endsWith("/bun"))return[o,...r,...e.slice(1)];return e}async function pe(e){let n=`${e.artifactDir}/${e.fileName}`,t=e.argv[0],s=t==="bun"||t?.endsWith("/bun"),r=Qe(e.argv,e.artifactDir,e.fileName,e.intervalUs),o=s?e.env:{...process.env,...e.env,BUN_OPTIONS:`--cpu-prof --cpu-prof-dir ${e.artifactDir} --cpu-prof-name ${e.fileName} --cpu-prof-interval ${e.intervalUs}`},i=Bun.nanoseconds(),c=await Bun.spawn(r,{cwd:e.cwd,env:o,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,l=Bun.nanoseconds()-i,u=Bun.file(n);if(!await u.exists())return{diagnosticWallNs:l,exitCode:c,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${n} after exit ${c}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:n,argv:e.argv}}]};let p=await u.json(),d=K(p,"cpu-prof",e.intervalUs),b=p.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:l,exitCode:c,artifactPath:n,cpu:d,warnings:b}}function me(e,n="heap-prof"){let{node_fields:t,node_types:s}=e.snapshot.meta,r=t.indexOf("type"),o=t.indexOf("self_size"),i=t.length,a=s[0];if(r===-1||o===-1||!Array.isArray(a))return{origin:n,typeCounts:[],objectCount:e.snapshot.node_count};let c=a.length,l=Array(c),u=new Map,p=[],d=0,b=e.nodes,x=b.length;for(let h=0;h<x;h+=i){let m=b[h+r],g=b[h+o]??0;d+=g;let f;if(m>=0&&m<c){if(f=l[m],f===void 0)f={type:a[m],count:0,bytes:0},l[m]=f,p.push(f)}else{let y=`unknown(${m})`;if(f=u.get(y),f===void 0)f={type:y,count:0,bytes:0},u.set(y,f),p.push(f)}f.count++,f.bytes+=g}let w=p.sort((h,m)=>m.count-h.count),R=w.slice(0,20),k=w.slice(20),P=R.map(({type:h,count:m,bytes:g})=>({type:h,count:m,retainedBytes:g}));if(k.length>0){let h=0,m=0;for(let g of k)h+=g.count,m+=g.bytes;P.push({type:"other",count:h,retainedBytes:m})}return{origin:n,heapSizeBytes:d,objectCount:e.snapshot.node_count,typeCounts:P}}function Xe(e,n,t){let s=["--heap-prof","--heap-prof-dir",n,"--heap-prof-name",t],r=e[0];if(r==="bun"||r?.endsWith("/bun"))return[r,...s,...e.slice(1)];return e}async function de(e){let n=`${e.artifactDir}/${e.fileName}`,t=e.argv[0],s=t==="bun"||t?.endsWith("/bun"),r=Xe(e.argv,e.artifactDir,e.fileName),o=s?e.env:{...process.env,...e.env,BUN_OPTIONS:`--heap-prof --heap-prof-dir ${e.artifactDir} --heap-prof-name ${e.fileName}`},i=Bun.nanoseconds(),c=await Bun.spawn(r,{cwd:e.cwd,env:o,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,l=Bun.nanoseconds()-i,u=Bun.file(n);if(!await u.exists())return{diagnosticWallNs:l,exitCode:c,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${n} after exit ${c}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:n,argv:e.argv}}]};let p=await u.json(),d=me(p,"heap-prof");return{diagnosticWallNs:l,exitCode:c,artifactPath:n,heap:d,warnings:[]}}import{Session as en}from"inspector/promises";var nn=1000;async function fe(e,n={}){let t=n.intervalUs??nn,s=new en;s.connect();let r=Bun.nanoseconds();try{await s.post("Profiler.enable"),await s.post("Profiler.setSamplingInterval",{interval:t}),await s.post("Profiler.start");let o=await e(),{profile:i}=await s.post("Profiler.stop"),a=Bun.nanoseconds()-r,c=K(i,"inspector",t);return{result:o,cpu:c,diagnosticWallNs:a}}finally{s.disconnect()}}import{profile as rn}from"bun:jsc";var tn=new Map([["LLInt","llint"],["Baseline","baseline"],["DFG","dfg"],["FTL","ftl"]]),ge=4294967295;function he(e,n){let t=n??e.interval*1e6,s=new Map,r=[];function o(f,y,C,N){let D=s.get(f);if(D===void 0)D=new Map,s.set(f,D);let F=y??"",U=D.get(F);if(U===void 0)U=r.length,D.set(F,U),r.push({key:T("fr",f,F),name:f,url:y,line:C,col:N});return U}function i(f){let y=f.line===ge,C=y?void 0:f.line-1,N=y||f.column===ge?void 0:f.column-1;return o(f.name,f.sourceURL,C,N)}let a=o("(root)",void 0,void 0,void 0),c=1,l={id:0,frameIx:a,children:new Map,selfUs:0,samples:0,totalUs:0},u=new Map([[0,l]]),p={llint:0,baseline:0,dfg:0,ftl:0},d=new Map,b=[],x=[];for(let f of e.traces){let y=f.frames,C=l;for(let F=y.length-1;F>=0;F--){let U=i(y[F]),A=C.children.get(U);if(!A)A={id:c++,frameIx:U,children:new Map,selfUs:0,samples:0,totalUs:0},C.children.set(U,A),u.set(A.id,A);C=A}C.selfUs+=t,C.samples+=1,b.push(C.id),x.push(t);let N=y[0],D=N&&tn.get(N.category);if(D){p[D]++;let F=d.get(D)??new Map;F.set(C.frameIx,(F.get(C.frameIx)??0)+1),d.set(D,F)}}function w(f){let y=f.selfUs;for(let C of f.children.values())y+=w(C);return f.totalUs=y,y}w(l);let R=new Map;function k(f){let y=R.get(f.frameIx);if(y)y.selfUs+=f.selfUs,y.totalUs+=f.totalUs,y.samples+=f.samples;else R.set(f.frameIx,{frameIx:f.frameIx,selfUs:f.selfUs,totalUs:f.totalUs,samples:f.samples});for(let C of f.children.values())k(C)}k(l);let P=[...u.values()].map((f)=>({id:f.id,frameIx:f.frameIx,children:[...f.children.values()].map((y)=>y.id)})),h={origin:"jsc-profile",samplingIntervalUs:t,frames:r,nodes:P,totals:[...R.values()].sort((f,y)=>y.selfUs-f.selfUs),samples:{nodeIds:b,timeDeltasUs:x}},m=[...d.entries()].flatMap(([f,y])=>[...y.entries()].sort((C,N)=>N[1]-C[1]).slice(0,3).map(([C,N])=>({tier:f,frameKey:r[C].key,samples:N})));return{cpu:h,jit:{origin:"jsc-profile",tiers:p,topFramesByTier:m}}}var sn=1000;async function be(e,n={}){let t=n.intervalUs??sn,s,r=Bun.nanoseconds(),o=await rn(async()=>(s=await e(),s),t),i=Bun.nanoseconds()-r,{cpu:a,jit:c}=he(o.stackTraces,t);return{result:s,cpu:a,jit:c,diagnosticWallNs:i}}var _="0.1.0";function M(e,n){return{schemaVersion:1,toolVersion:_,bunVersion:Bun.version,platform:{os:process.platform,arch:process.arch},createdAt:new Date().toISOString(),workloads:e,runs:n}}function G(e,n){return{id:T("wl","subprocess",e,process.cwd()),kind:"subprocess",command:e,label:n}}function we(e,n){return{id:T("wl","inprocess",e.name,e.toString()),kind:"inprocess",label:n}}function Z(e){return{id:T("run",e.workload.id,"timing",e.configFingerprint,Bun.version,_),workloadId:e.workload.id,phase:"timing",instrumented:!1,configFingerprint:e.configFingerprint,trials:e.trials,timing:e.timing,warnings:e.warnings,artifacts:[],memory:on(e.trials)}}function on(e){let n=e.map((t)=>t.maxRssBytes).filter((t)=>t!==void 0);if(n.length===0)return;return{origin:"resourceUsage",perTrial:e.map((t)=>({rssBytes:t.maxRssBytes})),maxRssBytes:Math.max(...n)}}function Y(e){return{id:T("run",e.workload.id,e.phase,e.configFingerprint,Bun.version,_),workloadId:e.workload.id,phase:e.phase,instrumented:!0,configFingerprint:e.configFingerprint,trials:[{i:0,wallNs:e.diagnosticWallNs,exitCode:e.exitCode}],diagnosticWallNs:e.diagnosticWallNs,cpu:e.cpu,heap:e.heap,jit:e.jit,warnings:e.warnings,artifacts:e.artifacts}}async function ye(e,n,t){let r=await Bun.file(t).arrayBuffer(),o=new Bun.CryptoHasher("sha256");return o.update(r),{id:T("art",e,n,t),kind:n,path:t,sha256:o.digest("hex"),bytes:r.byteLength}}function H(e){return T("cfg",e)}function re(e){return`${JSON.stringify(W(e),null,2)}
4
- `}async function E(e,n){await Bun.write(n,re(e))}async function v(e){let n=await Bun.file(e).text();return JSON.parse(n)}async function se(e){let n=Bun.nanoseconds(),t=Bun.spawn(e.argv,{cwd:e.cwd,env:e.env,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),s=await t.exited,r=Bun.nanoseconds(),o=t.resourceUsage?.();return{wallNs:r-n,exitCode:s,userNs:o?Number(o.cpuTime.user)*1000:void 0,systemNs:o?Number(o.cpuTime.system)*1000:void 0,maxRssBytes:o?.maxRSS}}function xe(e){return e.trim().split(/\s+/).filter(Boolean)}function Re(e){if(e.length===0)throw Error("computeTimingStats: samples must be non-empty");let n=e.length,t=ke(e),s=0;for(let h=0;h<n;h++)s+=e[h];let r=s/n,o=L(t,0.5),i=0;for(let h=0;h<n;h++){let m=e[h]-r;i+=m*m}let a=Math.sqrt(i/n),c=t[0],l=t[n-1],u=L(t,0.25),p=L(t,0.75),d=p-u,b=u-1.5*d,x=p+1.5*d,w=u-3*d,R=p+3*d,k=0,P=0;for(let h=0;h<n;h++){let m=e[h];if(m<w||m>R)P++;else if(m<b||m>x)k++}return{unit:"ns",samples:e,mean:r,median:o,stddev:a,min:c,max:l,outliers:{mild:k,severe:P}}}function ke(e){let n=new Float64Array(e.length);return n.set(e),n.sort(),n}function L(e,n){let t=e.length;if(t===1)return e[0];let s=n*(t-1),r=Math.floor(s),o=Math.ceil(s);if(r===o)return e[r];let i=s-r;return e[r]*(1-i)+e[o]*i}var an=5000000,cn=200;function Pe(e,n,t="subprocess"){let s=[],r=e.samples[0];if(r!==void 0){let i=ke(e.samples),a=L(i,0.25),l=L(i,0.75)-a;if(r>e.median+3*l&&l>0)s.push({code:"slow-first-run",message:`First run took ${(r/1e6).toFixed(2)}ms, much slower than the median ${(e.median/1e6).toFixed(2)}ms. Consider more warmup.`,data:{firstNs:r,medianNs:e.median}})}if(e.outliers.mild+e.outliers.severe>0)s.push({code:"outliers-detected",message:`${e.outliers.mild+e.outliers.severe} outlier(s) detected (${e.outliers.severe} severe, ${e.outliers.mild} mild).`,data:e.outliers});if(t==="subprocess"&&e.median<an)s.push({code:"fast-command",message:`Median run time (${(e.median/1e6).toFixed(3)}ms) is very fast; results may be dominated by spawn overhead.`,data:{medianNs:e.median}});if(t==="inprocess"&&e.median<cn)s.push({code:"below-timer-resolution",message:`Median run time (${e.median.toFixed(0)}ns) is close to timer resolution; consider a larger batch size or a coarser operation.`,data:{medianNs:e.median}});let o=n.filter((i)=>i!==void 0&&i!==0);if(o.length>0)s.push({code:"nonzero-exit",message:`${o.length} of ${n.length} trial(s) exited non-zero.`,data:{exitCodes:o}});return s}var un=10,ln=3000000000,pn=3;async function Q(e){let n=e.warmup??pn;for(let u=0;u<n;u++)await se(e);let t=[],s=e.runs??e.minRuns??un,r=e.runs!==void 0?0:e.minTotalNs??ln,o=0,i=0;while(i<s||o<r){let u=await se(e);if(t.push({i,wallNs:u.wallNs,exitCode:u.exitCode,userNs:u.userNs,systemNs:u.systemNs,maxRssBytes:u.maxRssBytes}),o+=u.wallNs,i++,e.runs!==void 0&&i>=e.runs)break}let a=t.map((u)=>u.wallNs),c=Re(a),l=Pe(c,t.map((u)=>u.exitCode));return{trials:t,timing:c,warnings:l}}var mn=new URL("./runner.ts",import.meta.url).pathname,dn=".ostia";async function oe(e){let t=`${e.outDir??dn}/bench-tmp`,s=e.cwd??process.cwd(),r={timeBudgetMs:e.timeBudgetMs,minSamples:e.minSamples,gc:e.gc},o=[],i=[];try{for(let a of e.suites){let c=a.startsWith("/")?a:`${s}/${a}`,l=`${t}/${T("bench-out",c)}.json`,p=await Bun.spawn(["bun",mn,c,l,JSON.stringify(r)],{cwd:s,stdout:"inherit",stderr:"inherit",stdin:"ignore"}).exited;if(p!==0)throw Error(`Bench suite failed: ${a} (runner exited ${p})`);let d=await v(l);o.push(...d.workloads),i.push(...d.runs)}}finally{await Bun.spawn(["rm","-rf",t]).exited}return M(o,i)}var fn=[],X;function gn(e,n){let t=X;X=e;try{n()}finally{X=t}}function hn(e,n){fn.push({groupName:X,name:e,fn:n})}var J={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000};function ee(e,n){if(e===0)return n===0?0:1/0;return(n-e)/e*100}function O(e,n,t){return e.runs.find((s)=>s.workloadId===n&&s.phase===t)}function ie(e,n,t=J){let s=new Set(n.workloads.map((o)=>o.id)),r=[];for(let o of e.workloads){if(!s.has(o.id))continue;let i=ae(e,n,o.id,t);if(i)r.push(i)}return r}function ae(e,n,t,s=J){let r=O(e,t,"timing"),o=O(n,t,"timing"),i=O(e,t,"cpu"),a=O(n,t,"cpu"),c=O(e,t,"heap"),l=O(n,t,"heap"),u=r?.id??i?.id??c?.id,p=o?.id??a?.id??l?.id;if(!u||!p)return;let d=!1,b;if(r?.timing&&o?.timing){let R=ee(r.timing.median,o.timing.median),k=ee(r.timing.mean,o.timing.mean),P=R>s.timingPct?"regressed":R<-s.timingPct?"improved":"unchanged";if(P==="regressed")d=!0;b={medianDeltaPct:R,meanDeltaPct:k,verdict:P}}let x;if(i?.cpu&&a?.cpu){let R=new Map(i.cpu.totals.map((g)=>[i.cpu.frames[g.frameIx].key,g])),k=new Map(a.cpu.totals.map((g)=>[a.cpu.frames[g.frameIx].key,g])),P=new Map(i.cpu.frames.map((g)=>[g.key,g.name])),h=new Map(a.cpu.frames.map((g)=>[g.key,g.name]));x=[...new Set([...R.keys(),...k.keys()])].map((g)=>{let f=R.get(g)?.selfUs??0,y=k.get(g)?.selfUs??0;return{frameKey:g,name:h.get(g)??P.get(g)??g,baseSelfUs:f,candSelfUs:y,deltaPct:ee(f,y)}}).sort((g,f)=>Math.abs(f.deltaPct)-Math.abs(g.deltaPct));for(let g of x)if((g.baseSelfUs>=s.minFrameSelfUs||g.candSelfUs>=s.minFrameSelfUs)&&g.deltaPct>s.frameSelfPct)d=!0}let w;if(c?.heap&&l?.heap){let R=new Map(c.heap.typeCounts.map((h)=>[h.type,h])),k=new Map(l.heap.typeCounts.map((h)=>[h.type,h]));w=[...new Set([...R.keys(),...k.keys()])].map((h)=>{let m=R.get(h),g=k.get(h);return{type:h,baseCount:m?.count??0,candCount:g?.count??0,baseBytes:m?.retainedBytes,candBytes:g?.retainedBytes,deltaPct:ee(m?.count??0,g?.count??0)}}).sort((h,m)=>Math.abs(m.deltaPct)-Math.abs(h.deltaPct));for(let h of w)if(h.deltaPct>s.heapTypePct)d=!0}return{id:T("cmp",u,p),baselineRunId:u,candidateRunId:p,timing:b,frames:x,heapTypes:w,thresholds:s,verdict:d?"fail":"pass"}}function S(e,n){if(n){let t=e.runs.find((s)=>s.id===n);return t?.cpu?[t]:[]}return e.runs.filter((t)=>t.phase==="cpu"&&t.cpu)}function j(e){let n=e.nodes,t=n.length,s=bn(e),r=new Int32Array(t).fill(-1);for(let c=0;c<t;c++)for(let l of n[c].children){let u=s(l);if(u!==-1)r[u]=c}let o=[];for(let c=0;c<t;c++)if(r[c]===-1)o.push(c);let i=[],a=[];for(let c=o.length-1;c>=0;c--)a.push(o[c]);while(a.length>0){let c=a.pop();i.push(c);for(let l of n[c].children){let u=s(l);if(u!==-1&&r[u]===c)a.push(u)}}return{count:t,indexOf:s,parentIx:r,roots:o,order:i}}function bn(e){let n=e.nodes,t=n.length,s=1/0,r=-1/0,o=!0;for(let a=0;a<t;a++){let c=n[a].id;if(!Number.isInteger(c)){o=!1;break}if(c<s)s=c;if(c>r)r=c}if(o&&t>0&&r-s<t*4+64){let a=r-s+1,c=new Int32Array(a).fill(-1);for(let l=0;l<t;l++)c[n[l].id-s]=l;return(l)=>{let u=l-s;return u>=0&&u<a?c[u]:-1}}let i=new Map;for(let a=0;a<t;a++)i.set(n[a].id,a);return(a)=>i.get(a)??-1}function Ce(e,n){let{count:t,indexOf:s,parentIx:r,order:o}=n,i=new Float64Array(t),a=new Float64Array(t),c=e.samples?.nodeIds??[],l=e.samples?.timeDeltasUs??[];for(let p=0;p<c.length;p++){let d=s(c[p]);if(d===-1)continue;i[d]+=l[p]??0,a[d]+=1}let u=new Float64Array(t);for(let p=o.length-1;p>=0;p--){let d=o[p];u[d]+=i[d];let b=r[d];if(b>=0)u[b]+=u[d]}return{selfUs:i,totalUs:u,samples:a}}var Te={name:"collapsed",async render(e,n={}){return{files:S(e,n.runId).map((r)=>{let o=r.cpu,{nodes:i,frames:a}=o,c=j(o),l=Array(c.count);for(let x of c.order){let w=a[i[x].frameIx].name||"(anonymous)",R=c.parentIx[x];l[x]=R===-1?w:`${l[R]};${w}`}let u=new Float64Array(c.count),p=[],d=o.samples?.nodeIds??[];for(let x=0;x<d.length;x++){let w=c.indexOf(d[x]);if(w===-1)continue;if(u[w]++===0)p.push(w)}let b=Array(p.length);for(let x=0;x<p.length;x++){let w=p[x];b[x]=`${l[w]} ${u[w]}`}return{path:`${r.id}.collapsed.txt`,content:b.join(`
5
- `)+(b.length>0?`
6
- `:"")}})}}};var $e={name:"cpuprofile",async render(e,n={}){let t=S(e,n.runId),s=[],r=[];for(let o of t){if(o.cpu?.origin!=="cpu-prof"&&o.cpu?.origin!=="inspector"){r.push(`${o.id} (origin ${o.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let i=o.artifacts.find((c)=>c.kind==="cpuprofile");if(!i){r.push(`${o.id} (no cpuprofile artifact recorded on this run)`);continue}let a=Bun.file(i.path);if(!await a.exists()){r.push(`${o.id} (artifact missing on disk: ${i.path})`);continue}s.push({path:`${o.id}.cpuprofile`,content:await a.text()})}if(s.length===0&&r.length>0)return{text:`No .cpuprofile artifacts available:
7
- ${r.map((o)=>` - ${o}`).join(`
3
+ import{m,a,d,b,f,n,w}from"./chunk-m8zhsw7r.js";import{e,c,r,u,i,s,o,t}from"./chunk-qh19pbhc.js";function q(p){return e("cache",p.workloadId,p.phase,p.configFingerprint,p.bunVersion,p.toolVersion,p.instrumented,p.inputsDigest??null)}async function v(p,l=process.cwd()){if(p.length===0)return;let h=new Set;for(let k of p){let P=new Bun.Glob(k);for await(let C of P.scan({cwd:l,absolute:!1}))h.add(C)}let x=[...h].sort(),g=await Promise.all(x.map(async(k)=>{let P=await Bun.file(`${l}/${k}`).arrayBuffer();return{path:k,sha256:Bun.CryptoHasher.hash("sha256",P,"hex")}}));return e("inputs",g)}function _(p,l){return`${p}/cache/${l}.json`}async function J(p,l){let h=Bun.file(_(p,l));if(!await h.exists())return;return await h.json()}async function L(p,l,h){await Bun.write(_(p,l),`${JSON.stringify(h,null,2)}
4
+ `)}var Z="node_modules/.cache/ostia",X=".ostia/baselines",Q={runs:null,warmup:3,outDir:Z,baselineDir:X,baseline:"main",cpuIntervalUs:1000,thresholds:a,workloads:[]};async function M(p="ostia.config.json"){let l=Bun.file(p);if(!await l.exists())return;let h=await l.json();return{...Q,...h,thresholds:{...a,...h.thresholds??{}}}}function V(p,l){return`${p.baselineDir}/${l??p.baseline}.json`}class S extends Error{path;constructor(p){super(`No baseline document at ${p}. Create one with: ostia run --export-json ${p} <command...>`);this.path=p}}async function W(p){let{config:l}=p,h=V(l,p.baselineName);if(!await Bun.file(h).exists())throw new S(h);let g=await t(h),k=[],P=0,C=0,D=0;for(let y of l.workloads){let N=u(y.command,y.label),G=await v(y.inputs??[]),O=s({runs:l.runs,warmup:l.warmup}),U=q({workloadId:N.id,phase:"timing",configFingerprint:O,bunVersion:Bun.version,toolVersion:c,instrumented:!1,inputsDigest:G}),H=p.full?void 0:await J(l.outDir,U),I,T;if(H)I=H,T="cached",C++;else{P++;let B=await f({argv:y.command,runs:l.runs??void 0,warmup:l.warmup});I=i({workload:N,configFingerprint:O,trials:B.trials,timing:B.timing,warnings:B.warnings}),await L(l.outDir,U,I),T="executed",D++}k.push({workload:N,status:T,run:I})}let R=r(k.map((y)=>y.workload),k.map((y)=>y.run)),A=0,F=0,j=0;for(let y of k){let N=b(g,R,y.workload.id,l.thresholds);if(!N){j++;continue}if(y.comparison=N,N.verdict==="pass")A++;else F++}return R.comparisons=k.map((y)=>y.comparison).filter((y)=>y!==void 0),{document:R,summary:{total:l.workloads.length,affected:P,cached:C,executed:D,passed:A,regressed:F,missingBaseline:j,results:k}}}function z(p){let l=[];if(l.push(`${p.total} workloads`),l.push(`${p.affected} affected by this change`),l.push(`${p.cached} cached`),l.push(`${p.executed} executed`),p.missingBaseline>0)l.push(`${p.missingBaseline} skipped (no matching baseline workload)`);let h=p.results.filter((x)=>x.comparison?.verdict==="fail").map((x)=>{let g=x.comparison.timing,k=x.workload.label??x.workload.command?.join(" ")??x.workload.id;return g?`${g.medianDeltaPct>0?"+":""}${g.medianDeltaPct.toFixed(1)}% median on ${k}`:k});return l.push(`${p.passed} passed ${p.regressed} regressed${h.length>0?` (${h.join(", ")})`:""}`),l.push(""),l.push(`Profile CI: ${p.regressed>0?"\u2717":"\u2713"}`),`${l.join(`
8
5
  `)}
9
- `};return{files:s}}};var Ne={name:"json",async render(e){return{text:re(e)}}};var Ie={name:"jsonl",async render(e){let{runs:n,...t}=e;return{text:`${[q(t),...n.map((r)=>q(r))].join(`
10
- `)}
11
- `}}};function B(e){return(e/1e6).toFixed(3)}function ne(e){return e?.label??e?.command?.join(" ")??e?.entry?.task??e?.id??"unknown"}var Fe=10,De=10,ve={name:"markdown",async render(e){let n=new Map(e.workloads.map((r)=>[r.id,r])),t=[];t.push("# Profile Report",""),t.push(`Bun ${e.bunVersion} \xB7 ostia ${e.toolVersion} \xB7 ${e.platform.os}/${e.platform.arch} \xB7 ${e.createdAt}`,"");let s=e.runs.filter((r)=>r.phase==="timing"&&r.timing!==void 0);if(s.length>0){t.push("## Timing",""),t.push("| Command | Mean \xB1 SD (ms) | Min\u2026Max (ms) | Median (ms) |","|---|---|---|---|");for(let o of s){let i=ne(n.get(o.workloadId)),a=o.timing;t.push(`| ${i} | ${B(a.mean)} \xB1 ${B(a.stddev)} | ${B(a.min)}\u2026${B(a.max)} | ${B(a.median)} |`)}t.push("");let r=s.filter((o)=>o.warnings.length>0);if(r.length>0){t.push("### Warnings","");for(let o of r){let i=ne(n.get(o.workloadId));for(let a of o.warnings)t.push(`- **${i}**: ${a.message} (\`${a.code}\`)`)}t.push("")}}for(let r of e.runs){if(r.phase!=="cpu"&&r.phase!=="heap")continue;let o=ne(n.get(r.workloadId));if(r.phase==="cpu"){if(t.push(`## CPU capture - ${o}`,""),t.push(`instrumented, diagnostic wall ${B(r.diagnosticWallNs??0)}ms`,""),r.cpu){t.push(`origin: \`${r.cpu.origin}\`, interval: ${r.cpu.samplingIntervalUs}\xB5s`,""),t.push("| Self % | Self (ms) | Total (ms) | Frame |","|---|---|---|---|");let i=r.cpu.totals.reduce((a,c)=>a+c.selfUs,0)||1;for(let a of r.cpu.totals.slice(0,Fe)){let c=r.cpu.frames[a.frameIx],l=(a.selfUs/i*100).toFixed(1);t.push(`| ${l}% | ${(a.selfUs/1000).toFixed(2)} | ${(a.totalUs/1000).toFixed(2)} | ${c?.name||"(anonymous)"} |`)}if(t.push(""),r.jit){let a=r.jit.tiers;t.push(`JIT tiers: LLInt ${a.llint} \xB7 Baseline ${a.baseline} \xB7 DFG ${a.dfg} \xB7 FTL ${a.ftl}`,"")}}}else if(t.push(`## Heap snapshot - ${o}`,""),t.push(`instrumented, diagnostic wall ${B(r.diagnosticWallNs??0)}ms`,""),r.heap){t.push(`${r.heap.objectCount??"?"} objects, ${((r.heap.heapSizeBytes??0)/1e6).toFixed(2)}MB`,""),t.push("| Count | Type |","|---|---|");for(let i of r.heap.typeCounts.slice(0,De))t.push(`| ${i.count} | ${i.type} |`);t.push("")}for(let i of r.artifacts)t.push(`- artifact: \`${i.path}\``);for(let i of r.warnings)t.push(`- ! ${i.message} (\`${i.code}\`)`);if(r.artifacts.length>0||r.warnings.length>0)t.push("")}if(e.comparisons&&e.comparisons.length>0){t.push("## Comparisons","");for(let r of e.comparisons){let o=e.runs.find((a)=>a.id===r.candidateRunId),i=ne(o?n.get(o.workloadId):void 0);if(t.push(`### ${r.verdict==="pass"?"\u2713":"\u2717"} ${i}`,""),r.timing){let a=r.timing.medianDeltaPct>0?"+":"";t.push(`- timing: ${a}${r.timing.medianDeltaPct.toFixed(1)}% median (**${r.timing.verdict}**)`)}for(let a of r.frames?.slice(0,Fe)??[]){if(Math.abs(a.deltaPct)<0.5)continue;let c=a.deltaPct>0?"+":"";t.push(`- frame \`${a.name}\`: ${c}${a.deltaPct.toFixed(1)}% self-time (${(a.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(a.candSelfUs/1000).toFixed(2)}ms)`)}for(let a of r.heapTypes?.slice(0,De)??[]){if(Math.abs(a.deltaPct)<0.5)continue;let c=a.deltaPct>0?"+":"";t.push(`- heap \`${a.type}\`: ${c}${a.deltaPct.toFixed(1)}% count (${a.baseCount} \u2192 ${a.candCount})`)}t.push("")}}return{text:t.join(`
12
- `)}}};var wn=15;function ce(e){return`n${e}`}function yn(e,n,t){return`${(e||"(anonymous)").replace(/"/g,"'")} (self ${(n/1000).toFixed(2)}ms, total ${(t/1000).toFixed(2)}ms)`}function xn(e,n,t,s){let r=[];if(s<=0)return r;for(let o=0;o<n;o++){if(o===t)continue;let i=e[o];if(r.length===s&&i<=e[r[s-1]])continue;let a=r.length;while(a>0&&e[r[a-1]]<i)a--;if(r.splice(a,0,o),r.length>s)r.pop()}return r}var Ue={name:"mermaid",async render(e,n={}){let t=n.topN??wn;return{files:S(e,n.runId).map((o)=>{let i=o.cpu,{nodes:a,frames:c}=i,l=j(i),{selfUs:u,totalUs:p}=Ce(i,l),{parentIx:d}=l,b=l.roots[0]??-1,x=xn(u,l.count,b,t),w=new Set(b!==-1?[b]:[]),R=[];for(let P of x){R.length=0;for(let h=P;h!==-1;h=d[h])R.push(h);for(let h=R.length-1;h>=0;h--)w.add(R[h])}let k=["graph TD"];for(let P of w){let h=a[P].id;k.push(` ${ce(h)}["${yn(c[a[P].frameIx].name,u[P],p[P])}"]`)}for(let P of w){let h=d[P];if(h!==-1&&w.has(h))k.push(` ${ce(a[h].id)} --> ${ce(a[P].id)}`)}return{path:`${o.id}.mermaid.md`,content:`${k.join(`
13
- `)}
14
- `}})}}};var Rn="https://www.speedscope.app/file-format-schema.json";function Se(e){return e?.label??e?.command?.join(" ")??e?.entry?.task??"profile"}var Be={name:"speedscope",async render(e,n={}){let t=S(e,n.runId),s=new Map(e.workloads.map((o)=>[o.id,o]));return{files:t.map((o)=>{let i=o.cpu,{nodes:a}=i,c=j(i),l=i.samples?.nodeIds??[],u=i.samples?.timeDeltasUs??[],p=Array(c.count);for(let w of c.order){let R=c.parentIx[w],k=a[w].frameIx;p[w]=R===-1?[k]:[...p[R],k]}let d=Array(l.length);for(let w=0;w<l.length;w++){let R=c.indexOf(l[w]);d[w]=R===-1?[]:p[R]}let b=0;for(let w=0;w<u.length;w++)b+=u[w];let x={$schema:Rn,exporter:"ostia",name:Se(s.get(o.workloadId)),activeProfileIndex:0,shared:{frames:i.frames.map((w)=>({name:w.name||"(anonymous)",file:w.url,line:w.line!==void 0?w.line+1:void 0}))},profiles:[{type:"sampled",name:Se(s.get(o.workloadId)),unit:"microseconds",startValue:0,endValue:b,samples:d,weights:u}]};return{path:`${o.id}.speedscope.json`,content:`${JSON.stringify(x,null,2)}
15
- `}})}}};function z(e){return(e/1e6).toFixed(3)}function ue(e){return e.label??e.command?.join(" ")??e.entry?.task??e.id}var Me={name:"table",async render(e){let n=e.runs.filter((p)=>p.phase==="timing"&&p.timing!==void 0),t=new Map(e.workloads.map((p)=>[p.id,p]));if(n.length===0){let p=Ae(e,t);return{text:p.length>0?`${p.join(`
16
- `)}
17
- `:`(no timing runs)
18
- `}}let s=n.map((p)=>{let d=t.get(p.workloadId);return{run:p,workload:d,label:d?ue(d):p.workloadId}}),r=Math.min(...s.map((p)=>p.run.timing.median)),o=s.length>1,i=[],a=Math.max(7,...s.map((p)=>p.label.length)),c=o?`${"Command".padEnd(a)} Mean [ms] Min\u2026Max [ms] Relative`:`${"Command".padEnd(a)} Mean [ms] Min\u2026Max [ms]`;i.push(c),i.push("-".repeat(c.length));for(let{run:p,label:d}of s){let b=p.timing,x=`${z(b.mean)} \xB1 ${z(b.stddev)}`,w=`${z(b.min)}\u2026${z(b.max)}`,R=`${d.padEnd(a)} ${x.padEnd(15)} ${w.padEnd(18)}`;if(o){let k=b.median/r;R+=k===1?" 1.00\xD7":` ${k.toFixed(2)}\xD7 slower`}i.push(R);for(let k of p.warnings)i.push(` ! ${k.message}`)}let l=Pn(e,t);if(l.length>0)i.push(""),i.push(...l);let u=Ae(e,t);if(u.length>0)i.push(""),i.push(...u);return{text:`${i.join(`
19
- `)}
20
- `}}};function kn(e,n,t){let s=e.runs.find((o)=>o.id===t),r=s?n.get(s.workloadId):void 0;return r?ue(r):t}function Ae(e,n){if(!e.comparisons||e.comparisons.length===0)return[];let t=[];for(let s of e.comparisons){let r=kn(e,n,s.candidateRunId),o=s.verdict==="pass"?"\u2713":"\u2717";if(t.push(`${o} ${r}`),s.timing){let i=s.timing.medianDeltaPct>0?"+":"";t.push(` timing: ${i}${s.timing.medianDeltaPct.toFixed(1)}% median (${s.timing.verdict})`)}if(s.frames)for(let i of s.frames.slice(0,Ee)){if(Math.abs(i.deltaPct)<0.5)continue;let a=i.deltaPct>0?"+":"";t.push(` frame ${i.name}: ${a}${i.deltaPct.toFixed(1)}% self-time (${(i.baseSelfUs/1000).toFixed(2)}ms -> ${(i.candSelfUs/1000).toFixed(2)}ms)`)}if(s.heapTypes)for(let i of s.heapTypes.slice(0,Oe)){if(Math.abs(i.deltaPct)<0.5)continue;let a=i.deltaPct>0?"+":"";t.push(` heap ${i.type}: ${a}${i.deltaPct.toFixed(1)}% count (${i.baseCount} -> ${i.candCount})`)}}return t}var Ee=5,Oe=5;function Pn(e,n){let t=[];for(let s of e.runs){if(s.phase!=="cpu"&&s.phase!=="heap")continue;let r=n.get(s.workloadId),o=r?ue(r):s.workloadId;if(s.phase==="cpu")if(s.cpu){t.push(`CPU capture - ${o} (instrumented, ${s.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${z(s.diagnosticWallNs??0)}ms)`);let i=s.cpu.totals.reduce((a,c)=>a+c.selfUs,0)||1;for(let a of s.cpu.totals.slice(0,Ee)){let c=s.cpu.frames[a.frameIx],l=(a.selfUs/i*100).toFixed(1);t.push(` ${l.padStart(5)}% ${(a.selfUs/1000).toFixed(2).padStart(8)}ms self ${c?.name??"?"}`)}}else t.push(`CPU capture - ${o} (instrumented, no evidence captured)`);else if(s.heap){let i=((s.heap.heapSizeBytes??0)/1e6).toFixed(2);t.push(`Heap snapshot - ${o} (instrumented, ${s.heap.objectCount??"?"} objects, ${i}MB)`);for(let a of s.heap.typeCounts.slice(0,Oe))t.push(` ${String(a.count).padStart(6)} ${a.type}`)}else t.push(`Heap snapshot - ${o} (instrumented, no evidence captured)`);for(let i of s.artifacts)t.push(` artifact: ${i.path}`);for(let i of s.warnings)t.push(` ! ${i.message}`)}return t}var I={table:Me,json:Ne,markdown:ve,jsonl:Ie,collapsed:Te,mermaid:Ue,speedscope:Be,cpuprofile:$e};var Cn=".ostia",le=1000;async function We(e){let n=H({runs:e.runs??null,warmup:e.warmup??null,cpu:e.cpu??!1,heap:e.heap??!1,cpuIntervalUs:e.cpuIntervalUs??le}),s=`${e.outDir??Cn}/artifacts`,r=[],o=[];for(let i of e.commands){let a=Array.isArray(i)?i:xe(i),c=G(a,Array.isArray(i)?void 0:i);r.push(c);let l=await Q({argv:a,cwd:e.cwd,env:e.env,runs:e.runs,warmup:e.warmup}),u=Z({workload:c,configFingerprint:n,trials:l.trials,timing:l.timing,warnings:l.warnings});if(o.push(u),e.cpu){let p=`${u.id}-cpu.cpuprofile`,d=await pe({argv:a,cwd:e.cwd,env:e.env,artifactDir:s,fileName:p,intervalUs:e.cpuIntervalUs??le});o.push(await je({workload:c,phase:"cpu",configFingerprint:n,diagnosticWallNs:d.diagnosticWallNs,exitCode:d.exitCode,cpu:d.cpu,artifactPath:d.artifactPath,artifactKind:"cpuprofile",warnings:d.warnings}))}if(e.heap){let p=`${u.id}-heap.heapsnapshot`,d=await de({argv:a,cwd:e.cwd,env:e.env,artifactDir:s,fileName:p});o.push(await je({workload:c,phase:"heap",configFingerprint:n,diagnosticWallNs:d.diagnosticWallNs,exitCode:d.exitCode,heap:d.heap,artifactPath:d.artifactPath,artifactKind:"heapsnapshot",warnings:d.warnings}))}}return M(r,o)}async function je(e){let n=`${e.workload.id}-${e.phase}-${e.configFingerprint}`,t=e.artifactPath?[await ye(n,e.artifactKind,e.artifactPath)]:[];return Y({workload:e.workload,phase:e.phase,configFingerprint:e.configFingerprint,diagnosticWallNs:e.diagnosticWallNs,exitCode:e.exitCode,cpu:e.cpu,heap:e.heap,warnings:e.warnings,artifacts:t})}async function Yt(e,n={}){let t=we(e),s=H({intervalUs:n.intervalUs??le,origin:n.origin??"inspector"}),r=(l)=>l.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(n.origin==="jsc"){let{result:l,cpu:u,jit:p,diagnosticWallNs:d}=await be(e,n),b=Y({workload:t,phase:"cpu",configFingerprint:s,diagnosticWallNs:d,cpu:u,jit:p,warnings:r(u),artifacts:[]});return{result:l,run:b}}let{result:o,cpu:i,diagnosticWallNs:a}=await fe(e,n),c=Y({workload:t,phase:"cpu",configFingerprint:s,diagnosticWallNs:a,cpu:i,warnings:r(i),artifacts:[]});return{result:o,run:c}}function _e(e){return T("cache",e.workloadId,e.phase,e.configFingerprint,e.bunVersion,e.toolVersion,e.instrumented,e.inputsDigest??null)}async function He(e,n=process.cwd()){if(e.length===0)return;let t=new Set;for(let o of e){let i=new Bun.Glob(o);for await(let a of i.scan({cwd:n,absolute:!1}))t.add(a)}let s=[...t].sort(),r=await Promise.all(s.map(async(o)=>{let i=await Bun.file(`${n}/${o}`).arrayBuffer();return{path:o,sha256:Bun.CryptoHasher.hash("sha256",i,"hex")}}));return T("inputs",r)}function Le(e,n){return`${e}/cache/${n}.json`}async function Je(e,n){let t=Bun.file(Le(e,n));if(!await t.exists())return;return await t.json()}async function ze(e,n,t){await Bun.write(Le(e,n),`${JSON.stringify(t,null,2)}
21
- `)}var Tn={runs:null,warmup:3,outDir:".ostia",baseline:"main",cpuIntervalUs:1000,thresholds:J,workloads:[]};async function Ve(e="ostia.config.json"){let n=Bun.file(e);if(!await n.exists())return;let t=await n.json();return{...Tn,...t,thresholds:{...J,...t.thresholds??{}}}}function qe(e,n){return`${e.outDir}/baselines/${n??e.baseline}.json`}class te extends Error{path;constructor(e){super(`No baseline document at ${e}. Create one with: ostia run --export-json ${e} <command...>`);this.path=e}}async function Ke(e){let{config:n}=e,t=qe(n,e.baselineName);if(!await Bun.file(t).exists())throw new te(t);let r=await v(t),o=[],i=0,a=0,c=0;for(let b of n.workloads){let x=G(b.command,b.label),w=await He(b.inputs??[]),R=H({runs:n.runs,warmup:n.warmup}),k=_e({workloadId:x.id,phase:"timing",configFingerprint:R,bunVersion:Bun.version,toolVersion:_,instrumented:!1,inputsDigest:w}),P=e.full?void 0:await Je(n.outDir,k),h,m;if(P)h=P,m="cached",a++;else{i++;let g=await Q({argv:b.command,runs:n.runs??void 0,warmup:n.warmup});h=Z({workload:x,configFingerprint:R,trials:g.trials,timing:g.timing,warnings:g.warnings}),await ze(n.outDir,k,h),m="executed",c++}o.push({workload:x,status:m,run:h})}let l=M(o.map((b)=>b.workload),o.map((b)=>b.run)),u=0,p=0,d=0;for(let b of o){let x=ae(r,l,b.workload.id,n.thresholds);if(!x){d++;continue}if(b.comparison=x,x.verdict==="pass")u++;else p++}return l.comparisons=o.map((b)=>b.comparison).filter((b)=>b!==void 0),{document:l,summary:{total:n.workloads.length,affected:i,cached:a,executed:c,passed:u,regressed:p,missingBaseline:d,results:o}}}function Ge(e){let n=[];if(n.push(`${e.total} workloads`),n.push(`${e.affected} affected by this change`),n.push(`${e.cached} cached`),n.push(`${e.executed} executed`),e.missingBaseline>0)n.push(`${e.missingBaseline} skipped (no matching baseline workload)`);let t=e.results.filter((s)=>s.comparison?.verdict==="fail").map((s)=>{let r=s.comparison.timing,o=s.workload.label??s.workload.command?.join(" ")??s.workload.id;return r?`${r.medianDeltaPct>0?"+":""}${r.medianDeltaPct.toFixed(1)}% median on ${o}`:o});return n.push(`${e.passed} passed ${e.regressed} regressed${t.length>0?` (${t.join(", ")})`:""}`),n.push(""),n.push(`Profile CI: ${e.regressed>0?"\u2717":"\u2713"}`),`${n.join(`
22
- `)}
23
- `}async function V(e,n){if(e.text)process.stdout.write(e.text);if(!e.files||e.files.length===0)return;if(n)for(let t of e.files){let s=t.path?`${n}/${t.path}`:n;await Bun.write(s,t.content),process.stdout.write(`wrote ${s}
24
- `)}else if(e.files.length===1)process.stdout.write(e.files[0].content);else for(let t of e.files)process.stdout.write(`--- ${t.path??"(unnamed)"} ---
25
- ${t.content}
26
- `)}var $n=`ostia run [flags] <command...>
6
+ `}async function E(p,l){if(p.text)process.stdout.write(p.text);if(!p.files||p.files.length===0)return;if(l)for(let h of p.files){let x=h.path?`${l}/${h.path}`:l;await Bun.write(x,h.content),process.stdout.write(`wrote ${x}
7
+ `)}else if(p.files.length===1)process.stdout.write(p.files[0].content);else for(let h of p.files)process.stdout.write(`--- ${h.path??"(unnamed)"} ---
8
+ ${h.content}
9
+ `)}var Y=`ostia run [flags] <command...>
27
10
 
28
11
  Run one or more commands N times with warmup and report timing statistics.
29
12
 
@@ -33,7 +16,7 @@ Flags:
33
16
  --cpu capture one instrumented CPU-profile trial (subprocess --cpu-prof)
34
17
  --heap capture one instrumented heap-snapshot trial (subprocess --heap-prof)
35
18
  --cpu-interval USEC CPU sampling interval in microseconds (default: 1000)
36
- --out-dir PATH directory for captured artifacts (default: .ostia)
19
+ --out-dir PATH directory for captured artifacts (default: node_modules/.cache/ostia)
37
20
  --export-json PATH write the full ProfileDocument to PATH
38
21
  --format FORMAT table | json (default: table)
39
22
  --quiet suppress the rendered report (still writes --export-json)
@@ -47,16 +30,20 @@ Examples:
47
30
  ostia run --runs 25 --warmup 3 "bun a.ts" "bun b.ts"
48
31
  ostia run --cpu --heap "bun src/server.ts"
49
32
  ostia run --format json "bun a.ts"
50
- `,Nn=`ostia bench [flags] <suite.ts...>
33
+ `,ee=`ostia bench [flags] <suite.ts...>
51
34
 
52
35
  Run in-process benchmark suites (registered via group()/task()). Each suite file runs
53
36
  in its own spawned child process (isolated from CLI startup state).
54
37
 
55
38
  Flags:
56
- --time-budget MS time budget per task, min-samples permitting (default: 500)
57
- --min-samples N minimum samples per task (default: 20)
39
+ --time-budget MS sampling budget per task; always runs at least this long (default: 500)
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
+ clamped to 3..20, so one slow task can't blow the total.
58
43
  --gc Bun.gc(true) between trials (default: off - hides allocation cost)
59
- --out-dir PATH directory for scratch IPC files (default: .ostia)
44
+ --filter REGEX only run tasks whose "group/name" id matches this regex (substring,
45
+ case-sensitive; unmatched tasks are skipped, not timed)
46
+ --out-dir PATH directory for scratch IPC files (default: node_modules/.cache/ostia)
60
47
  --export-json PATH write the full ProfileDocument to PATH
61
48
  --format FORMAT table | json (default: table)
62
49
  --quiet suppress the rendered report (still writes --export-json)
@@ -66,12 +53,15 @@ Suite files register tasks like:
66
53
  import { group, task } from "<pkg>"
67
54
  group("parse", () => {
68
55
  task("small input", () => parse(smallBuf))
56
+ task("full pipeline", () => build(), { timeBudgetMs: 2000, minSamples: 10 })
69
57
  })
58
+ Per-task options override --time-budget / --min-samples for that task only.
70
59
 
71
60
  Examples:
72
61
  ostia bench benches/parse.ts
73
62
  ostia bench --time-budget 1000 --min-samples 50 benches/*.ts
74
- `,Ze=`ostia compare <base.json> <candidate.json>
63
+ ostia bench benches/*.ts --filter parse
64
+ `,K=`ostia compare <base.json> <candidate.json>
75
65
  ostia compare <candidate.json> --baseline <path.json>
76
66
 
77
67
  Compare two ProfileDocuments (matched by workload id) and rank timing/frame/heap deltas.
@@ -85,10 +75,10 @@ Flags:
85
75
  Examples:
86
76
  ostia compare before.json after.json
87
77
  ostia compare after.json --baseline .ostia/baselines/main.json
88
- `,In=`ostia report <document.json> [--format table|json|markdown|jsonl]
78
+ `,te=`ostia report <document.json> [--format table|json|markdown|jsonl]
89
79
 
90
80
  Render a saved ProfileDocument.
91
- `,Fn=`ostia viz <document.json> --format FORMAT [--run <id>] [--out-dir PATH]
81
+ `,re=`ostia viz <document.json> --format FORMAT [--run <id>] [--out-dir PATH]
92
82
 
93
83
  Render CPU evidence from a saved ProfileDocument as a visualization artifact. Files,
94
84
  not a GUI - hand the output to speedscope.app, flamegraph.pl, or
@@ -107,9 +97,9 @@ Flags:
107
97
  --help show this message
108
98
 
109
99
  Examples:
110
- ostia viz run.json --format speedscope --out-dir .ostia/viz
100
+ ostia viz run.json --format speedscope --out-dir node_modules/.cache/ostia/viz
111
101
  ostia viz run.json --format collapsed | flamegraph.pl > flame.svg
112
- `,Dn=`ostia ci [--full] [--baseline NAME]
102
+ `,se=`ostia ci [--full] [--baseline NAME]
113
103
 
114
104
  Load ostia.config.json, run configured workloads (reusing cached results when their
115
105
  fingerprint is unchanged), compare against the named baseline, and gate on regressions.
@@ -122,21 +112,21 @@ Flags:
122
112
  --help show this message
123
113
 
124
114
  Exit codes: 0 pass, 1 regression, 2 harness error (missing config/baseline, spawn failure).
125
- `;function vn(e){let n=[],t,s,r=!1,o=!1,i,a,c,l="table",u=!1,p=!1;for(let d=0;d<e.length;d++){let b=e[d];switch(b){case"--runs":t=Number(e[++d]);break;case"--warmup":s=Number(e[++d]);break;case"--cpu":r=!0;break;case"--heap":o=!0;break;case"--cpu-interval":i=Number(e[++d]);break;case"--out-dir":a=e[++d];break;case"--export-json":c=e[++d];break;case"--format":l=e[++d];break;case"--quiet":u=!0;break;case"--help":case"-h":p=!0;break;default:n.push(b)}}return{commands:n,runs:t,warmup:s,cpu:r,heap:o,cpuIntervalUs:i,outDir:a,exportJson:c,format:l,quiet:u,help:p}}async function Un(e){let n=vn(e);if(n.help||n.commands.length===0)return process.stdout.write($n),n.help?0:2;if(!(n.format in I))return process.stderr.write(`Unknown --format "${n.format}". Expected one of: ${Object.keys(I).join(", ")}
126
- `),2;let t;try{t=await We({commands:n.commands,runs:n.runs,warmup:n.warmup,cpu:n.cpu,heap:n.heap,cpuIntervalUs:n.cpuIntervalUs,outDir:n.outDir})}catch(r){return process.stderr.write(`Run failed: ${r instanceof Error?r.message:String(r)}
127
- `),2}if(n.exportJson)await E(t,n.exportJson);if(!n.quiet){let o=await I[n.format].render(t,{});await V(o)}return t.runs.some((r)=>r.trials.some((o)=>o.exitCode!==void 0&&o.exitCode!==0))?1:0}function Sn(e){let n=[],t,s,r=!1,o,i,a="table",c=!1,l=!1;for(let u=0;u<e.length;u++){let p=e[u];switch(p){case"--time-budget":t=Number(e[++u]);break;case"--min-samples":s=Number(e[++u]);break;case"--gc":r=!0;break;case"--out-dir":o=e[++u];break;case"--export-json":i=e[++u];break;case"--format":a=e[++u];break;case"--quiet":c=!0;break;case"--help":case"-h":l=!0;break;default:n.push(p)}}return{suites:n,timeBudgetMs:t,minSamples:s,gc:r,outDir:o,exportJson:i,format:a,quiet:c,help:l}}async function Bn(e){let n=Sn(e);if(n.help||n.suites.length===0)return process.stdout.write(Nn),n.help?0:2;if(!(n.format in I))return process.stderr.write(`Unknown --format "${n.format}". Expected one of: ${Object.keys(I).join(", ")}
128
- `),2;let t;try{t=await oe({suites:n.suites,timeBudgetMs:n.timeBudgetMs,minSamples:n.minSamples,gc:n.gc,outDir:n.outDir})}catch(s){return process.stderr.write(`Bench failed: ${s instanceof Error?s.message:String(s)}
129
- `),2}if(n.exportJson)await E(t,n.exportJson);if(!n.quiet){let r=await I[n.format].render(t,{});await V(r)}return 0}function An(e){let n=[],t,s,r="table",o=!1,i=!1;for(let a=0;a<e.length;a++){let c=e[a];switch(c){case"--baseline":t=e[++a];break;case"--export-json":s=e[++a];break;case"--format":r=e[++a];break;case"--quiet":o=!0;break;case"--help":case"-h":i=!0;break;default:n.push(c)}}return{paths:n,baseline:t,exportJson:s,format:r,quiet:o,help:i}}async function Mn(e){let n=An(e);if(n.help)return process.stdout.write(Ze),0;let t,s;if(n.baseline)t=n.baseline,s=n.paths[0];else t=n.paths[0],s=n.paths[1];if(!t||!s)return process.stdout.write(Ze),2;let r,o;try{[r,o]=await Promise.all([v(t),v(s)])}catch(l){return process.stderr.write(`Failed to load documents: ${l instanceof Error?l.message:String(l)}
130
- `),2}let i=ie(r,o),a={...o,comparisons:i};if(n.exportJson)await E(a,n.exportJson);if(!n.quiet){let u=await I[n.format].render(a,{});await V(u)}return i.some((l)=>l.verdict==="fail")?1:0}function En(e){let n,t="table",s=!1;for(let r=0;r<e.length;r++){let o=e[r];switch(o){case"--format":t=e[++r];break;case"--help":case"-h":s=!0;break;default:n=o}}return{path:n,format:t,help:s}}async function On(e){let n=En(e);if(n.help||!n.path)return process.stdout.write(In),n.help?0:2;let t;try{t=await v(n.path)}catch(o){return process.stderr.write(`Failed to load ${n.path}: ${o instanceof Error?o.message:String(o)}
131
- `),2}let r=await I[n.format].render(t,{});return await V(r),0}var jn={ascii:"table"};function Wn(e){let n,t,s,r,o=!1;for(let i=0;i<e.length;i++){let a=e[i];switch(a){case"--format":{let c=e[++i]??"";t=jn[c]??c;break}case"--run":s=e[++i];break;case"--out-dir":r=e[++i];break;case"--help":case"-h":o=!0;break;default:n=a}}return{path:n,format:t,runId:s,outDir:r,help:o}}async function _n(e){let n=Wn(e);if(n.help||!n.path||!n.format)return process.stdout.write(Fn),n.help?0:2;if(!(n.format in I))return process.stderr.write(`Unknown --format "${n.format}". Expected one of: ${Object.keys(I).join(", ")}, ascii
132
- `),2;let t;try{t=await v(n.path)}catch(o){return process.stderr.write(`Failed to load ${n.path}: ${o instanceof Error?o.message:String(o)}
133
- `),2}let r=await I[n.format].render(t,{runId:n.runId});if(!r.text&&(!r.files||r.files.length===0))return process.stderr.write(n.runId?`No CPU evidence found for run "${n.runId}".
115
+ `;function ne(p){let l=[],h,x,g=!1,k=!1,P,C,D,R="table",A=!1,F=!1;for(let j=0;j<p.length;j++){let y=p[j];switch(y){case"--runs":h=Number(p[++j]);break;case"--warmup":x=Number(p[++j]);break;case"--cpu":g=!0;break;case"--heap":k=!0;break;case"--cpu-interval":P=Number(p[++j]);break;case"--out-dir":C=p[++j];break;case"--export-json":D=p[++j];break;case"--format":R=p[++j];break;case"--quiet":A=!0;break;case"--help":case"-h":F=!0;break;default:l.push(y)}}return{commands:l,runs:h,warmup:x,cpu:g,heap:k,cpuIntervalUs:P,outDir:C,exportJson:D,format:R,quiet:A,help:F}}async function oe(p){let l=ne(p);if(l.help||l.commands.length===0)return process.stdout.write(Y),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
+ `),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 k=await n[l.format].render(h,{});await E(k)}return h.runs.some((g)=>g.trials.some((k)=>k.exitCode!==void 0&&k.exitCode!==0))?1:0}function ae(p){let l=[],h,x,g=!1,k,P,C,D="table",R=!1,A=!1;for(let F=0;F<p.length;F++){let j=p[F];switch(j){case"--time-budget":h=Number(p[++F]);break;case"--min-samples":x=Number(p[++F]);break;case"--gc":g=!0;break;case"--filter":k=p[++F];break;case"--out-dir":P=p[++F];break;case"--export-json":C=p[++F];break;case"--format":D=p[++F];break;case"--quiet":R=!0;break;case"--help":case"-h":A=!0;break;default:l.push(j)}}return{suites:l,timeBudgetMs:h,minSamples:x,gc:g,filter:k,outDir:P,exportJson:C,format:D,quiet:R,help:A}}async function ie(p){let l=ae(p);if(l.help||l.suites.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(", ")}
118
+ `),2;let h;try{h=await m({suites:l.suites,timeBudgetMs:l.timeBudgetMs,minSamples:l.minSamples,gc:l.gc,filter:l.filter,outDir:l.outDir})}catch(x){return process.stderr.write(`Bench failed: ${x instanceof Error?x.message:String(x)}
119
+ `),2}if(l.exportJson)await o(h,l.exportJson);if(!l.quiet){let g=await n[l.format].render(h,{});await E(g)}return 0}function ue(p){let l=[],h,x,g="table",k=!1,P=!1;for(let C=0;C<p.length;C++){let D=p[C];switch(D){case"--baseline":h=p[++C];break;case"--export-json":x=p[++C];break;case"--format":g=p[++C];break;case"--quiet":k=!0;break;case"--help":case"-h":P=!0;break;default:l.push(D)}}return{paths:l,baseline:h,exportJson:x,format:g,quiet:k,help:P}}async function ce(p){let l=ue(p);if(l.help)return process.stdout.write(K),0;let h,x;if(l.baseline)h=l.baseline,x=l.paths[0];else h=l.paths[0],x=l.paths[1];if(!h||!x)return process.stdout.write(K),2;let g,k;try{[g,k]=await Promise.all([t(h),t(x)])}catch(R){return process.stderr.write(`Failed to load documents: ${R instanceof Error?R.message:String(R)}
120
+ `),2}let P=d(g,k),C={...k,comparisons:P};if(l.exportJson)await o(C,l.exportJson);if(!l.quiet){let A=await n[l.format].render(C,{});await E(A)}return P.some((R)=>R.verdict==="fail")?1:0}function le(p){let l,h="table",x=!1;for(let g=0;g<p.length;g++){let k=p[g];switch(k){case"--format":h=p[++g];break;case"--help":case"-h":x=!0;break;default:l=k}}return{path:l,format:h,help:x}}async function de(p){let l=le(p);if(l.help||!l.path)return process.stdout.write(te),l.help?0:2;let h;try{h=await t(l.path)}catch(k){return process.stderr.write(`Failed to load ${l.path}: ${k instanceof Error?k.message:String(k)}
121
+ `),2}let g=await n[l.format].render(h,{});return await E(g),0}var pe={ascii:"table"};function me(p){let l,h,x,g,k=!1;for(let P=0;P<p.length;P++){let C=p[P];switch(C){case"--format":{let D=p[++P]??"";h=pe[D]??D;break}case"--run":x=p[++P];break;case"--out-dir":g=p[++P];break;case"--help":case"-h":k=!0;break;default:l=C}}return{path:l,format:h,runId:x,outDir:g,help:k}}async function fe(p){let l=me(p);if(l.help||!l.path||!l.format)return process.stdout.write(re),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
122
+ `),2;let h;try{h=await t(l.path)}catch(k){return process.stderr.write(`Failed to load ${l.path}: ${k instanceof Error?k.message:String(k)}
123
+ `),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}".
134
124
  `:`No CPU evidence found in this document (no cpu-phase runs). Capture some with "ostia run --cpu ...".
135
- `),2;return await V(r,n.outDir),0}function Hn(e){let n=!1,t,s,r=!1,o=!1;for(let i=0;i<e.length;i++)switch(e[i]){case"--full":n=!0;break;case"--baseline":t=e[++i];break;case"--export-json":s=e[++i];break;case"--quiet":r=!0;break;case"--help":case"-h":o=!0;break}return{full:n,baseline:t,exportJson:s,quiet:r,help:o}}async function Ln(e){let n=Hn(e);if(n.help)return process.stdout.write(Dn),0;let t=await Ve();if(!t)return process.stderr.write(`No ostia.config.json found. "ostia ci" needs configured workloads.
136
- `),2;if(t.workloads.length===0)return process.stderr.write(`ostia.config.json has no "workloads" configured.
137
- `),2;let s;try{s=await Ke({config:t,full:n.full,baselineName:n.baseline})}catch(r){if(r instanceof te)return process.stderr.write(`${r.message}
138
- `),2;return process.stderr.write(`CI run failed: ${r instanceof Error?r.message:String(r)}
139
- `),2}if(n.exportJson)await E(s.document,n.exportJson);if(!n.quiet)process.stdout.write(Ge(s.summary));return s.summary.regressed>0?1:0}async function Jn(){let[e,...n]=process.argv.slice(2);switch(e){case"run":return Un(n);case"bench":return Bn(n);case"compare":return Mn(n);case"report":return On(n);case"ci":return Ln(n);case"viz":return _n(n);case void 0:case"--help":case"-h":return process.stdout.write(`ostia - Bun-native profile IR engine
125
+ `),2;return await E(g,l.outDir),0}function he(p){let l=!1,h,x,g=!1,k=!1;for(let P=0;P<p.length;P++)switch(p[P]){case"--full":l=!0;break;case"--baseline":h=p[++P];break;case"--export-json":x=p[++P];break;case"--quiet":g=!0;break;case"--help":case"-h":k=!0;break}return{full:l,baseline:h,exportJson:x,quiet:g,help:k}}async function ge(p){let l=he(p);if(l.help)return process.stdout.write(se),0;let h=await M();if(!h)return process.stderr.write(`No ostia.config.json found. "ostia ci" needs configured workloads.
126
+ `),2;if(h.workloads.length===0)return process.stderr.write(`ostia.config.json has no "workloads" configured.
127
+ `),2;let x;try{x=await W({config:h,full:l.full,baselineName:l.baseline})}catch(g){if(g instanceof S)return process.stderr.write(`${g.message}
128
+ `),2;return process.stderr.write(`CI run failed: ${g instanceof Error?g.message:String(g)}
129
+ `),2}if(l.exportJson)await o(x.document,l.exportJson);if(!l.quiet)process.stdout.write(z(x.summary));return x.summary.regressed>0?1:0}async function be(){let[p,...l]=process.argv.slice(2);switch(p){case"run":return oe(l);case"bench":return ie(l);case"compare":return ce(l);case"report":return de(l);case"ci":return ge(l);case"viz":return fe(l);case void 0:case"--help":case"-h":return process.stdout.write(`ostia - Bun-native profile IR engine
140
130
 
141
131
  Commands:
142
132
  run Run commands N times and report timing/CPU/heap
@@ -147,5 +137,5 @@ Commands:
147
137
  viz Render CPU evidence as collapsed/mermaid/speedscope/cpuprofile
148
138
 
149
139
  Run "ostia <command> --help" for details.
150
- `),e===void 0?2:0;default:return process.stderr.write(`Unknown subcommand "${e}". Run "ostia --help".
151
- `),2}}if(import.meta.main)Jn().then((e)=>process.exit(e));
140
+ `),p===void 0?2:0;default:return process.stderr.write(`Unknown subcommand "${p}". Run "ostia --help".
141
+ `),2}}if(import.meta.main)be().then((p)=>process.exit(p));
package/index.d.ts CHANGED
@@ -48,6 +48,10 @@ interface Workload {
48
48
  file: string;
49
49
  task: string;
50
50
  };
51
+ /** Marks this task as the in-run Relative reference for its group (see
52
+ * `task(name, fn, { baseline: true })`). At most one per group is
53
+ * meaningful; renderers use the first they encounter. */
54
+ baseline?: boolean;
51
55
  }
52
56
 
53
57
  type Phase = "timing" | "cpu" | "heap" | "memstats";
@@ -218,15 +222,27 @@ interface BenchOptions {
218
222
  timeBudgetMs?: number;
219
223
  minSamples?: number;
220
224
  gc?: boolean;
225
+ filter?: string;
221
226
  outDir?: string;
222
227
  cwd?: string;
223
228
  }
224
229
 
225
230
  export declare function bench(opts: BenchOptions): Promise<ProfileDocument>;
226
231
 
232
+ export interface TaskOptions {
233
+ /** Marks this task as the Relative reference for its group in the table
234
+ * renderer, mirroring mitata's `baseline()`. At most one per group. */
235
+ baseline?: boolean;
236
+ /** Per-task time budget; overrides the suite-wide `--time-budget` / `timeBudgetMs`. */
237
+ timeBudgetMs?: number;
238
+ /** Per-task hard floor on trials; overrides the suite-wide `--min-samples` /
239
+ * `minSamples`. */
240
+ minSamples?: number;
241
+ }
242
+
227
243
  export declare function group(name: string, fn: () => void): void;
228
244
 
229
- export declare function task(name: string, fn: () => unknown | Promise<unknown>): void;
245
+ export declare function task(name: string, fn: () => unknown | Promise<unknown>, opts?: TaskOptions): void;
230
246
 
231
247
  interface Thresholds {
232
248
  timingPct: number;
package/index.js CHANGED
@@ -1,19 +1,2 @@
1
1
  // @bun
2
- function A(e){return JSON.stringify(W(e))}function W(e){if(Array.isArray(e))return e.map(W);if(e!==null&&typeof e==="object"){let s={};for(let n of Object.keys(e).sort())s[n]=W(e[n]);return s}return e}function C(e,...s){let n=Bun.CryptoHasher.hash("sha256",A(s),"hex");return`${e}_${n.slice(0,16)}`}function Se(e){return e.startsWith("file://")?e.slice(7):e}function _(e,s,n){let r=e.nodes,t=r.length,a=new Map,i=[],o=new Map,c=new Int32Array(t);for(let p=0;p<t;p++){let f=r[p],u=f.callFrame,w=Se(u.url),k=a.get(u.functionName);if(k===void 0)k=new Map,a.set(u.functionName,k);let N=k.get(w);if(N===void 0)N=i.length,k.set(w,N),i.push({key:C("fr",u.functionName,w),name:u.functionName,url:w||void 0,line:u.lineNumber>=0?u.lineNumber:void 0,col:u.columnNumber>=0?u.columnNumber:void 0});c[p]=N,o.set(f.id,p)}let m=Array(t);for(let p=0;p<t;p++){let f=r[p];m[p]={id:f.id,frameIx:c[o.get(f.id)],children:f.children??[]}}let l=new Float64Array(t),d=new Float64Array(t),g=e.samples,x=e.timeDeltas;for(let p=0;p<g.length;p++){let f=o.get(g[p]);if(f===void 0)continue;l[f]+=x[p]??0,d[f]+=1}let R=new Int32Array(t).fill(-1);for(let p=0;p<t;p++){let f=r[p].children;if(!f)continue;for(let u of f){let w=o.get(u);if(w!==void 0)R[w]=p}}let y=[],b=[];for(let p=t-1;p>=0;p--)if(R[p]===-1)b.push(p);while(b.length>0){let p=b.pop();y.push(p);let f=r[p].children;if(!f)continue;for(let u of f){let w=o.get(u);if(w!==void 0&&R[w]===p)b.push(w)}}let T=new Float64Array(t);for(let p=y.length-1;p>=0;p--){let f=y[p];T[f]+=l[f];let u=R[f];if(u>=0)T[u]+=T[f]}let P=Array(i.length),h=[];for(let p=0;p<t;p++){let f=m[p].frameIx,u=P[f];if(u)u.selfUs+=l[p],u.totalUs+=T[p],u.samples+=d[p];else{let w={frameIx:f,selfUs:l[p],totalUs:T[p],samples:d[p]};P[f]=w,h.push(w)}}return{origin:s,samplingIntervalUs:n,frames:i,nodes:m,totals:h.sort((p,f)=>f.selfUs-p.selfUs),samples:{nodeIds:e.samples,timeDeltasUs:e.timeDeltas}}}function Me(e,s,n,r){let t=["--cpu-prof","--cpu-prof-dir",s,"--cpu-prof-name",n,"--cpu-prof-interval",String(r)],a=e[0];if(a==="bun"||a?.endsWith("/bun"))return[a,...t,...e.slice(1)];return e}async function ee(e){let s=`${e.artifactDir}/${e.fileName}`,n=e.argv[0],r=n==="bun"||n?.endsWith("/bun"),t=Me(e.argv,e.artifactDir,e.fileName,e.intervalUs),a=r?e.env:{...process.env,...e.env,BUN_OPTIONS:`--cpu-prof --cpu-prof-dir ${e.artifactDir} --cpu-prof-name ${e.fileName} --cpu-prof-interval ${e.intervalUs}`},i=Bun.nanoseconds(),c=await Bun.spawn(t,{cwd:e.cwd,env:a,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,m=Bun.nanoseconds()-i,l=Bun.file(s);if(!await l.exists())return{diagnosticWallNs:m,exitCode:c,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${s} after exit ${c}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:s,argv:e.argv}}]};let d=await l.json(),g=_(d,"cpu-prof",e.intervalUs),x=d.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:m,exitCode:c,artifactPath:s,cpu:g,warnings:x}}function ne(e,s="heap-prof"){let{node_fields:n,node_types:r}=e.snapshot.meta,t=n.indexOf("type"),a=n.indexOf("self_size"),i=n.length,o=r[0];if(t===-1||a===-1||!Array.isArray(o))return{origin:s,typeCounts:[],objectCount:e.snapshot.node_count};let c=o.length,m=Array(c),l=new Map,d=[],g=0,x=e.nodes,R=x.length;for(let h=0;h<R;h+=i){let p=x[h+t],f=x[h+a]??0;g+=f;let u;if(p>=0&&p<c){if(u=m[p],u===void 0)u={type:o[p],count:0,bytes:0},m[p]=u,d.push(u)}else{let w=`unknown(${p})`;if(u=l.get(w),u===void 0)u={type:w,count:0,bytes:0},l.set(w,u),d.push(u)}u.count++,u.bytes+=f}let y=d.sort((h,p)=>p.count-h.count),b=y.slice(0,20),T=y.slice(20),P=b.map(({type:h,count:p,bytes:f})=>({type:h,count:p,retainedBytes:f}));if(T.length>0){let h=0,p=0;for(let f of T)h+=f.count,p+=f.bytes;P.push({type:"other",count:h,retainedBytes:p})}return{origin:s,heapSizeBytes:g,objectCount:e.snapshot.node_count,typeCounts:P}}function Be(e,s,n){let r=["--heap-prof","--heap-prof-dir",s,"--heap-prof-name",n],t=e[0];if(t==="bun"||t?.endsWith("/bun"))return[t,...r,...e.slice(1)];return e}async function te(e){let s=`${e.artifactDir}/${e.fileName}`,n=e.argv[0],r=n==="bun"||n?.endsWith("/bun"),t=Be(e.argv,e.artifactDir,e.fileName),a=r?e.env:{...process.env,...e.env,BUN_OPTIONS:`--heap-prof --heap-prof-dir ${e.artifactDir} --heap-prof-name ${e.fileName}`},i=Bun.nanoseconds(),c=await Bun.spawn(t,{cwd:e.cwd,env:a,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,m=Bun.nanoseconds()-i,l=Bun.file(s);if(!await l.exists())return{diagnosticWallNs:m,exitCode:c,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${s} after exit ${c}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:s,argv:e.argv}}]};let d=await l.json(),g=ne(d,"heap-prof");return{diagnosticWallNs:m,exitCode:c,artifactPath:s,heap:g,warnings:[]}}import{Session as We}from"inspector/promises";var Oe=1000;async function re(e,s={}){let n=s.intervalUs??Oe,r=new We;r.connect();let t=Bun.nanoseconds();try{await r.post("Profiler.enable"),await r.post("Profiler.setSamplingInterval",{interval:n}),await r.post("Profiler.start");let a=await e(),{profile:i}=await r.post("Profiler.stop"),o=Bun.nanoseconds()-t,c=_(i,"inspector",n);return{result:a,cpu:c,diagnosticWallNs:o}}finally{r.disconnect()}}import{profile as Ae}from"bun:jsc";var Ee=new Map([["LLInt","llint"],["Baseline","baseline"],["DFG","dfg"],["FTL","ftl"]]),se=4294967295;function oe(e,s){let n=s??e.interval*1e6,r=new Map,t=[];function a(u,w,k,N){let I=r.get(u);if(I===void 0)I=new Map,r.set(u,I);let v=w??"",U=I.get(v);if(U===void 0)U=t.length,I.set(v,U),t.push({key:C("fr",u,v),name:u,url:w,line:k,col:N});return U}function i(u){let w=u.line===se,k=w?void 0:u.line-1,N=w||u.column===se?void 0:u.column-1;return a(u.name,u.sourceURL,k,N)}let o=a("(root)",void 0,void 0,void 0),c=1,m={id:0,frameIx:o,children:new Map,selfUs:0,samples:0,totalUs:0},l=new Map([[0,m]]),d={llint:0,baseline:0,dfg:0,ftl:0},g=new Map,x=[],R=[];for(let u of e.traces){let w=u.frames,k=m;for(let v=w.length-1;v>=0;v--){let U=i(w[v]),S=k.children.get(U);if(!S)S={id:c++,frameIx:U,children:new Map,selfUs:0,samples:0,totalUs:0},k.children.set(U,S),l.set(S.id,S);k=S}k.selfUs+=n,k.samples+=1,x.push(k.id),R.push(n);let N=w[0],I=N&&Ee.get(N.category);if(I){d[I]++;let v=g.get(I)??new Map;v.set(k.frameIx,(v.get(k.frameIx)??0)+1),g.set(I,v)}}function y(u){let w=u.selfUs;for(let k of u.children.values())w+=y(k);return u.totalUs=w,w}y(m);let b=new Map;function T(u){let w=b.get(u.frameIx);if(w)w.selfUs+=u.selfUs,w.totalUs+=u.totalUs,w.samples+=u.samples;else b.set(u.frameIx,{frameIx:u.frameIx,selfUs:u.selfUs,totalUs:u.totalUs,samples:u.samples});for(let k of u.children.values())T(k)}T(m);let P=[...l.values()].map((u)=>({id:u.id,frameIx:u.frameIx,children:[...u.children.values()].map((w)=>w.id)})),h={origin:"jsc-profile",samplingIntervalUs:n,frames:t,nodes:P,totals:[...b.values()].sort((u,w)=>w.selfUs-u.selfUs),samples:{nodeIds:x,timeDeltasUs:R}},p=[...g.entries()].flatMap(([u,w])=>[...w.entries()].sort((k,N)=>N[1]-k[1]).slice(0,3).map(([k,N])=>({tier:u,frameKey:t[k].key,samples:N})));return{cpu:h,jit:{origin:"jsc-profile",tiers:d,topFramesByTier:p}}}var _e=1000;async function ie(e,s={}){let n=s.intervalUs??_e,r,t=Bun.nanoseconds(),a=await Ae(async()=>(r=await e(),r),n),i=Bun.nanoseconds()-t,{cpu:o,jit:c}=oe(a.stackTraces,n);return{result:r,cpu:o,jit:c,diagnosticWallNs:i}}var V="0.1.0";function j(e,s){return{schemaVersion:1,toolVersion:V,bunVersion:Bun.version,platform:{os:process.platform,arch:process.arch},createdAt:new Date().toISOString(),workloads:e,runs:s}}function ae(e,s){return{id:C("wl","subprocess",e,process.cwd()),kind:"subprocess",command:e,label:s}}function ce(e,s){return{id:C("wl","inprocess",e.name,e.toString()),kind:"inprocess",label:s}}function ue(e){return{id:C("run",e.workload.id,"timing",e.configFingerprint,Bun.version,V),workloadId:e.workload.id,phase:"timing",instrumented:!1,configFingerprint:e.configFingerprint,trials:e.trials,timing:e.timing,warnings:e.warnings,artifacts:[],memory:je(e.trials)}}function je(e){let s=e.map((n)=>n.maxRssBytes).filter((n)=>n!==void 0);if(s.length===0)return;return{origin:"resourceUsage",perTrial:e.map((n)=>({rssBytes:n.maxRssBytes})),maxRssBytes:Math.max(...s)}}function L(e){return{id:C("run",e.workload.id,e.phase,e.configFingerprint,Bun.version,V),workloadId:e.workload.id,phase:e.phase,instrumented:!0,configFingerprint:e.configFingerprint,trials:[{i:0,wallNs:e.diagnosticWallNs,exitCode:e.exitCode}],diagnosticWallNs:e.diagnosticWallNs,cpu:e.cpu,heap:e.heap,jit:e.jit,warnings:e.warnings,artifacts:e.artifacts}}async function pe(e,s,n){let t=await Bun.file(n).arrayBuffer(),a=new Bun.CryptoHasher("sha256");return a.update(t),{id:C("art",e,s,n),kind:s,path:n,sha256:a.digest("hex"),bytes:t.byteLength}}function K(e){return C("cfg",e)}function q(e){return`${JSON.stringify(W(e),null,2)}
3
- `}async function Le(e,s){await Bun.write(s,q(e))}async function G(e){let s=await Bun.file(e).text();return JSON.parse(s)}async function Y(e){let s=Bun.nanoseconds(),n=Bun.spawn(e.argv,{cwd:e.cwd,env:e.env,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),r=await n.exited,t=Bun.nanoseconds(),a=n.resourceUsage?.();return{wallNs:t-s,exitCode:r,userNs:a?Number(a.cpuTime.user)*1000:void 0,systemNs:a?Number(a.cpuTime.system)*1000:void 0,maxRssBytes:a?.maxRSS}}function le(e){return e.trim().split(/\s+/).filter(Boolean)}function me(e){if(e.length===0)throw Error("computeTimingStats: samples must be non-empty");let s=e.length,n=de(e),r=0;for(let h=0;h<s;h++)r+=e[h];let t=r/s,a=O(n,0.5),i=0;for(let h=0;h<s;h++){let p=e[h]-t;i+=p*p}let o=Math.sqrt(i/s),c=n[0],m=n[s-1],l=O(n,0.25),d=O(n,0.75),g=d-l,x=l-1.5*g,R=d+1.5*g,y=l-3*g,b=d+3*g,T=0,P=0;for(let h=0;h<s;h++){let p=e[h];if(p<y||p>b)P++;else if(p<x||p>R)T++}return{unit:"ns",samples:e,mean:t,median:a,stddev:o,min:c,max:m,outliers:{mild:T,severe:P}}}function de(e){let s=new Float64Array(e.length);return s.set(e),s.sort(),s}function O(e,s){let n=e.length;if(n===1)return e[0];let r=s*(n-1),t=Math.floor(r),a=Math.ceil(r);if(t===a)return e[t];let i=r-t;return e[t]*(1-i)+e[a]*i}var He=5000000,Je=200;function fe(e,s,n="subprocess"){let r=[],t=e.samples[0];if(t!==void 0){let i=de(e.samples),o=O(i,0.25),m=O(i,0.75)-o;if(t>e.median+3*m&&m>0)r.push({code:"slow-first-run",message:`First run took ${(t/1e6).toFixed(2)}ms, much slower than the median ${(e.median/1e6).toFixed(2)}ms. Consider more warmup.`,data:{firstNs:t,medianNs:e.median}})}if(e.outliers.mild+e.outliers.severe>0)r.push({code:"outliers-detected",message:`${e.outliers.mild+e.outliers.severe} outlier(s) detected (${e.outliers.severe} severe, ${e.outliers.mild} mild).`,data:e.outliers});if(n==="subprocess"&&e.median<He)r.push({code:"fast-command",message:`Median run time (${(e.median/1e6).toFixed(3)}ms) is very fast; results may be dominated by spawn overhead.`,data:{medianNs:e.median}});if(n==="inprocess"&&e.median<Je)r.push({code:"below-timer-resolution",message:`Median run time (${e.median.toFixed(0)}ns) is close to timer resolution; consider a larger batch size or a coarser operation.`,data:{medianNs:e.median}});let a=s.filter((i)=>i!==void 0&&i!==0);if(a.length>0)r.push({code:"nonzero-exit",message:`${a.length} of ${s.length} trial(s) exited non-zero.`,data:{exitCodes:a}});return r}var ze=10,Ve=3000000000,Ke=3;async function ge(e){let s=e.warmup??Ke;for(let l=0;l<s;l++)await Y(e);let n=[],r=e.runs??e.minRuns??ze,t=e.runs!==void 0?0:e.minTotalNs??Ve,a=0,i=0;while(i<r||a<t){let l=await Y(e);if(n.push({i,wallNs:l.wallNs,exitCode:l.exitCode,userNs:l.userNs,systemNs:l.systemNs,maxRssBytes:l.maxRssBytes}),a+=l.wallNs,i++,e.runs!==void 0&&i>=e.runs)break}let o=n.map((l)=>l.wallNs),c=me(o),m=fe(c,n.map((l)=>l.exitCode));return{trials:n,timing:c,warnings:m}}var qe=new URL("./runner.ts",import.meta.url).pathname,Ge=".ostia";async function Ye(e){let n=`${e.outDir??Ge}/bench-tmp`,r=e.cwd??process.cwd(),t={timeBudgetMs:e.timeBudgetMs,minSamples:e.minSamples,gc:e.gc},a=[],i=[];try{for(let o of e.suites){let c=o.startsWith("/")?o:`${r}/${o}`,m=`${n}/${C("bench-out",c)}.json`,d=await Bun.spawn(["bun",qe,c,m,JSON.stringify(t)],{cwd:r,stdout:"inherit",stderr:"inherit",stdin:"ignore"}).exited;if(d!==0)throw Error(`Bench suite failed: ${o} (runner exited ${d})`);let g=await G(m);a.push(...g.workloads),i.push(...g.runs)}}finally{await Bun.spawn(["rm","-rf",n]).exited}return j(a,i)}var Ze=[],H;function Qe(e,s){let n=H;H=e;try{s()}finally{H=n}}function Xe(e,s){Ze.push({groupName:H,name:e,fn:s})}var he={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000};function J(e,s){if(e===0)return s===0?0:1/0;return(s-e)/e*100}function M(e,s,n){return e.runs.find((r)=>r.workloadId===s&&r.phase===n)}function en(e,s,n=he){let r=new Set(s.workloads.map((a)=>a.id)),t=[];for(let a of e.workloads){if(!r.has(a.id))continue;let i=nn(e,s,a.id,n);if(i)t.push(i)}return t}function nn(e,s,n,r=he){let t=M(e,n,"timing"),a=M(s,n,"timing"),i=M(e,n,"cpu"),o=M(s,n,"cpu"),c=M(e,n,"heap"),m=M(s,n,"heap"),l=t?.id??i?.id??c?.id,d=a?.id??o?.id??m?.id;if(!l||!d)return;let g=!1,x;if(t?.timing&&a?.timing){let b=J(t.timing.median,a.timing.median),T=J(t.timing.mean,a.timing.mean),P=b>r.timingPct?"regressed":b<-r.timingPct?"improved":"unchanged";if(P==="regressed")g=!0;x={medianDeltaPct:b,meanDeltaPct:T,verdict:P}}let R;if(i?.cpu&&o?.cpu){let b=new Map(i.cpu.totals.map((f)=>[i.cpu.frames[f.frameIx].key,f])),T=new Map(o.cpu.totals.map((f)=>[o.cpu.frames[f.frameIx].key,f])),P=new Map(i.cpu.frames.map((f)=>[f.key,f.name])),h=new Map(o.cpu.frames.map((f)=>[f.key,f.name]));R=[...new Set([...b.keys(),...T.keys()])].map((f)=>{let u=b.get(f)?.selfUs??0,w=T.get(f)?.selfUs??0;return{frameKey:f,name:h.get(f)??P.get(f)??f,baseSelfUs:u,candSelfUs:w,deltaPct:J(u,w)}}).sort((f,u)=>Math.abs(u.deltaPct)-Math.abs(f.deltaPct));for(let f of R)if((f.baseSelfUs>=r.minFrameSelfUs||f.candSelfUs>=r.minFrameSelfUs)&&f.deltaPct>r.frameSelfPct)g=!0}let y;if(c?.heap&&m?.heap){let b=new Map(c.heap.typeCounts.map((h)=>[h.type,h])),T=new Map(m.heap.typeCounts.map((h)=>[h.type,h]));y=[...new Set([...b.keys(),...T.keys()])].map((h)=>{let p=b.get(h),f=T.get(h);return{type:h,baseCount:p?.count??0,candCount:f?.count??0,baseBytes:p?.retainedBytes,candBytes:f?.retainedBytes,deltaPct:J(p?.count??0,f?.count??0)}}).sort((h,p)=>Math.abs(p.deltaPct)-Math.abs(h.deltaPct));for(let h of y)if(h.deltaPct>r.heapTypePct)g=!0}return{id:C("cmp",l,d),baselineRunId:l,candidateRunId:d,timing:x,frames:R,heapTypes:y,thresholds:r,verdict:g?"fail":"pass"}}function F(e,s){if(s){let n=e.runs.find((r)=>r.id===s);return n?.cpu?[n]:[]}return e.runs.filter((n)=>n.phase==="cpu"&&n.cpu)}function B(e){let s=e.nodes,n=s.length,r=tn(e),t=new Int32Array(n).fill(-1);for(let c=0;c<n;c++)for(let m of s[c].children){let l=r(m);if(l!==-1)t[l]=c}let a=[];for(let c=0;c<n;c++)if(t[c]===-1)a.push(c);let i=[],o=[];for(let c=a.length-1;c>=0;c--)o.push(a[c]);while(o.length>0){let c=o.pop();i.push(c);for(let m of s[c].children){let l=r(m);if(l!==-1&&t[l]===c)o.push(l)}}return{count:n,indexOf:r,parentIx:t,roots:a,order:i}}function tn(e){let s=e.nodes,n=s.length,r=1/0,t=-1/0,a=!0;for(let o=0;o<n;o++){let c=s[o].id;if(!Number.isInteger(c)){a=!1;break}if(c<r)r=c;if(c>t)t=c}if(a&&n>0&&t-r<n*4+64){let o=t-r+1,c=new Int32Array(o).fill(-1);for(let m=0;m<n;m++)c[s[m].id-r]=m;return(m)=>{let l=m-r;return l>=0&&l<o?c[l]:-1}}let i=new Map;for(let o=0;o<n;o++)i.set(s[o].id,o);return(o)=>i.get(o)??-1}function ye(e,s){let{count:n,indexOf:r,parentIx:t,order:a}=s,i=new Float64Array(n),o=new Float64Array(n),c=e.samples?.nodeIds??[],m=e.samples?.timeDeltasUs??[];for(let d=0;d<c.length;d++){let g=r(c[d]);if(g===-1)continue;i[g]+=m[d]??0,o[g]+=1}let l=new Float64Array(n);for(let d=a.length-1;d>=0;d--){let g=a[d];l[g]+=i[g];let x=t[g];if(x>=0)l[x]+=l[g]}return{selfUs:i,totalUs:l,samples:o}}var we={name:"collapsed",async render(e,s={}){return{files:F(e,s.runId).map((t)=>{let a=t.cpu,{nodes:i,frames:o}=a,c=B(a),m=Array(c.count);for(let R of c.order){let y=o[i[R].frameIx].name||"(anonymous)",b=c.parentIx[R];m[R]=b===-1?y:`${m[b]};${y}`}let l=new Float64Array(c.count),d=[],g=a.samples?.nodeIds??[];for(let R=0;R<g.length;R++){let y=c.indexOf(g[R]);if(y===-1)continue;if(l[y]++===0)d.push(y)}let x=Array(d.length);for(let R=0;R<d.length;R++){let y=d[R];x[R]=`${m[y]} ${l[y]}`}return{path:`${t.id}.collapsed.txt`,content:x.join(`
4
- `)+(x.length>0?`
5
- `:"")}})}}};var be={name:"cpuprofile",async render(e,s={}){let n=F(e,s.runId),r=[],t=[];for(let a of n){if(a.cpu?.origin!=="cpu-prof"&&a.cpu?.origin!=="inspector"){t.push(`${a.id} (origin ${a.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let i=a.artifacts.find((c)=>c.kind==="cpuprofile");if(!i){t.push(`${a.id} (no cpuprofile artifact recorded on this run)`);continue}let o=Bun.file(i.path);if(!await o.exists()){t.push(`${a.id} (artifact missing on disk: ${i.path})`);continue}r.push({path:`${a.id}.cpuprofile`,content:await o.text()})}if(r.length===0&&t.length>0)return{text:`No .cpuprofile artifacts available:
6
- ${t.map((a)=>` - ${a}`).join(`
7
- `)}
8
- `};return{files:r}}};var xe={name:"json",async render(e){return{text:q(e)}}};var Re={name:"jsonl",async render(e){let{runs:s,...n}=e;return{text:`${[A(n),...s.map((t)=>A(t))].join(`
9
- `)}
10
- `}}};function D(e){return(e/1e6).toFixed(3)}function z(e){return e?.label??e?.command?.join(" ")??e?.entry?.task??e?.id??"unknown"}var Te=10,Pe=10,ke={name:"markdown",async render(e){let s=new Map(e.workloads.map((t)=>[t.id,t])),n=[];n.push("# Profile Report",""),n.push(`Bun ${e.bunVersion} \xB7 ostia ${e.toolVersion} \xB7 ${e.platform.os}/${e.platform.arch} \xB7 ${e.createdAt}`,"");let r=e.runs.filter((t)=>t.phase==="timing"&&t.timing!==void 0);if(r.length>0){n.push("## Timing",""),n.push("| Command | Mean \xB1 SD (ms) | Min\u2026Max (ms) | Median (ms) |","|---|---|---|---|");for(let a of r){let i=z(s.get(a.workloadId)),o=a.timing;n.push(`| ${i} | ${D(o.mean)} \xB1 ${D(o.stddev)} | ${D(o.min)}\u2026${D(o.max)} | ${D(o.median)} |`)}n.push("");let t=r.filter((a)=>a.warnings.length>0);if(t.length>0){n.push("### Warnings","");for(let a of t){let i=z(s.get(a.workloadId));for(let o of a.warnings)n.push(`- **${i}**: ${o.message} (\`${o.code}\`)`)}n.push("")}}for(let t of e.runs){if(t.phase!=="cpu"&&t.phase!=="heap")continue;let a=z(s.get(t.workloadId));if(t.phase==="cpu"){if(n.push(`## CPU capture - ${a}`,""),n.push(`instrumented, diagnostic wall ${D(t.diagnosticWallNs??0)}ms`,""),t.cpu){n.push(`origin: \`${t.cpu.origin}\`, interval: ${t.cpu.samplingIntervalUs}\xB5s`,""),n.push("| Self % | Self (ms) | Total (ms) | Frame |","|---|---|---|---|");let i=t.cpu.totals.reduce((o,c)=>o+c.selfUs,0)||1;for(let o of t.cpu.totals.slice(0,Te)){let c=t.cpu.frames[o.frameIx],m=(o.selfUs/i*100).toFixed(1);n.push(`| ${m}% | ${(o.selfUs/1000).toFixed(2)} | ${(o.totalUs/1000).toFixed(2)} | ${c?.name||"(anonymous)"} |`)}if(n.push(""),t.jit){let o=t.jit.tiers;n.push(`JIT tiers: LLInt ${o.llint} \xB7 Baseline ${o.baseline} \xB7 DFG ${o.dfg} \xB7 FTL ${o.ftl}`,"")}}}else if(n.push(`## Heap snapshot - ${a}`,""),n.push(`instrumented, diagnostic wall ${D(t.diagnosticWallNs??0)}ms`,""),t.heap){n.push(`${t.heap.objectCount??"?"} objects, ${((t.heap.heapSizeBytes??0)/1e6).toFixed(2)}MB`,""),n.push("| Count | Type |","|---|---|");for(let i of t.heap.typeCounts.slice(0,Pe))n.push(`| ${i.count} | ${i.type} |`);n.push("")}for(let i of t.artifacts)n.push(`- artifact: \`${i.path}\``);for(let i of t.warnings)n.push(`- ! ${i.message} (\`${i.code}\`)`);if(t.artifacts.length>0||t.warnings.length>0)n.push("")}if(e.comparisons&&e.comparisons.length>0){n.push("## Comparisons","");for(let t of e.comparisons){let a=e.runs.find((o)=>o.id===t.candidateRunId),i=z(a?s.get(a.workloadId):void 0);if(n.push(`### ${t.verdict==="pass"?"\u2713":"\u2717"} ${i}`,""),t.timing){let o=t.timing.medianDeltaPct>0?"+":"";n.push(`- timing: ${o}${t.timing.medianDeltaPct.toFixed(1)}% median (**${t.timing.verdict}**)`)}for(let o of t.frames?.slice(0,Te)??[]){if(Math.abs(o.deltaPct)<0.5)continue;let c=o.deltaPct>0?"+":"";n.push(`- frame \`${o.name}\`: ${c}${o.deltaPct.toFixed(1)}% self-time (${(o.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(o.candSelfUs/1000).toFixed(2)}ms)`)}for(let o of t.heapTypes?.slice(0,Pe)??[]){if(Math.abs(o.deltaPct)<0.5)continue;let c=o.deltaPct>0?"+":"";n.push(`- heap \`${o.type}\`: ${c}${o.deltaPct.toFixed(1)}% count (${o.baseCount} \u2192 ${o.candCount})`)}n.push("")}}return{text:n.join(`
11
- `)}}};var rn=15;function Z(e){return`n${e}`}function sn(e,s,n){return`${(e||"(anonymous)").replace(/"/g,"'")} (self ${(s/1000).toFixed(2)}ms, total ${(n/1000).toFixed(2)}ms)`}function on(e,s,n,r){let t=[];if(r<=0)return t;for(let a=0;a<s;a++){if(a===n)continue;let i=e[a];if(t.length===r&&i<=e[t[r-1]])continue;let o=t.length;while(o>0&&e[t[o-1]]<i)o--;if(t.splice(o,0,a),t.length>r)t.pop()}return t}var $e={name:"mermaid",async render(e,s={}){let n=s.topN??rn;return{files:F(e,s.runId).map((a)=>{let i=a.cpu,{nodes:o,frames:c}=i,m=B(i),{selfUs:l,totalUs:d}=ye(i,m),{parentIx:g}=m,x=m.roots[0]??-1,R=on(l,m.count,x,n),y=new Set(x!==-1?[x]:[]),b=[];for(let P of R){b.length=0;for(let h=P;h!==-1;h=g[h])b.push(h);for(let h=b.length-1;h>=0;h--)y.add(b[h])}let T=["graph TD"];for(let P of y){let h=o[P].id;T.push(` ${Z(h)}["${sn(c[o[P].frameIx].name,l[P],d[P])}"]`)}for(let P of y){let h=g[P];if(h!==-1&&y.has(h))T.push(` ${Z(o[h].id)} --> ${Z(o[P].id)}`)}return{path:`${a.id}.mermaid.md`,content:`${T.join(`
12
- `)}
13
- `}})}}};var an="https://www.speedscope.app/file-format-schema.json";function Ne(e){return e?.label??e?.command?.join(" ")??e?.entry?.task??"profile"}var Ce={name:"speedscope",async render(e,s={}){let n=F(e,s.runId),r=new Map(e.workloads.map((a)=>[a.id,a]));return{files:n.map((a)=>{let i=a.cpu,{nodes:o}=i,c=B(i),m=i.samples?.nodeIds??[],l=i.samples?.timeDeltasUs??[],d=Array(c.count);for(let y of c.order){let b=c.parentIx[y],T=o[y].frameIx;d[y]=b===-1?[T]:[...d[b],T]}let g=Array(m.length);for(let y=0;y<m.length;y++){let b=c.indexOf(m[y]);g[y]=b===-1?[]:d[b]}let x=0;for(let y=0;y<l.length;y++)x+=l[y];let R={$schema:an,exporter:"ostia",name:Ne(r.get(a.workloadId)),activeProfileIndex:0,shared:{frames:i.frames.map((y)=>({name:y.name||"(anonymous)",file:y.url,line:y.line!==void 0?y.line+1:void 0}))},profiles:[{type:"sampled",name:Ne(r.get(a.workloadId)),unit:"microseconds",startValue:0,endValue:x,samples:g,weights:l}]};return{path:`${a.id}.speedscope.json`,content:`${JSON.stringify(R,null,2)}
14
- `}})}}};function E(e){return(e/1e6).toFixed(3)}function Q(e){return e.label??e.command?.join(" ")??e.entry?.task??e.id}var Ie={name:"table",async render(e){let s=e.runs.filter((d)=>d.phase==="timing"&&d.timing!==void 0),n=new Map(e.workloads.map((d)=>[d.id,d]));if(s.length===0){let d=ve(e,n);return{text:d.length>0?`${d.join(`
15
- `)}
16
- `:`(no timing runs)
17
- `}}let r=s.map((d)=>{let g=n.get(d.workloadId);return{run:d,workload:g,label:g?Q(g):d.workloadId}}),t=Math.min(...r.map((d)=>d.run.timing.median)),a=r.length>1,i=[],o=Math.max(7,...r.map((d)=>d.label.length)),c=a?`${"Command".padEnd(o)} Mean [ms] Min\u2026Max [ms] Relative`:`${"Command".padEnd(o)} Mean [ms] Min\u2026Max [ms]`;i.push(c),i.push("-".repeat(c.length));for(let{run:d,label:g}of r){let x=d.timing,R=`${E(x.mean)} \xB1 ${E(x.stddev)}`,y=`${E(x.min)}\u2026${E(x.max)}`,b=`${g.padEnd(o)} ${R.padEnd(15)} ${y.padEnd(18)}`;if(a){let T=x.median/t;b+=T===1?" 1.00\xD7":` ${T.toFixed(2)}\xD7 slower`}i.push(b);for(let T of d.warnings)i.push(` ! ${T.message}`)}let m=un(e,n);if(m.length>0)i.push(""),i.push(...m);let l=ve(e,n);if(l.length>0)i.push(""),i.push(...l);return{text:`${i.join(`
18
- `)}
19
- `}}};function cn(e,s,n){let r=e.runs.find((a)=>a.id===n),t=r?s.get(r.workloadId):void 0;return t?Q(t):n}function ve(e,s){if(!e.comparisons||e.comparisons.length===0)return[];let n=[];for(let r of e.comparisons){let t=cn(e,s,r.candidateRunId),a=r.verdict==="pass"?"\u2713":"\u2717";if(n.push(`${a} ${t}`),r.timing){let i=r.timing.medianDeltaPct>0?"+":"";n.push(` timing: ${i}${r.timing.medianDeltaPct.toFixed(1)}% median (${r.timing.verdict})`)}if(r.frames)for(let i of r.frames.slice(0,Ue)){if(Math.abs(i.deltaPct)<0.5)continue;let o=i.deltaPct>0?"+":"";n.push(` frame ${i.name}: ${o}${i.deltaPct.toFixed(1)}% self-time (${(i.baseSelfUs/1000).toFixed(2)}ms -> ${(i.candSelfUs/1000).toFixed(2)}ms)`)}if(r.heapTypes)for(let i of r.heapTypes.slice(0,Fe)){if(Math.abs(i.deltaPct)<0.5)continue;let o=i.deltaPct>0?"+":"";n.push(` heap ${i.type}: ${o}${i.deltaPct.toFixed(1)}% count (${i.baseCount} -> ${i.candCount})`)}}return n}var Ue=5,Fe=5;function un(e,s){let n=[];for(let r of e.runs){if(r.phase!=="cpu"&&r.phase!=="heap")continue;let t=s.get(r.workloadId),a=t?Q(t):r.workloadId;if(r.phase==="cpu")if(r.cpu){n.push(`CPU capture - ${a} (instrumented, ${r.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${E(r.diagnosticWallNs??0)}ms)`);let i=r.cpu.totals.reduce((o,c)=>o+c.selfUs,0)||1;for(let o of r.cpu.totals.slice(0,Ue)){let c=r.cpu.frames[o.frameIx],m=(o.selfUs/i*100).toFixed(1);n.push(` ${m.padStart(5)}% ${(o.selfUs/1000).toFixed(2).padStart(8)}ms self ${c?.name??"?"}`)}}else n.push(`CPU capture - ${a} (instrumented, no evidence captured)`);else if(r.heap){let i=((r.heap.heapSizeBytes??0)/1e6).toFixed(2);n.push(`Heap snapshot - ${a} (instrumented, ${r.heap.objectCount??"?"} objects, ${i}MB)`);for(let o of r.heap.typeCounts.slice(0,Fe))n.push(` ${String(o.count).padStart(6)} ${o.type}`)}else n.push(`Heap snapshot - ${a} (instrumented, no evidence captured)`);for(let i of r.artifacts)n.push(` artifact: ${i.path}`);for(let i of r.warnings)n.push(` ! ${i.message}`)}return n}var pn={table:Ie,json:xe,markdown:ke,jsonl:Re,collapsed:we,mermaid:$e,speedscope:Ce,cpuprofile:be};var ln=".ostia",X=1000;async function wt(e){let s=K({runs:e.runs??null,warmup:e.warmup??null,cpu:e.cpu??!1,heap:e.heap??!1,cpuIntervalUs:e.cpuIntervalUs??X}),r=`${e.outDir??ln}/artifacts`,t=[],a=[];for(let i of e.commands){let o=Array.isArray(i)?i:le(i),c=ae(o,Array.isArray(i)?void 0:i);t.push(c);let m=await ge({argv:o,cwd:e.cwd,env:e.env,runs:e.runs,warmup:e.warmup}),l=ue({workload:c,configFingerprint:s,trials:m.trials,timing:m.timing,warnings:m.warnings});if(a.push(l),e.cpu){let d=`${l.id}-cpu.cpuprofile`,g=await ee({argv:o,cwd:e.cwd,env:e.env,artifactDir:r,fileName:d,intervalUs:e.cpuIntervalUs??X});a.push(await De({workload:c,phase:"cpu",configFingerprint:s,diagnosticWallNs:g.diagnosticWallNs,exitCode:g.exitCode,cpu:g.cpu,artifactPath:g.artifactPath,artifactKind:"cpuprofile",warnings:g.warnings}))}if(e.heap){let d=`${l.id}-heap.heapsnapshot`,g=await te({argv:o,cwd:e.cwd,env:e.env,artifactDir:r,fileName:d});a.push(await De({workload:c,phase:"heap",configFingerprint:s,diagnosticWallNs:g.diagnosticWallNs,exitCode:g.exitCode,heap:g.heap,artifactPath:g.artifactPath,artifactKind:"heapsnapshot",warnings:g.warnings}))}}return j(t,a)}async function De(e){let s=`${e.workload.id}-${e.phase}-${e.configFingerprint}`,n=e.artifactPath?[await pe(s,e.artifactKind,e.artifactPath)]:[];return L({workload:e.workload,phase:e.phase,configFingerprint:e.configFingerprint,diagnosticWallNs:e.diagnosticWallNs,exitCode:e.exitCode,cpu:e.cpu,heap:e.heap,warnings:e.warnings,artifacts:n})}async function bt(e,s={}){let n=ce(e),r=K({intervalUs:s.intervalUs??X,origin:s.origin??"inspector"}),t=(m)=>m.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(s.origin==="jsc"){let{result:m,cpu:l,jit:d,diagnosticWallNs:g}=await ie(e,s),x=L({workload:n,phase:"cpu",configFingerprint:r,diagnosticWallNs:g,cpu:l,jit:d,warnings:t(l),artifacts:[]});return{result:m,run:x}}let{result:a,cpu:i,diagnosticWallNs:o}=await re(e,s),c=L({workload:n,phase:"cpu",configFingerprint:r,diagnosticWallNs:o,cpu:i,warnings:t(i),artifacts:[]});return{result:a,run:c}}export{Ye as bench,en as compareDocuments,Qe as group,G as loadDocument,bt as profile,pn as renderers,wt as run,Le as saveDocument,Xe as task};
2
+ import{m,d,n,w,I}from"./chunk-m8zhsw7r.js";import{o,t,F,D}from"./chunk-qh19pbhc.js";export{m as bench,d as compareDocuments,F as group,t as loadDocument,I as profile,n as renderers,w as run,o as saveDocument,D as task};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ostia",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Fast profiling and benchmarking for Bun.",
5
5
  "type": "module",
6
6
  "exports": {
package/runner.ts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ import{r,R,i,s,o,l,p,T,C,x,N}from"./chunk-qh19pbhc.js";var U=500,W=20,J=3,z=0.1,H=1000,G=1e4,A=0;function b(n){if(typeof n==="number")A+=n;else if(n!==void 0&&n!==null)A+=1}function I(n){return n!==null&&typeof n==="object"&&typeof n.then==="function"}function F(n,a){return Math.max(1,Math.ceil(H/n),Math.ceil(a/(n*G)))}async function L(n,a={}){let m=(a.timeBudgetMs??U)*1e6,h=m*(a.warmupFraction??z),k=Bun.nanoseconds(),d=0,f=0;while(f<h){let e=n();b(I(e)?await e:e),d++,f=Bun.nanoseconds()-k}let c;if(d>0)c=Math.max(1,f/d);else{let e=Bun.nanoseconds(),g=n();b(I(g)?await g:g),c=Math.max(1,Bun.nanoseconds()-e)}let t=F(c,m);if(t>1){let e=Bun.nanoseconds();for(let g=0;g<t;g++){let w=n();b(I(w)?await w:w)}c=Math.max(1,(Bun.nanoseconds()-e)/t),t=F(c,m)}let M=c*t,B=a.minSamples??Math.min(W,Math.max(J,Math.floor(m/M))),u=[],S=Bun.nanoseconds(),E=0,_=0;while(_<B||E<m){let e=Bun.nanoseconds();for(let w=0;w<t;w++){let O=n();b(I(O)?await O:O)}let g=Bun.nanoseconds();if(u.push({i:_,wallNs:(g-e)/t}),_++,E=Bun.nanoseconds()-S,a.gc)Bun.gc(!0)}let P=u.map((e)=>e.wallNs),y=l(P),D=p(y,[],"inprocess");return{trials:u,timing:y,warnings:D}}async function j(){let[n,a,m]=process.argv.slice(2);if(!n||!a)return process.stderr.write(`bench runner: usage: runner.ts <suiteFile> <outputPath> [optsJson]
4
+ `),2;let h=m?JSON.parse(m):{};C(),await import(n);let k=T();if(k.length===0)return process.stderr.write(`bench runner: ${n} registered no tasks (no task() calls found).
5
+ `),2;let d=N(k,h.filter);if(d.length===0)return process.stderr.write(`bench runner: --filter ${JSON.stringify(h.filter)} matched zero of ${k.length} registered tasks in ${n}.
6
+ `),2;let f=[],c=[];for(let t of d){let M=x(t),B=R(n,M,M,t.baseline);f.push(B);let u={...h,...t.opts?.timeBudgetMs!==void 0&&{timeBudgetMs:t.opts.timeBudgetMs},...t.opts?.minSamples!==void 0&&{minSamples:t.opts.minSamples}},S=await L(t.fn,u);c.push(i({workload:B,configFingerprint:s({timeBudgetMs:u.timeBudgetMs??null,minSamples:u.minSamples??null,gc:u.gc??!1}),trials:S.trials,timing:S.timing,warnings:S.warnings}))}return await o(r(f,c),a),0}j().then((n)=>process.exit(n));