ostia 0.1.1 → 0.1.3
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 +38 -12
- package/chunk-qh19pbhc.js +4 -0
- package/chunk-v7vpm34a.js +19 -0
- package/cli.js +39 -32
- package/index.d.ts +17 -1
- package/index.js +1 -1
- package/package.json +1 -1
- package/runner.ts +4 -3
- package/chunk-ck12vbed.js +0 -4
- package/chunk-j0j2b0fj.js +0 -19
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
|
|
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:
|
|
48
|
+
artifact: node_modules/.cache/ostia/artifacts/<run-id>-cpu.cpuprofile
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
|
|
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:
|
|
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()`.
|
|
129
|
-
|
|
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
|
|
193
|
-
ostia viz
|
|
194
|
-
ostia viz
|
|
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: "
|
|
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, "
|
|
399
|
-
const loaded: ProfileDocument = await loadDocument("
|
|
424
|
+
await saveDocument(doc, "doc.json")
|
|
425
|
+
const loaded: ProfileDocument = await loadDocument("doc.json")
|
|
400
426
|
```
|
|
401
427
|
|
|
402
428
|
### `renderers`
|
|
@@ -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};
|
|
@@ -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,j=Be(F.url),J=C.get(F.functionName);if(J===void 0)J=new Map,C.set(F.functionName,J);let K=J.get(j);if(K===void 0)K=N.length,J.set(j,K),N.push({key:e("fr",F.functionName,j),name:F.functionName,url:j||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 L=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 j=R.get(F);if(j!==void 0)L[j]=D}}let E=[],H=[];for(let D=x-1;D>=0;D--)if(L[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 j=R.get(F);if(j!==void 0&&L[j]===D)H.push(j)}}let z=new Float64Array(x);for(let D=E.length-1;D>=0;D--){let M=E[D];z[M]+=S[M];let F=L[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 j={frameIx:M,selfUs:S[D],totalUs:z[D],samples:A[D]};V[M]=j,_.push(j)}}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,L=W.length;for(let _=0;_<L;_+=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 j=`unknown(${D})`;if(F=S.get(j),F===void 0)F={type:j,count:0,bytes:0},S.set(j,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,j,J,K){let Y=T.get(F);if(Y===void 0)Y=new Map,T.set(F,Y);let G=j??"",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:j,line:J,col:K});return q}function N(F){let j=F.line===de,J=j?void 0:F.line-1,K=j||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=[],L=[];for(let F of o.traces){let j=F.frames,J=B;for(let G=j.length-1;G>=0;G--){let q=N(j[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),L.push(c);let K=j[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 j=F.selfUs;for(let J of F.children.values())j+=E(J);return F.totalUs=j,j}E(B);let H=new Map;function z(F){let j=H.get(F.frameIx);if(j)j.selfUs+=F.selfUs,j.totalUs+=F.totalUs,j.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((j)=>j.id)})),_={origin:"jsc-profile",samplingIntervalUs:c,frames:x,nodes:V,totals:[...H.values()].sort((F,j)=>j.selfUs-F.selfUs),samples:{nodeIds:W,timeDeltasUs:L}},D=[...O.entries()].flatMap(([F,j])=>[...j.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 L;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]));L=[...new Set([...H.keys(),...z.keys()])].map((M)=>{let F=H.get(M)?.selfUs??0,j=z.get(M)?.selfUs??0;return{frameKey:M,name:_.get(M)??V.get(M)??M,baseSelfUs:F,candSelfUs:j,deltaPct:se(F,j)}}).sort((M,F)=>Math.abs(F.deltaPct)-Math.abs(M.deltaPct));for(let M of L)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:L,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 L of U.order){let E=R[N[L].frameIx].name||"(anonymous)",H=U.parentIx[L];B[L]=H===-1?E:`${B[H]};${E}`}let S=new Float64Array(U.count),A=[],O=C.samples?.nodeIds??[];for(let L=0;L<O.length;L++){let E=U.indexOf(O[L]);if(E===-1)continue;if(S[E]++===0)A.push(E)}let W=Array(A.length);for(let L=0;L<A.length;L++){let E=A[L];W[L]=`${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,L=Qe(S,B.count,W,c),E=new Set(W!==-1?[W]:[]),H=[];for(let V of L){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 L={$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(L,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 L=c.get(W.workloadId);return{run:W,workload:L,label:L?ce(L):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 L=Ue(W.workload);if(L===void 0)continue;let E=N.get(L);if(E)E.push(W);else N.set(L,[W])}let R=(W)=>{let L=Ue(W.workload);if(L===void 0)return x;let E=N.get(L)??[W],H=E.find((z)=>z.workload?.baseline);return H?H.run.timing.median:Math.min(...E.map((z)=>z.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:L,label:E,workload:H}=W,z=L.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 L.warnings)U.push(` ! ${M.message}`)}let A=en(o,c);if(A.length>0)U.push(""),U.push(...A);let O=ve(o,c);if(O.length>0)U.push(""),U.push(...O);return{text:`${U.join(`
|
|
17
|
+
`)}
|
|
18
|
+
`}}};function Ze(o,v,c){let T=o.runs.find((C)=>C.id===c),x=T?v.get(T.workloadId):void 0;return x?ce(x):c}function ve(o,v){if(!o.comparisons||o.comparisons.length===0)return[];let c=[];for(let T of o.comparisons){let x=Ze(o,v,T.candidateRunId),C=T.verdict==="pass"?"\u2713":"\u2717";if(c.push(`${C} ${x}`),T.timing){let N=T.timing.medianDeltaPct>0?"+":"";c.push(` timing: ${N}${T.timing.medianDeltaPct.toFixed(1)}% median (${T.timing.verdict})`)}if(T.frames)for(let N of T.frames.slice(0,De)){if(Math.abs(N.deltaPct)<0.5)continue;let R=N.deltaPct>0?"+":"";c.push(` frame ${N.name}: ${R}${N.deltaPct.toFixed(1)}% self-time (${(N.baseSelfUs/1000).toFixed(2)}ms -> ${(N.candSelfUs/1000).toFixed(2)}ms)`)}if(T.heapTypes)for(let N of T.heapTypes.slice(0,Me)){if(Math.abs(N.deltaPct)<0.5)continue;let R=N.deltaPct>0?"+":"";c.push(` heap ${N.type}: ${R}${N.deltaPct.toFixed(1)}% count (${N.baseCount} -> ${N.candCount})`)}}return c}var De=5,Me=5;function en(o,v){let c=[];for(let T of o.runs){if(T.phase!=="cpu"&&T.phase!=="heap")continue;let x=v.get(T.workloadId),C=x?ce(x):T.workloadId;if(T.phase==="cpu")if(T.cpu){c.push(`CPU capture - ${C} (instrumented, ${T.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${te(T.diagnosticWallNs??0)}ms)`);let N=T.cpu.totals.reduce((R,U)=>R+U.selfUs,0)||1;for(let R of T.cpu.totals.slice(0,De)){let U=T.cpu.frames[R.frameIx],B=(R.selfUs/N*100).toFixed(1);c.push(` ${B.padStart(5)}% ${(R.selfUs/1000).toFixed(2).padStart(8)}ms self ${U?.name??"?"}`)}}else c.push(`CPU capture - ${C} (instrumented, no evidence captured)`);else if(T.heap){let N=((T.heap.heapSizeBytes??0)/1e6).toFixed(2);c.push(`Heap snapshot - ${C} (instrumented, ${T.heap.objectCount??"?"} objects, ${N}MB)`);for(let R of T.heap.typeCounts.slice(0,Me))c.push(` ${String(R.count).padStart(6)} ${R.type}`)}else c.push(`Heap snapshot - ${C} (instrumented, no evidence captured)`);for(let N of T.artifacts)c.push(` artifact: ${N.path}`);for(let N of T.warnings)c.push(` ! ${N.message}`)}return c}var n={table:Fe,json:Re,markdown:Ce,jsonl:Pe,collapsed:we,mermaid:Ie,speedscope:ke,cpuprofile:xe};var nn="node_modules/.cache/ostia",ue=1000;async function w(o){let v=s({runs:o.runs??null,warmup:o.warmup??null,cpu:o.cpu??!1,heap:o.heap??!1,cpuIntervalUs:o.cpuIntervalUs??ue}),T=`${o.outDir??nn}/artifacts`,x=[],C=[];for(let N of o.commands){let R=Array.isArray(N)?N:be(N),U=u(R,Array.isArray(N)?void 0:N);x.push(U);let B=await f({argv:R,cwd:o.cwd,env:o.env,runs:o.runs,warmup:o.warmup}),S=i({workload:U,configFingerprint:v,trials:B.trials,timing:B.timing,warnings:B.warnings});if(C.push(S),o.cpu){let A=`${S.id}-cpu.cpuprofile`,O=await pe({argv:R,cwd:o.cwd,env:o.env,artifactDir:T,fileName:A,intervalUs:o.cpuIntervalUs??ue});C.push(await Se({workload:U,phase:"cpu",configFingerprint:v,diagnosticWallNs:O.diagnosticWallNs,exitCode:O.exitCode,cpu:O.cpu,artifactPath:O.artifactPath,artifactKind:"cpuprofile",warnings:O.warnings}))}if(o.heap){let A=`${S.id}-heap.heapsnapshot`,O=await me({argv:R,cwd:o.cwd,env:o.env,artifactDir:T,fileName:A});C.push(await Se({workload:U,phase:"heap",configFingerprint:v,diagnosticWallNs:O.diagnosticWallNs,exitCode:O.exitCode,heap:O.heap,artifactPath:O.artifactPath,artifactKind:"heapsnapshot",warnings:O.warnings}))}}return r(x,C)}async function Se(o){let v=`${o.workload.id}-${o.phase}-${o.configFingerprint}`,c=o.artifactPath?[await P(v,o.artifactKind,o.artifactPath)]:[];return h({workload:o.workload,phase:o.phase,configFingerprint:o.configFingerprint,diagnosticWallNs:o.diagnosticWallNs,exitCode:o.exitCode,cpu:o.cpu,heap:o.heap,warnings:o.warnings,artifacts:c})}async function I(o,v={}){let c=k(o),T=s({intervalUs:v.intervalUs??ue,origin:v.origin??"inspector"}),x=(B)=>B.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(v.origin==="jsc"){let{result:B,cpu:S,jit:A,diagnosticWallNs:O}=await he(o,v),W=h({workload:c,phase:"cpu",configFingerprint:T,diagnosticWallNs:O,cpu:S,jit:A,warnings:x(S),artifacts:[]});return{result:B,run:W}}let{result:C,cpu:N,diagnosticWallNs:R}=await fe(o,v),U=h({workload:c,phase:"cpu",configFingerprint:T,diagnosticWallNs:R,cpu:N,warnings:x(N),artifacts:[]});return{result:C,run:U}}
|
|
19
|
+
export{m,a,d,b,f,n,w,I};
|
package/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{a
|
|
4
|
-
`)}var
|
|
3
|
+
import{m,a,d,b,f,n,w}from"./chunk-v7vpm34a.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(`
|
|
5
5
|
`)}
|
|
6
|
-
`}async function
|
|
7
|
-
`)}else if(
|
|
8
|
-
${
|
|
9
|
-
`)}var
|
|
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...>
|
|
10
10
|
|
|
11
11
|
Run one or more commands N times with warmup and report timing statistics.
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ Flags:
|
|
|
16
16
|
--cpu capture one instrumented CPU-profile trial (subprocess --cpu-prof)
|
|
17
17
|
--heap capture one instrumented heap-snapshot trial (subprocess --heap-prof)
|
|
18
18
|
--cpu-interval USEC CPU sampling interval in microseconds (default: 1000)
|
|
19
|
-
--out-dir PATH directory for captured artifacts (default:
|
|
19
|
+
--out-dir PATH directory for captured artifacts (default: node_modules/.cache/ostia)
|
|
20
20
|
--export-json PATH write the full ProfileDocument to PATH
|
|
21
21
|
--format FORMAT table | json (default: table)
|
|
22
22
|
--quiet suppress the rendered report (still writes --export-json)
|
|
@@ -30,16 +30,20 @@ Examples:
|
|
|
30
30
|
ostia run --runs 25 --warmup 3 "bun a.ts" "bun b.ts"
|
|
31
31
|
ostia run --cpu --heap "bun src/server.ts"
|
|
32
32
|
ostia run --format json "bun a.ts"
|
|
33
|
-
`,
|
|
33
|
+
`,ee=`ostia bench [flags] <suite.ts...>
|
|
34
34
|
|
|
35
35
|
Run in-process benchmark suites (registered via group()/task()). Each suite file runs
|
|
36
36
|
in its own spawned child process (isolated from CLI startup state).
|
|
37
37
|
|
|
38
38
|
Flags:
|
|
39
|
-
--time-budget MS
|
|
40
|
-
--min-samples N
|
|
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.
|
|
41
43
|
--gc Bun.gc(true) between trials (default: off - hides allocation cost)
|
|
42
|
-
--
|
|
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)
|
|
43
47
|
--export-json PATH write the full ProfileDocument to PATH
|
|
44
48
|
--format FORMAT table | json (default: table)
|
|
45
49
|
--quiet suppress the rendered report (still writes --export-json)
|
|
@@ -49,12 +53,15 @@ Suite files register tasks like:
|
|
|
49
53
|
import { group, task } from "<pkg>"
|
|
50
54
|
group("parse", () => {
|
|
51
55
|
task("small input", () => parse(smallBuf))
|
|
56
|
+
task("full pipeline", () => build(), { timeBudgetMs: 2000, minSamples: 10 })
|
|
52
57
|
})
|
|
58
|
+
Per-task options override --time-budget / --min-samples for that task only.
|
|
53
59
|
|
|
54
60
|
Examples:
|
|
55
61
|
ostia bench benches/parse.ts
|
|
56
62
|
ostia bench --time-budget 1000 --min-samples 50 benches/*.ts
|
|
57
|
-
|
|
63
|
+
ostia bench benches/*.ts --filter parse
|
|
64
|
+
`,K=`ostia compare <base.json> <candidate.json>
|
|
58
65
|
ostia compare <candidate.json> --baseline <path.json>
|
|
59
66
|
|
|
60
67
|
Compare two ProfileDocuments (matched by workload id) and rank timing/frame/heap deltas.
|
|
@@ -68,10 +75,10 @@ Flags:
|
|
|
68
75
|
Examples:
|
|
69
76
|
ostia compare before.json after.json
|
|
70
77
|
ostia compare after.json --baseline .ostia/baselines/main.json
|
|
71
|
-
`,
|
|
78
|
+
`,te=`ostia report <document.json> [--format table|json|markdown|jsonl]
|
|
72
79
|
|
|
73
80
|
Render a saved ProfileDocument.
|
|
74
|
-
`,
|
|
81
|
+
`,re=`ostia viz <document.json> --format FORMAT [--run <id>] [--out-dir PATH]
|
|
75
82
|
|
|
76
83
|
Render CPU evidence from a saved ProfileDocument as a visualization artifact. Files,
|
|
77
84
|
not a GUI - hand the output to speedscope.app, flamegraph.pl, or
|
|
@@ -90,9 +97,9 @@ Flags:
|
|
|
90
97
|
--help show this message
|
|
91
98
|
|
|
92
99
|
Examples:
|
|
93
|
-
ostia viz run.json --format speedscope --out-dir
|
|
100
|
+
ostia viz run.json --format speedscope --out-dir node_modules/.cache/ostia/viz
|
|
94
101
|
ostia viz run.json --format collapsed | flamegraph.pl > flame.svg
|
|
95
|
-
`,
|
|
102
|
+
`,se=`ostia ci [--full] [--baseline NAME]
|
|
96
103
|
|
|
97
104
|
Load ostia.config.json, run configured workloads (reusing cached results when their
|
|
98
105
|
fingerprint is unchanged), compare against the named baseline, and gate on regressions.
|
|
@@ -105,21 +112,21 @@ Flags:
|
|
|
105
112
|
--help show this message
|
|
106
113
|
|
|
107
114
|
Exit codes: 0 pass, 1 regression, 2 harness error (missing config/baseline, spawn failure).
|
|
108
|
-
`;function
|
|
109
|
-
`),2;let
|
|
110
|
-
`),2}if(
|
|
111
|
-
`),2;let
|
|
112
|
-
`),2}if(
|
|
113
|
-
`),2}let
|
|
114
|
-
`),2}let
|
|
115
|
-
`),2;let
|
|
116
|
-
`),2}let
|
|
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}".
|
|
117
124
|
`:`No CPU evidence found in this document (no cpu-phase runs). Capture some with "ostia run --cpu ...".
|
|
118
|
-
`),2;return await
|
|
119
|
-
`),2;if(
|
|
120
|
-
`),2;let
|
|
121
|
-
`),2;return process.stderr.write(`CI run failed: ${
|
|
122
|
-
`),2}if(
|
|
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
|
|
123
130
|
|
|
124
131
|
Commands:
|
|
125
132
|
run Run commands N times and report timing/CPU/heap
|
|
@@ -130,5 +137,5 @@ Commands:
|
|
|
130
137
|
viz Render CPU evidence as collapsed/mermaid/speedscope/cpuprofile
|
|
131
138
|
|
|
132
139
|
Run "ostia <command> --help" for details.
|
|
133
|
-
`),
|
|
134
|
-
`),2}}if(import.meta.main)
|
|
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
|
|
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,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{m,d,n,w,I}from"./chunk-v7vpm34a.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
package/runner.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{
|
|
4
|
-
`),2;let
|
|
5
|
-
`),2;let
|
|
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));
|
package/chunk-ck12vbed.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
function N(n){return JSON.stringify(d(n))}function d(n){if(Array.isArray(n))return n.map(d);if(n!==null&&typeof n==="object"){let e={};for(let r of Object.keys(n).sort())e[r]=d(n[r]);return e}return n}function c(n,...e){let r=Bun.CryptoHasher.hash("sha256",N(e),"hex");return`${n}_${r.slice(0,16)}`}var k="0.1.0";function E(n,e){return{schemaVersion:1,toolVersion:k,bunVersion:Bun.version,platform:{os:process.platform,arch:process.arch},createdAt:new Date().toISOString(),workloads:n,runs:e}}function O(n,e){return{id:c("wl","subprocess",n,process.cwd()),kind:"subprocess",command:n,label:e}}function C(n,e){return{id:c("wl","inprocess",n.name,n.toString()),kind:"inprocess",label:e}}function q(n,e,r){return{id:c("wl","inprocess-entry",n,e),kind:"inprocess",entry:{file:n,task:e},label:r}}function _(n){return{id:c("run",n.workload.id,"timing",n.configFingerprint,Bun.version,k),workloadId:n.workload.id,phase:"timing",instrumented:!1,configFingerprint:n.configFingerprint,trials:n.trials,timing:n.timing,warnings:n.warnings,artifacts:[],memory:B(n.trials)}}function B(n){let e=n.map((r)=>r.maxRssBytes).filter((r)=>r!==void 0);if(e.length===0)return;return{origin:"resourceUsage",perTrial:n.map((r)=>({rssBytes:r.maxRssBytes})),maxRssBytes:Math.max(...e)}}function H(n){return{id:c("run",n.workload.id,n.phase,n.configFingerprint,Bun.version,k),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 J(n,e,r){let i=await Bun.file(r).arrayBuffer(),o=new Bun.CryptoHasher("sha256");return o.update(i),{id:c("art",n,e,r),kind:e,path:r,sha256:o.digest("hex"),bytes:i.byteLength}}function j(n){return c("cfg",n)}function D(n){return`${JSON.stringify(d(n),null,2)}
|
|
3
|
-
`}async function L(n,e){await Bun.write(e,D(n))}async function z(n){let e=await Bun.file(n).text();return JSON.parse(e)}var x=[],m;function K(n,e){let r=m;m=n;try{e()}finally{m=r}}function U(n,e){x.push({groupName:m,name:n,fn:e})}function G(){return x}function Z(){x.length=0,m=void 0}function X(n){if(n.length===0)throw Error("computeTimingStats: samples must be non-empty");let e=n.length,r=b(n),t=0;for(let a=0;a<e;a++)t+=n[a];let i=t/e,o=g(r,0.5),s=0;for(let a=0;a<e;a++){let u=n[a]-i;s+=u*u}let p=Math.sqrt(s/e),y=r[0],f=r[e-1],h=g(r,0.25),w=g(r,0.75),l=w-h,v=h-1.5*l,W=w+1.5*l,S=h-3*l,F=w+3*l,R=0,T=0;for(let a=0;a<e;a++){let u=n[a];if(u<S||u>F)T++;else if(u<v||u>W)R++}return{unit:"ns",samples:n,mean:i,median:o,stddev:p,min:y,max:f,outliers:{mild:R,severe:T}}}function b(n){let e=new Float64Array(n.length);return e.set(n),e.sort(),e}function g(n,e){let r=n.length;if(r===1)return n[0];let t=e*(r-1),i=Math.floor(t),o=Math.ceil(t);if(i===o)return n[i];let s=t-i;return n[i]*(1-s)+n[o]*s}var I=5000000,A=200;function Y(n,e,r="subprocess"){let t=[],i=n.samples[0];if(i!==void 0){let s=b(n.samples),p=g(s,0.25),f=g(s,0.75)-p;if(i>n.median+3*f&&f>0)t.push({code:"slow-first-run",message:`First run took ${(i/1e6).toFixed(2)}ms, much slower than the median ${(n.median/1e6).toFixed(2)}ms. Consider more warmup.`,data:{firstNs:i,medianNs:n.median}})}if(n.outliers.mild+n.outliers.severe>0)t.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(r==="subprocess"&&n.median<I)t.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(r==="inprocess"&&n.median<A)t.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 o=e.filter((s)=>s!==void 0&&s!==0);if(o.length>0)t.push({code:"nonzero-exit",message:`${o.length} of ${e.length} trial(s) exited non-zero.`,data:{exitCodes:o}});return t}
|
|
4
|
-
export{N as i,c as j,k,E as l,O as m,C as n,q as o,_ as p,H as q,J as r,j as s,D as t,L as u,z as v,X as w,Y as x,K as y,U as z,G as A,Z as B};
|
package/chunk-j0j2b0fj.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{i as z,j as k,l as E,m as $e,n as Ce,p as Ie,q as j,r as Ne,s as G,t as pe,v as H,w as re,x as se}from"./chunk-ck12vbed.js";function Ue(e){return e.startsWith("file://")?e.slice(7):e}function W(e,a,n){let s=e.nodes,t=s.length,i=new Map,o=[],r=new Map,c=new Int32Array(t);for(let m=0;m<t;m++){let d=s[m],u=d.callFrame,y=Ue(u.url),T=i.get(u.functionName);if(T===void 0)T=new Map,i.set(u.functionName,T);let I=T.get(y);if(I===void 0)I=o.length,T.set(y,I),o.push({key:k("fr",u.functionName,y),name:u.functionName,url:y||void 0,line:u.lineNumber>=0?u.lineNumber:void 0,col:u.columnNumber>=0?u.columnNumber:void 0});c[m]=I,r.set(d.id,m)}let f=Array(t);for(let m=0;m<t;m++){let d=s[m];f[m]={id:d.id,frameIx:c[r.get(d.id)],children:d.children??[]}}let p=new Float64Array(t),l=new Float64Array(t),g=e.samples,x=e.timeDeltas;for(let m=0;m<g.length;m++){let d=r.get(g[m]);if(d===void 0)continue;p[d]+=x[m]??0,l[d]+=1}let R=new Int32Array(t).fill(-1);for(let m=0;m<t;m++){let d=s[m].children;if(!d)continue;for(let u of d){let y=r.get(u);if(y!==void 0)R[y]=m}}let h=[],w=[];for(let m=t-1;m>=0;m--)if(R[m]===-1)w.push(m);while(w.length>0){let m=w.pop();h.push(m);let d=s[m].children;if(!d)continue;for(let u of d){let y=r.get(u);if(y!==void 0&&R[y]===m)w.push(y)}}let P=new Float64Array(t);for(let m=h.length-1;m>=0;m--){let d=h[m];P[d]+=p[d];let u=R[d];if(u>=0)P[u]+=P[d]}let C=Array(o.length),b=[];for(let m=0;m<t;m++){let d=f[m].frameIx,u=C[d];if(u)u.selfUs+=p[m],u.totalUs+=P[m],u.samples+=l[m];else{let y={frameIx:d,selfUs:p[m],totalUs:P[m],samples:l[m]};C[d]=y,b.push(y)}}return{origin:a,samplingIntervalUs:n,frames:o,nodes:f,totals:b.sort((m,d)=>d.selfUs-m.selfUs),samples:{nodeIds:e.samples,timeDeltasUs:e.timeDeltas}}}function ve(e,a,n,s){let t=["--cpu-prof","--cpu-prof-dir",a,"--cpu-prof-name",n,"--cpu-prof-interval",String(s)],i=e[0];if(i==="bun"||i?.endsWith("/bun"))return[i,...t,...e.slice(1)];return e}async function Y(e){let a=`${e.artifactDir}/${e.fileName}`,n=e.argv[0],s=n==="bun"||n?.endsWith("/bun"),t=ve(e.argv,e.artifactDir,e.fileName,e.intervalUs),i=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}`},o=Bun.nanoseconds(),c=await Bun.spawn(t,{cwd:e.cwd,env:i,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,f=Bun.nanoseconds()-o,p=Bun.file(a);if(!await p.exists())return{diagnosticWallNs:f,exitCode:c,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${a} after exit ${c}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:a,argv:e.argv}}]};let l=await p.json(),g=W(l,"cpu-prof",e.intervalUs),x=l.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:f,exitCode:c,artifactPath:a,cpu:g,warnings:x}}function q(e,a="heap-prof"){let{node_fields:n,node_types:s}=e.snapshot.meta,t=n.indexOf("type"),i=n.indexOf("self_size"),o=n.length,r=s[0];if(t===-1||i===-1||!Array.isArray(r))return{origin:a,typeCounts:[],objectCount:e.snapshot.node_count};let c=r.length,f=Array(c),p=new Map,l=[],g=0,x=e.nodes,R=x.length;for(let b=0;b<R;b+=o){let m=x[b+t],d=x[b+i]??0;g+=d;let u;if(m>=0&&m<c){if(u=f[m],u===void 0)u={type:r[m],count:0,bytes:0},f[m]=u,l.push(u)}else{let y=`unknown(${m})`;if(u=p.get(y),u===void 0)u={type:y,count:0,bytes:0},p.set(y,u),l.push(u)}u.count++,u.bytes+=d}let h=l.sort((b,m)=>m.count-b.count),w=h.slice(0,20),P=h.slice(20),C=w.map(({type:b,count:m,bytes:d})=>({type:b,count:m,retainedBytes:d}));if(P.length>0){let b=0,m=0;for(let d of P)b+=d.count,m+=d.bytes;C.push({type:"other",count:b,retainedBytes:m})}return{origin:a,heapSizeBytes:g,objectCount:e.snapshot.node_count,typeCounts:C}}function ke(e,a,n){let s=["--heap-prof","--heap-prof-dir",a,"--heap-prof-name",n],t=e[0];if(t==="bun"||t?.endsWith("/bun"))return[t,...s,...e.slice(1)];return e}async function Q(e){let a=`${e.artifactDir}/${e.fileName}`,n=e.argv[0],s=n==="bun"||n?.endsWith("/bun"),t=ke(e.argv,e.artifactDir,e.fileName),i=s?e.env:{...process.env,...e.env,BUN_OPTIONS:`--heap-prof --heap-prof-dir ${e.artifactDir} --heap-prof-name ${e.fileName}`},o=Bun.nanoseconds(),c=await Bun.spawn(t,{cwd:e.cwd,env:i,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,f=Bun.nanoseconds()-o,p=Bun.file(a);if(!await p.exists())return{diagnosticWallNs:f,exitCode:c,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${a} after exit ${c}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:a,argv:e.argv}}]};let l=await p.json(),g=q(l,"heap-prof");return{diagnosticWallNs:f,exitCode:c,artifactPath:a,heap:g,warnings:[]}}import{Session as Fe}from"inspector/promises";var De=1000;async function X(e,a={}){let n=a.intervalUs??De,s=new Fe;s.connect();let t=Bun.nanoseconds();try{await s.post("Profiler.enable"),await s.post("Profiler.setSamplingInterval",{interval:n}),await s.post("Profiler.start");let i=await e(),{profile:o}=await s.post("Profiler.stop"),r=Bun.nanoseconds()-t,c=W(o,"inspector",n);return{result:i,cpu:c,diagnosticWallNs:r}}finally{s.disconnect()}}import{profile as Se}from"bun:jsc";var Me=new Map([["LLInt","llint"],["Baseline","baseline"],["DFG","dfg"],["FTL","ftl"]]),Z=4294967295;function ee(e,a){let n=a??e.interval*1e6,s=new Map,t=[];function i(u,y,T,I){let U=s.get(u);if(U===void 0)U=new Map,s.set(u,U);let N=y??"",v=U.get(N);if(v===void 0)v=t.length,U.set(N,v),t.push({key:k("fr",u,N),name:u,url:y,line:T,col:I});return v}function o(u){let y=u.line===Z,T=y?void 0:u.line-1,I=y||u.column===Z?void 0:u.column-1;return i(u.name,u.sourceURL,T,I)}let r=i("(root)",void 0,void 0,void 0),c=1,f={id:0,frameIx:r,children:new Map,selfUs:0,samples:0,totalUs:0},p=new Map([[0,f]]),l={llint:0,baseline:0,dfg:0,ftl:0},g=new Map,x=[],R=[];for(let u of e.traces){let y=u.frames,T=f;for(let N=y.length-1;N>=0;N--){let v=o(y[N]),M=T.children.get(v);if(!M)M={id:c++,frameIx:v,children:new Map,selfUs:0,samples:0,totalUs:0},T.children.set(v,M),p.set(M.id,M);T=M}T.selfUs+=n,T.samples+=1,x.push(T.id),R.push(n);let I=y[0],U=I&&Me.get(I.category);if(U){l[U]++;let N=g.get(U)??new Map;N.set(T.frameIx,(N.get(T.frameIx)??0)+1),g.set(U,N)}}function h(u){let y=u.selfUs;for(let T of u.children.values())y+=h(T);return u.totalUs=y,y}h(f);let w=new Map;function P(u){let y=w.get(u.frameIx);if(y)y.selfUs+=u.selfUs,y.totalUs+=u.totalUs,y.samples+=u.samples;else w.set(u.frameIx,{frameIx:u.frameIx,selfUs:u.selfUs,totalUs:u.totalUs,samples:u.samples});for(let T of u.children.values())P(T)}P(f);let C=[...p.values()].map((u)=>({id:u.id,frameIx:u.frameIx,children:[...u.children.values()].map((y)=>y.id)})),b={origin:"jsc-profile",samplingIntervalUs:n,frames:t,nodes:C,totals:[...w.values()].sort((u,y)=>y.selfUs-u.selfUs),samples:{nodeIds:x,timeDeltasUs:R}},m=[...g.entries()].flatMap(([u,y])=>[...y.entries()].sort((T,I)=>I[1]-T[1]).slice(0,3).map(([T,I])=>({tier:u,frameKey:t[T].key,samples:I})));return{cpu:b,jit:{origin:"jsc-profile",tiers:l,topFramesByTier:m}}}var Be=1000;async function ne(e,a={}){let n=a.intervalUs??Be,s,t=Bun.nanoseconds(),i=await Se(async()=>(s=await e(),s),n),o=Bun.nanoseconds()-t,{cpu:r,jit:c}=ee(i.stackTraces,n);return{result:s,cpu:r,jit:c,diagnosticWallNs:o}}async function L(e){let a=Bun.nanoseconds(),n=Bun.spawn(e.argv,{cwd:e.cwd,env:e.env,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),s=await n.exited,t=Bun.nanoseconds(),i=n.resourceUsage?.();return{wallNs:t-a,exitCode:s,userNs:i?Number(i.cpuTime.user)*1000:void 0,systemNs:i?Number(i.cpuTime.system)*1000:void 0,maxRssBytes:i?.maxRSS}}function te(e){return e.trim().split(/\s+/).filter(Boolean)}var Oe=10,We=3000000000,Ee=3;async function oe(e){let a=e.warmup??Ee;for(let p=0;p<a;p++)await L(e);let n=[],s=e.runs??e.minRuns??Oe,t=e.runs!==void 0?0:e.minTotalNs??We,i=0,o=0;while(o<s||i<t){let p=await L(e);if(n.push({i:o,wallNs:p.wallNs,exitCode:p.exitCode,userNs:p.userNs,systemNs:p.systemNs,maxRssBytes:p.maxRssBytes}),i+=p.wallNs,o++,e.runs!==void 0&&o>=e.runs)break}let r=n.map((p)=>p.wallNs),c=re(r),f=se(c,n.map((p)=>p.exitCode));return{trials:n,timing:c,warnings:f}}var Ae=new URL("./runner.ts",import.meta.url).pathname,_e=".ostia";async function je(e){let n=`${e.outDir??_e}/bench-tmp`,s=e.cwd??process.cwd(),t={timeBudgetMs:e.timeBudgetMs,minSamples:e.minSamples,gc:e.gc},i=[],o=[];try{for(let r of e.suites){let c=r.startsWith("/")?r:`${s}/${r}`,f=`${n}/${k("bench-out",c)}.json`,l=await Bun.spawn(["bun",Ae,c,f,JSON.stringify(t)],{cwd:s,stdout:"inherit",stderr:"inherit",stdin:"ignore"}).exited;if(l!==0)throw Error(`Bench suite failed: ${r} (runner exited ${l})`);let g=await H(f);i.push(...g.workloads),o.push(...g.runs)}}finally{await Bun.spawn(["rm","-rf",n]).exited}return E(i,o)}var ie={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000};function A(e,a){if(e===0)return a===0?0:1/0;return(a-e)/e*100}function S(e,a,n){return e.runs.find((s)=>s.workloadId===a&&s.phase===n)}function Le(e,a,n=ie){let s=new Set(a.workloads.map((i)=>i.id)),t=[];for(let i of e.workloads){if(!s.has(i.id))continue;let o=He(e,a,i.id,n);if(o)t.push(o)}return t}function He(e,a,n,s=ie){let t=S(e,n,"timing"),i=S(a,n,"timing"),o=S(e,n,"cpu"),r=S(a,n,"cpu"),c=S(e,n,"heap"),f=S(a,n,"heap"),p=t?.id??o?.id??c?.id,l=i?.id??r?.id??f?.id;if(!p||!l)return;let g=!1,x;if(t?.timing&&i?.timing){let w=A(t.timing.median,i.timing.median),P=A(t.timing.mean,i.timing.mean),C=w>s.timingPct?"regressed":w<-s.timingPct?"improved":"unchanged";if(C==="regressed")g=!0;x={medianDeltaPct:w,meanDeltaPct:P,verdict:C}}let R;if(o?.cpu&&r?.cpu){let w=new Map(o.cpu.totals.map((d)=>[o.cpu.frames[d.frameIx].key,d])),P=new Map(r.cpu.totals.map((d)=>[r.cpu.frames[d.frameIx].key,d])),C=new Map(o.cpu.frames.map((d)=>[d.key,d.name])),b=new Map(r.cpu.frames.map((d)=>[d.key,d.name]));R=[...new Set([...w.keys(),...P.keys()])].map((d)=>{let u=w.get(d)?.selfUs??0,y=P.get(d)?.selfUs??0;return{frameKey:d,name:b.get(d)??C.get(d)??d,baseSelfUs:u,candSelfUs:y,deltaPct:A(u,y)}}).sort((d,u)=>Math.abs(u.deltaPct)-Math.abs(d.deltaPct));for(let d of R)if((d.baseSelfUs>=s.minFrameSelfUs||d.candSelfUs>=s.minFrameSelfUs)&&d.deltaPct>s.frameSelfPct)g=!0}let h;if(c?.heap&&f?.heap){let w=new Map(c.heap.typeCounts.map((b)=>[b.type,b])),P=new Map(f.heap.typeCounts.map((b)=>[b.type,b]));h=[...new Set([...w.keys(),...P.keys()])].map((b)=>{let m=w.get(b),d=P.get(b);return{type:b,baseCount:m?.count??0,candCount:d?.count??0,baseBytes:m?.retainedBytes,candBytes:d?.retainedBytes,deltaPct:A(m?.count??0,d?.count??0)}}).sort((b,m)=>Math.abs(m.deltaPct)-Math.abs(b.deltaPct));for(let b of h)if(b.deltaPct>s.heapTypePct)g=!0}return{id:k("cmp",p,l),baselineRunId:p,candidateRunId:l,timing:x,frames:R,heapTypes:h,thresholds:s,verdict:g?"fail":"pass"}}function F(e,a){if(a){let n=e.runs.find((s)=>s.id===a);return n?.cpu?[n]:[]}return e.runs.filter((n)=>n.phase==="cpu"&&n.cpu)}function B(e){let a=e.nodes,n=a.length,s=ze(e),t=new Int32Array(n).fill(-1);for(let c=0;c<n;c++)for(let f of a[c].children){let p=s(f);if(p!==-1)t[p]=c}let i=[];for(let c=0;c<n;c++)if(t[c]===-1)i.push(c);let o=[],r=[];for(let c=i.length-1;c>=0;c--)r.push(i[c]);while(r.length>0){let c=r.pop();o.push(c);for(let f of a[c].children){let p=s(f);if(p!==-1&&t[p]===c)r.push(p)}}return{count:n,indexOf:s,parentIx:t,roots:i,order:o}}function ze(e){let a=e.nodes,n=a.length,s=1/0,t=-1/0,i=!0;for(let r=0;r<n;r++){let c=a[r].id;if(!Number.isInteger(c)){i=!1;break}if(c<s)s=c;if(c>t)t=c}if(i&&n>0&&t-s<n*4+64){let r=t-s+1,c=new Int32Array(r).fill(-1);for(let f=0;f<n;f++)c[a[f].id-s]=f;return(f)=>{let p=f-s;return p>=0&&p<r?c[p]:-1}}let o=new Map;for(let r=0;r<n;r++)o.set(a[r].id,r);return(r)=>o.get(r)??-1}function ae(e,a){let{count:n,indexOf:s,parentIx:t,order:i}=a,o=new Float64Array(n),r=new Float64Array(n),c=e.samples?.nodeIds??[],f=e.samples?.timeDeltasUs??[];for(let l=0;l<c.length;l++){let g=s(c[l]);if(g===-1)continue;o[g]+=f[l]??0,r[g]+=1}let p=new Float64Array(n);for(let l=i.length-1;l>=0;l--){let g=i[l];p[g]+=o[g];let x=t[g];if(x>=0)p[x]+=p[g]}return{selfUs:o,totalUs:p,samples:r}}var ce={name:"collapsed",async render(e,a={}){return{files:F(e,a.runId).map((t)=>{let i=t.cpu,{nodes:o,frames:r}=i,c=B(i),f=Array(c.count);for(let R of c.order){let h=r[o[R].frameIx].name||"(anonymous)",w=c.parentIx[R];f[R]=w===-1?h:`${f[w]};${h}`}let p=new Float64Array(c.count),l=[],g=i.samples?.nodeIds??[];for(let R=0;R<g.length;R++){let h=c.indexOf(g[R]);if(h===-1)continue;if(p[h]++===0)l.push(h)}let x=Array(l.length);for(let R=0;R<l.length;R++){let h=l[R];x[R]=`${f[h]} ${p[h]}`}return{path:`${t.id}.collapsed.txt`,content:x.join(`
|
|
3
|
-
`)+(x.length>0?`
|
|
4
|
-
`:"")}})}}};var ue={name:"cpuprofile",async render(e,a={}){let n=F(e,a.runId),s=[],t=[];for(let i of n){if(i.cpu?.origin!=="cpu-prof"&&i.cpu?.origin!=="inspector"){t.push(`${i.id} (origin ${i.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let o=i.artifacts.find((c)=>c.kind==="cpuprofile");if(!o){t.push(`${i.id} (no cpuprofile artifact recorded on this run)`);continue}let r=Bun.file(o.path);if(!await r.exists()){t.push(`${i.id} (artifact missing on disk: ${o.path})`);continue}s.push({path:`${i.id}.cpuprofile`,content:await r.text()})}if(s.length===0&&t.length>0)return{text:`No .cpuprofile artifacts available:
|
|
5
|
-
${t.map((i)=>` - ${i}`).join(`
|
|
6
|
-
`)}
|
|
7
|
-
`};return{files:s}}};var le={name:"json",async render(e){return{text:pe(e)}}};var me={name:"jsonl",async render(e){let{runs:a,...n}=e;return{text:`${[z(n),...a.map((t)=>z(t))].join(`
|
|
8
|
-
`)}
|
|
9
|
-
`}}};function D(e){return(e/1e6).toFixed(3)}function _(e){return e?.label??e?.command?.join(" ")??e?.entry?.task??e?.id??"unknown"}var fe=10,de=10,ge={name:"markdown",async render(e){let a=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 s=e.runs.filter((t)=>t.phase==="timing"&&t.timing!==void 0);if(s.length>0){n.push("## Timing",""),n.push("| Command | Mean \xB1 SD (ms) | Min\u2026Max (ms) | Median (ms) |","|---|---|---|---|");for(let i of s){let o=_(a.get(i.workloadId)),r=i.timing;n.push(`| ${o} | ${D(r.mean)} \xB1 ${D(r.stddev)} | ${D(r.min)}\u2026${D(r.max)} | ${D(r.median)} |`)}n.push("");let t=s.filter((i)=>i.warnings.length>0);if(t.length>0){n.push("### Warnings","");for(let i of t){let o=_(a.get(i.workloadId));for(let r of i.warnings)n.push(`- **${o}**: ${r.message} (\`${r.code}\`)`)}n.push("")}}for(let t of e.runs){if(t.phase!=="cpu"&&t.phase!=="heap")continue;let i=_(a.get(t.workloadId));if(t.phase==="cpu"){if(n.push(`## CPU capture - ${i}`,""),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 o=t.cpu.totals.reduce((r,c)=>r+c.selfUs,0)||1;for(let r of t.cpu.totals.slice(0,fe)){let c=t.cpu.frames[r.frameIx],f=(r.selfUs/o*100).toFixed(1);n.push(`| ${f}% | ${(r.selfUs/1000).toFixed(2)} | ${(r.totalUs/1000).toFixed(2)} | ${c?.name||"(anonymous)"} |`)}if(n.push(""),t.jit){let r=t.jit.tiers;n.push(`JIT tiers: LLInt ${r.llint} \xB7 Baseline ${r.baseline} \xB7 DFG ${r.dfg} \xB7 FTL ${r.ftl}`,"")}}}else if(n.push(`## Heap snapshot - ${i}`,""),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 o of t.heap.typeCounts.slice(0,de))n.push(`| ${o.count} | ${o.type} |`);n.push("")}for(let o of t.artifacts)n.push(`- artifact: \`${o.path}\``);for(let o of t.warnings)n.push(`- ! ${o.message} (\`${o.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 i=e.runs.find((r)=>r.id===t.candidateRunId),o=_(i?a.get(i.workloadId):void 0);if(n.push(`### ${t.verdict==="pass"?"\u2713":"\u2717"} ${o}`,""),t.timing){let r=t.timing.medianDeltaPct>0?"+":"";n.push(`- timing: ${r}${t.timing.medianDeltaPct.toFixed(1)}% median (**${t.timing.verdict}**)`)}for(let r of t.frames?.slice(0,fe)??[]){if(Math.abs(r.deltaPct)<0.5)continue;let c=r.deltaPct>0?"+":"";n.push(`- frame \`${r.name}\`: ${c}${r.deltaPct.toFixed(1)}% self-time (${(r.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(r.candSelfUs/1000).toFixed(2)}ms)`)}for(let r of t.heapTypes?.slice(0,de)??[]){if(Math.abs(r.deltaPct)<0.5)continue;let c=r.deltaPct>0?"+":"";n.push(`- heap \`${r.type}\`: ${c}${r.deltaPct.toFixed(1)}% count (${r.baseCount} \u2192 ${r.candCount})`)}n.push("")}}return{text:n.join(`
|
|
10
|
-
`)}}};var Je=15;function J(e){return`n${e}`}function Ve(e,a,n){return`${(e||"(anonymous)").replace(/"/g,"'")} (self ${(a/1000).toFixed(2)}ms, total ${(n/1000).toFixed(2)}ms)`}function Ke(e,a,n,s){let t=[];if(s<=0)return t;for(let i=0;i<a;i++){if(i===n)continue;let o=e[i];if(t.length===s&&o<=e[t[s-1]])continue;let r=t.length;while(r>0&&e[t[r-1]]<o)r--;if(t.splice(r,0,i),t.length>s)t.pop()}return t}var he={name:"mermaid",async render(e,a={}){let n=a.topN??Je;return{files:F(e,a.runId).map((i)=>{let o=i.cpu,{nodes:r,frames:c}=o,f=B(o),{selfUs:p,totalUs:l}=ae(o,f),{parentIx:g}=f,x=f.roots[0]??-1,R=Ke(p,f.count,x,n),h=new Set(x!==-1?[x]:[]),w=[];for(let C of R){w.length=0;for(let b=C;b!==-1;b=g[b])w.push(b);for(let b=w.length-1;b>=0;b--)h.add(w[b])}let P=["graph TD"];for(let C of h){let b=r[C].id;P.push(` ${J(b)}["${Ve(c[r[C].frameIx].name,p[C],l[C])}"]`)}for(let C of h){let b=g[C];if(b!==-1&&h.has(b))P.push(` ${J(r[b].id)} --> ${J(r[C].id)}`)}return{path:`${i.id}.mermaid.md`,content:`${P.join(`
|
|
11
|
-
`)}
|
|
12
|
-
`}})}}};var Ge="https://www.speedscope.app/file-format-schema.json";function be(e){return e?.label??e?.command?.join(" ")??e?.entry?.task??"profile"}var ye={name:"speedscope",async render(e,a={}){let n=F(e,a.runId),s=new Map(e.workloads.map((i)=>[i.id,i]));return{files:n.map((i)=>{let o=i.cpu,{nodes:r}=o,c=B(o),f=o.samples?.nodeIds??[],p=o.samples?.timeDeltasUs??[],l=Array(c.count);for(let h of c.order){let w=c.parentIx[h],P=r[h].frameIx;l[h]=w===-1?[P]:[...l[w],P]}let g=Array(f.length);for(let h=0;h<f.length;h++){let w=c.indexOf(f[h]);g[h]=w===-1?[]:l[w]}let x=0;for(let h=0;h<p.length;h++)x+=p[h];let R={$schema:Ge,exporter:"ostia",name:be(s.get(i.workloadId)),activeProfileIndex:0,shared:{frames:o.frames.map((h)=>({name:h.name||"(anonymous)",file:h.url,line:h.line!==void 0?h.line+1:void 0}))},profiles:[{type:"sampled",name:be(s.get(i.workloadId)),unit:"microseconds",startValue:0,endValue:x,samples:g,weights:p}]};return{path:`${i.id}.speedscope.json`,content:`${JSON.stringify(R,null,2)}
|
|
13
|
-
`}})}}};function O(e){return(e/1e6).toFixed(3)}function V(e){return e.label??e.command?.join(" ")??e.entry?.task??e.id}var xe={name:"table",async render(e){let a=e.runs.filter((l)=>l.phase==="timing"&&l.timing!==void 0),n=new Map(e.workloads.map((l)=>[l.id,l]));if(a.length===0){let l=we(e,n);return{text:l.length>0?`${l.join(`
|
|
14
|
-
`)}
|
|
15
|
-
`:`(no timing runs)
|
|
16
|
-
`}}let s=a.map((l)=>{let g=n.get(l.workloadId);return{run:l,workload:g,label:g?V(g):l.workloadId}}),t=Math.min(...s.map((l)=>l.run.timing.median)),i=s.length>1,o=[],r=Math.max(7,...s.map((l)=>l.label.length)),c=i?`${"Command".padEnd(r)} Mean [ms] Min\u2026Max [ms] Relative`:`${"Command".padEnd(r)} Mean [ms] Min\u2026Max [ms]`;o.push(c),o.push("-".repeat(c.length));for(let{run:l,label:g}of s){let x=l.timing,R=`${O(x.mean)} \xB1 ${O(x.stddev)}`,h=`${O(x.min)}\u2026${O(x.max)}`,w=`${g.padEnd(r)} ${R.padEnd(15)} ${h.padEnd(18)}`;if(i){let P=x.median/t;w+=P===1?" 1.00\xD7":` ${P.toFixed(2)}\xD7 slower`}o.push(w);for(let P of l.warnings)o.push(` ! ${P.message}`)}let f=qe(e,n);if(f.length>0)o.push(""),o.push(...f);let p=we(e,n);if(p.length>0)o.push(""),o.push(...p);return{text:`${o.join(`
|
|
17
|
-
`)}
|
|
18
|
-
`}}};function Ye(e,a,n){let s=e.runs.find((i)=>i.id===n),t=s?a.get(s.workloadId):void 0;return t?V(t):n}function we(e,a){if(!e.comparisons||e.comparisons.length===0)return[];let n=[];for(let s of e.comparisons){let t=Ye(e,a,s.candidateRunId),i=s.verdict==="pass"?"\u2713":"\u2717";if(n.push(`${i} ${t}`),s.timing){let o=s.timing.medianDeltaPct>0?"+":"";n.push(` timing: ${o}${s.timing.medianDeltaPct.toFixed(1)}% median (${s.timing.verdict})`)}if(s.frames)for(let o of s.frames.slice(0,Re)){if(Math.abs(o.deltaPct)<0.5)continue;let r=o.deltaPct>0?"+":"";n.push(` frame ${o.name}: ${r}${o.deltaPct.toFixed(1)}% self-time (${(o.baseSelfUs/1000).toFixed(2)}ms -> ${(o.candSelfUs/1000).toFixed(2)}ms)`)}if(s.heapTypes)for(let o of s.heapTypes.slice(0,Pe)){if(Math.abs(o.deltaPct)<0.5)continue;let r=o.deltaPct>0?"+":"";n.push(` heap ${o.type}: ${r}${o.deltaPct.toFixed(1)}% count (${o.baseCount} -> ${o.candCount})`)}}return n}var Re=5,Pe=5;function qe(e,a){let n=[];for(let s of e.runs){if(s.phase!=="cpu"&&s.phase!=="heap")continue;let t=a.get(s.workloadId),i=t?V(t):s.workloadId;if(s.phase==="cpu")if(s.cpu){n.push(`CPU capture - ${i} (instrumented, ${s.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${O(s.diagnosticWallNs??0)}ms)`);let o=s.cpu.totals.reduce((r,c)=>r+c.selfUs,0)||1;for(let r of s.cpu.totals.slice(0,Re)){let c=s.cpu.frames[r.frameIx],f=(r.selfUs/o*100).toFixed(1);n.push(` ${f.padStart(5)}% ${(r.selfUs/1000).toFixed(2).padStart(8)}ms self ${c?.name??"?"}`)}}else n.push(`CPU capture - ${i} (instrumented, no evidence captured)`);else if(s.heap){let o=((s.heap.heapSizeBytes??0)/1e6).toFixed(2);n.push(`Heap snapshot - ${i} (instrumented, ${s.heap.objectCount??"?"} objects, ${o}MB)`);for(let r of s.heap.typeCounts.slice(0,Pe))n.push(` ${String(r.count).padStart(6)} ${r.type}`)}else n.push(`Heap snapshot - ${i} (instrumented, no evidence captured)`);for(let o of s.artifacts)n.push(` artifact: ${o.path}`);for(let o of s.warnings)n.push(` ! ${o.message}`)}return n}var Qe={table:xe,json:le,markdown:ge,jsonl:me,collapsed:ce,mermaid:he,speedscope:ye,cpuprofile:ue};var Xe=".ostia",K=1000;async function st(e){let a=G({runs:e.runs??null,warmup:e.warmup??null,cpu:e.cpu??!1,heap:e.heap??!1,cpuIntervalUs:e.cpuIntervalUs??K}),s=`${e.outDir??Xe}/artifacts`,t=[],i=[];for(let o of e.commands){let r=Array.isArray(o)?o:te(o),c=$e(r,Array.isArray(o)?void 0:o);t.push(c);let f=await oe({argv:r,cwd:e.cwd,env:e.env,runs:e.runs,warmup:e.warmup}),p=Ie({workload:c,configFingerprint:a,trials:f.trials,timing:f.timing,warnings:f.warnings});if(i.push(p),e.cpu){let l=`${p.id}-cpu.cpuprofile`,g=await Y({argv:r,cwd:e.cwd,env:e.env,artifactDir:s,fileName:l,intervalUs:e.cpuIntervalUs??K});i.push(await Te({workload:c,phase:"cpu",configFingerprint:a,diagnosticWallNs:g.diagnosticWallNs,exitCode:g.exitCode,cpu:g.cpu,artifactPath:g.artifactPath,artifactKind:"cpuprofile",warnings:g.warnings}))}if(e.heap){let l=`${p.id}-heap.heapsnapshot`,g=await Q({argv:r,cwd:e.cwd,env:e.env,artifactDir:s,fileName:l});i.push(await Te({workload:c,phase:"heap",configFingerprint:a,diagnosticWallNs:g.diagnosticWallNs,exitCode:g.exitCode,heap:g.heap,artifactPath:g.artifactPath,artifactKind:"heapsnapshot",warnings:g.warnings}))}}return E(t,i)}async function Te(e){let a=`${e.workload.id}-${e.phase}-${e.configFingerprint}`,n=e.artifactPath?[await Ne(a,e.artifactKind,e.artifactPath)]:[];return j({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 ot(e,a={}){let n=Ce(e),s=G({intervalUs:a.intervalUs??K,origin:a.origin??"inspector"}),t=(f)=>f.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(a.origin==="jsc"){let{result:f,cpu:p,jit:l,diagnosticWallNs:g}=await ne(e,a),x=j({workload:n,phase:"cpu",configFingerprint:s,diagnosticWallNs:g,cpu:p,jit:l,warnings:t(p),artifacts:[]});return{result:f,run:x}}let{result:i,cpu:o,diagnosticWallNs:r}=await X(e,a),c=j({workload:n,phase:"cpu",configFingerprint:s,diagnosticWallNs:r,cpu:o,warnings:t(o),artifacts:[]});return{result:i,run:c}}
|
|
19
|
-
export{je as a,ie as b,Le as c,He as d,oe as e,Qe as f,st as g,ot as h};
|