ostia 0.1.6 → 0.1.7
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 +34 -1
- package/chunk-3qbcj1m9.js +21 -0
- package/{chunk-nfgy545q.js → chunk-zrck2q0b.js} +3 -3
- package/cli.js +35 -20
- package/index.d.ts +16 -9
- package/index.js +1 -1
- package/package.json +1 -1
- package/runner.ts +4 -4
- package/chunk-tw064qem.js +0 -21
package/README.md
CHANGED
|
@@ -188,7 +188,9 @@ it to install globals a suite needs at import time (jsdom's `document`/`window`)
|
|
|
188
188
|
a `Bun.plugin()` file-loader (e.g. compiling `.svelte`/`.vue` SFCs) before the suite's own
|
|
189
189
|
top-level code runs. Multiple `--preload` scripts run in the order given, so state one
|
|
190
190
|
installs (a plugin registration, a global) is visible to the next and to the suite itself.
|
|
191
|
-
ostia ships none of this itself - just the hook point
|
|
191
|
+
ostia ships none of this itself - just the hook point (for a full jsdom/happy-dom global
|
|
192
|
+
setup or a `Bun.plugin()` component-compile hook, see
|
|
193
|
+
[docs/preload-recipes.md](docs/preload-recipes.md)):
|
|
192
194
|
|
|
193
195
|
```ts
|
|
194
196
|
// bench/jsdom-setup.ts
|
|
@@ -201,6 +203,24 @@ Object.assign(globalThis, { document: dom.window.document, window: dom.window })
|
|
|
201
203
|
ostia bench --preload ./bench/jsdom-setup.ts bench/*.dom.bench.ts
|
|
202
204
|
```
|
|
203
205
|
|
|
206
|
+
`--bun-flags FLAGS` (repeatable, space-separated flags within one value are all appended)
|
|
207
|
+
passes extra flags through to the `bun` invocation that spawns each suite file - the fix for
|
|
208
|
+
packages whose `package.json` `exports` map branches on a resolution condition Bun doesn't
|
|
209
|
+
set by default. Svelte 5's `exports` map, for example, is `{ "browser": "./src/index-client.js",
|
|
210
|
+
"default": "./src/index-server.js" }`: without `--conditions browser`, Bun resolves `default`
|
|
211
|
+
(the server-rendering build), and mounting a component via `@testing-library/svelte` throws
|
|
212
|
+
`lifecycle_function_unavailable` since `mount()` isn't available server-side. The same applies
|
|
213
|
+
to Vue and other dual-target frameworks:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
ostia bench --bun-flags="--conditions=browser" bench/*.dom.bench.ts
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Unlike `BUN_OPTIONS` (an env var Bun's CLI reads to prepend flags, which only reaches the
|
|
220
|
+
spawned suite process today because ostia's `Bun.spawn()` happens to inherit `process.env`),
|
|
221
|
+
`--bun-flags` is a declared, documented integration point that doesn't depend on the parent
|
|
222
|
+
shell's environment.
|
|
223
|
+
|
|
204
224
|
|
|
205
225
|
```
|
|
206
226
|
Command Mean [ms] Min…Max [ms] Relative
|
|
@@ -461,6 +481,19 @@ group("parse", () => {
|
|
|
461
481
|
That is the whole registration surface: `group()` and `task()`. Presentation lives in
|
|
462
482
|
the renderers (`--format`), not in the suite file.
|
|
463
483
|
|
|
484
|
+
All module-scope code in a suite file runs up front, before any task is sampled -
|
|
485
|
+
there's no hook that runs a task's own setup immediately before its sampling and
|
|
486
|
+
its teardown immediately after, the way mitata's generator-based `bench()` drove
|
|
487
|
+
one case to completion before starting the next. If a suite builds more than one
|
|
488
|
+
instance of something stateful (a mounted UI component, an open connection, a
|
|
489
|
+
server) at module scope, every instance already exists by the time any task
|
|
490
|
+
samples - so a query has to be scoped to the instance it belongs to, not written
|
|
491
|
+
against a global/ambient lookup that assumes it's the only one alive. Porting a
|
|
492
|
+
mitata suite that opens a component's menu and queries `getByRole(...)`
|
|
493
|
+
unscoped, for example, breaks once a second instance of that component exists
|
|
494
|
+
in the document; scope the query with something like `within(instance.container)`
|
|
495
|
+
instead.
|
|
496
|
+
|
|
464
497
|
Both take an optional `description` that flows into the document
|
|
465
498
|
(`Workload.description` / `Workload.groupDescription`) and into `--format minimal`, so
|
|
466
499
|
what a number measures and why travels with the data instead of living only in a
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{h,e,r,u,T,i,b,I,s,x,t,l,p}from"./chunk-zrck2q0b.js";function Le(o){return o.startsWith("file://")?o.slice(7):o}function ae(o,U,c){let R=o.nodes,m=R.length,C=new Map,N=[],v=new Map,D=new Int32Array(m);for(let A=0;A<m;A++){let F=R[A],M=F.callFrame,H=Le(M.url),Y=C.get(M.functionName);if(Y===void 0)Y=new Map,C.set(M.functionName,Y);let q=Y.get(H);if(q===void 0)q=N.length,Y.set(H,q),N.push({key:e("fr",M.functionName,H),name:M.functionName,url:H||void 0,line:M.lineNumber>=0?M.lineNumber:void 0,col:M.columnNumber>=0?M.columnNumber:void 0});D[A]=q,v.set(F.id,A)}let W=Array(m);for(let A=0;A<m;A++){let F=R[A];W[A]={id:F.id,frameIx:D[v.get(F.id)],children:F.children??[]}}let O=new Float64Array(m),E=new Float64Array(m),{samples:j,timeDeltas:z}=o;for(let A=0;A<j.length;A++){let F=v.get(j[A]);if(F===void 0)continue;O[F]+=z[A]??0,E[F]+=1}let V=new Int32Array(m).fill(-1);for(let A=0;A<m;A++){let F=R[A].children;if(!F)continue;for(let M of F){let H=v.get(M);if(H!==void 0)V[H]=A}}let _=[],J=[];for(let A=m-1;A>=0;A--)if(V[A]===-1)J.push(A);while(J.length>0){let A=J.pop();_.push(A);let F=R[A].children;if(!F)continue;for(let M of F){let H=v.get(M);if(H!==void 0&&V[H]===A)J.push(H)}}let K=new Float64Array(m);for(let A=_.length-1;A>=0;A--){let F=_[A];K[F]+=O[F];let M=V[F];if(M>=0)K[M]+=K[F]}let G=Array(N.length),L=[];for(let A=0;A<m;A++){let F=W[A].frameIx,M=G[F];if(M)M.selfUs+=O[A],M.totalUs+=K[A],M.samples+=E[A];else{let H={frameIx:F,selfUs:O[A],totalUs:K[A],samples:E[A]};G[F]=H,L.push(H)}}return{origin:U,samplingIntervalUs:c,frames:N,nodes:W,totals:L.sort((A,F)=>F.selfUs-A.selfUs),samples:{nodeIds:o.samples,timeDeltasUs:o.timeDeltas}}}function He(o,U,c,R){let m=["--cpu-prof","--cpu-prof-dir",U,"--cpu-prof-name",c,"--cpu-prof-interval",String(R)],C=o[0];if(C==="bun"||C?.endsWith("/bun"))return[C,...m,...o.slice(1)];return o}async function ge(o){let U=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],R=c==="bun"||c?.endsWith("/bun"),m=He(o.argv,o.artifactDir,o.fileName,o.intervalUs),C=R?o.env:{...process.env,...o.env,BUN_OPTIONS:`--cpu-prof --cpu-prof-dir ${o.artifactDir} --cpu-prof-name ${o.fileName} --cpu-prof-interval ${o.intervalUs}`},N=Bun.nanoseconds(),D=await Bun.spawn(m,{cwd:o.cwd,env:C,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,W=Bun.nanoseconds()-N,O=Bun.file(U);if(!await O.exists())return{diagnosticWallNs:W,exitCode:D,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${U} after exit ${D}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:U,argv:o.argv}}]};let E=await O.json(),j=ae(E,"cpu-prof",o.intervalUs),z=E.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:W,exitCode:D,artifactPath:U,cpu:j,warnings:z}}function he(o,U="heap-prof"){let{node_fields:c,node_types:R}=o.snapshot.meta,m=c.indexOf("type"),C=c.indexOf("self_size"),N=c.length,v=R[0];if(m===-1||C===-1||!Array.isArray(v))return{origin:U,typeCounts:[],objectCount:o.snapshot.node_count};let D=v.length,W=Array(D),O=new Map,E=[],j=0,z=o.nodes,V=z.length;for(let L=0;L<V;L+=N){let A=z[L+m],F=z[L+C]??0;j+=F;let M;if(A>=0&&A<D){if(M=W[A],M===void 0)M={type:v[A],count:0,bytes:0},W[A]=M,E.push(M)}else{let H=`unknown(${A})`;if(M=O.get(H),M===void 0)M={type:H,count:0,bytes:0},O.set(H,M),E.push(M)}M.count++,M.bytes+=F}let _=E.sort((L,A)=>A.count-L.count),J=_.slice(0,20),K=_.slice(20),G=J.map(({type:L,count:A,bytes:F})=>({type:L,count:A,retainedBytes:F}));if(K.length>0){let L=0,A=0;for(let F of K)L+=F.count,A+=F.bytes;G.push({type:"other",count:L,retainedBytes:A})}return{origin:U,heapSizeBytes:j,objectCount:o.snapshot.node_count,typeCounts:G}}function Je(o,U,c){let R=["--heap-prof","--heap-prof-dir",U,"--heap-prof-name",c],m=o[0];if(m==="bun"||m?.endsWith("/bun"))return[m,...R,...o.slice(1)];return o}async function be(o){let U=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],R=c==="bun"||c?.endsWith("/bun"),m=Je(o.argv,o.artifactDir,o.fileName),C=R?o.env:{...process.env,...o.env,BUN_OPTIONS:`--heap-prof --heap-prof-dir ${o.artifactDir} --heap-prof-name ${o.fileName}`},N=Bun.nanoseconds(),D=await Bun.spawn(m,{cwd:o.cwd,env:C,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,W=Bun.nanoseconds()-N,O=Bun.file(U);if(!await O.exists())return{diagnosticWallNs:W,exitCode:D,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${U} after exit ${D}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:U,argv:o.argv}}]};let E=await O.json(),j=he(E,"heap-prof");return{diagnosticWallNs:W,exitCode:D,artifactPath:U,heap:j,warnings:[]}}import{Session as ze}from"inspector/promises";var Ve=1000;async function ye(o,U={}){let c=U.intervalUs??Ve,R=new ze;R.connect();let m=Bun.nanoseconds();try{await R.post("Profiler.enable"),await R.post("Profiler.setSamplingInterval",{interval:c}),await R.post("Profiler.start");let C=await o(),{profile:N}=await R.post("Profiler.stop"),v=Bun.nanoseconds()-m,D=ae(N,"inspector",c);return{result:C,cpu:D,diagnosticWallNs:v}}finally{R.disconnect()}}import{profile as Ge}from"bun:jsc";var Ke=new Map([["LLInt","llint"],["Baseline","baseline"],["DFG","dfg"],["FTL","ftl"]]),we=4294967295;function xe(o,U){let c=U??o.interval*1e6,R=new Map,m=[];function C(M,H,Y,q){let Q=R.get(M);if(Q===void 0)Q=new Map,R.set(M,Q);let X=H??"",ee=Q.get(X);if(ee===void 0)ee=m.length,Q.set(X,ee),m.push({key:e("fr",M,X),name:M,url:H,line:Y,col:q});return ee}function N(M){let H=M.line===we,Y=H?void 0:M.line-1,q=H||M.column===we?void 0:M.column-1;return C(M.name,M.sourceURL,Y,q)}let v=C("(root)",void 0,void 0,void 0),D=1,W={id:0,frameIx:v,children:new Map,selfUs:0,samples:0,totalUs:0},O=new Map([[0,W]]),E={llint:0,baseline:0,dfg:0,ftl:0},j=new Map,z=[],V=[];for(let M of o.traces){let H=M.frames,Y=W;for(let X=H.length-1;X>=0;X--){let ee=N(H[X]),re=Y.children.get(ee);if(!re)re={id:D++,frameIx:ee,children:new Map,selfUs:0,samples:0,totalUs:0},Y.children.set(ee,re),O.set(re.id,re);Y=re}Y.selfUs+=c,Y.samples+=1,z.push(Y.id),V.push(c);let q=H[0],Q=q&&Ke.get(q.category);if(Q){E[Q]++;let X=j.get(Q)??new Map;X.set(Y.frameIx,(X.get(Y.frameIx)??0)+1),j.set(Q,X)}}function _(M){let H=M.selfUs;for(let Y of M.children.values())H+=_(Y);return M.totalUs=H,H}_(W);let J=new Map;function K(M){let H=J.get(M.frameIx);if(H)H.selfUs+=M.selfUs,H.totalUs+=M.totalUs,H.samples+=M.samples;else J.set(M.frameIx,{frameIx:M.frameIx,selfUs:M.selfUs,totalUs:M.totalUs,samples:M.samples});for(let Y of M.children.values())K(Y)}K(W);let G=[...O.values()].map((M)=>({id:M.id,frameIx:M.frameIx,children:[...M.children.values()].map((H)=>H.id)})),L={origin:"jsc-profile",samplingIntervalUs:c,frames:m,nodes:G,totals:[...J.values()].sort((M,H)=>H.selfUs-M.selfUs),samples:{nodeIds:z,timeDeltasUs:V}},A=[...j.entries()].flatMap(([M,H])=>[...H.entries()].sort((Y,q)=>q[1]-Y[1]).slice(0,3).map(([Y,q])=>({tier:M,frameKey:m[Y].key,samples:q})));return{cpu:L,jit:{origin:"jsc-profile",tiers:E,topFramesByTier:A}}}var Ye=1000;async function Re(o,U={}){let c=U.intervalUs??Ye,R,m=Bun.nanoseconds(),C=await Ge(async()=>(R=await o(),R),c),N=Bun.nanoseconds()-m,{cpu:v,jit:D}=xe(C.stackTraces,c);return{result:R,cpu:v,jit:D,diagnosticWallNs:N}}async function le(o){let U=Bun.nanoseconds(),c=Bun.spawn(o.argv,{cwd:o.cwd,env:o.env,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),R=await c.exited,m=Bun.nanoseconds(),C=c.resourceUsage?.();return{wallNs:m-U,exitCode:R,userNs:C?Number(C.cpuTime.user)*1000:void 0,systemNs:C?Number(C.cpuTime.system)*1000:void 0,maxRssBytes:C?.maxRSS}}function Pe(o){return o.trim().split(/\s+/).filter(Boolean)}var qe=10,Qe=3000000000,Xe=3;async function g(o){let U=o.warmup??Xe;for(let O=0;O<U;O++)await le(o);let c=[],R=o.runs??o.minRuns??qe,m=o.runs!==void 0?0:o.minTotalNs??Qe,C=0,N=0;while(N<R||C<m){let O=await le(o);if(c.push({i:N,wallNs:O.wallNs,exitCode:O.exitCode,userNs:O.userNs,systemNs:O.systemNs,maxRssBytes:O.maxRssBytes}),C+=O.wallNs,N++,o.runs!==void 0&&N>=o.runs)break}let v=c.map((O)=>O.wallNs),D=l(v),W=p(D,c.map((O)=>O.exitCode));return{trials:c,timing:D,warnings:W}}var Te=new URL("./runner.ts",import.meta.url).pathname,Ze="node_modules/.cache/ostia";function w(){return Math.max(1,navigator.hardwareConcurrency||1)}async function en(o,U){let c=new Set;for(let R of o){let m=new Bun.Glob(R);for await(let C of m.scan({cwd:U,absolute:!1}))c.add(C)}return[...c].sort()}function nn(o){if(o===void 0)return;return o==="auto"?w():o}async function P(o,U,c=process.cwd()){return{suites:o.suites.length>0?o.suites:U?.suites?await en(U.suites,c):[],timeBudgetMs:o.timeBudgetMs??U?.timeBudgetMs,minSamples:o.minSamples??U?.minSamples,jobs:o.jobs??nn(U?.jobs),gc:o.gc||(U?.gc??!1),filter:o.filter??U?.filter,isolate:o.isolate||(U?.isolate??!1),preload:o.preload.length>0?o.preload:U?.preload??[],bunFlags:o.bunFlags,outDir:o.outDir??U?.outDir,cwd:c}}async function d(o){let c=`${o.outDir??Ze}/bench-tmp`,R=o.cwd??process.cwd(),m=Math.max(1,Math.floor(o.jobs??1)),C={timeBudgetMs:o.timeBudgetMs,minSamples:o.minSamples,gc:o.gc},N=o.suites.map((O)=>O.startsWith("/")?O:`${R}/${O}`),v=(o.preload??[]).map((O)=>O.startsWith("/")?O:`${R}/${O}`),D=o.bunFlags??[],W=async(O,E)=>{let j=new Set,z=0,V,_=async()=>{while(V===void 0&&z<O.length){let J=z++;try{let K=Bun.spawn(O[J],{cwd:R,stdout:"inherit",stderr:"inherit",stdin:"ignore"});j.add(K);let G=await K.exited;if(j.delete(K),G!==0)throw Error(`Bench suite failed: ${E(J)} (runner exited ${G})`)}catch(K){V??=K instanceof Error?K:Error(String(K));for(let G of j)G.kill()}}};if(await Promise.all(Array.from({length:Math.min(m,O.length)},_)),V)throw V};try{let O=N.map((F)=>`${c}/${e("bench-plan",F)}.json`),E=N.map((F)=>`${c}/${e("bench-primary",F)}.json`),j=N.map((F,M)=>["bun",...D,Te,F,E[M],JSON.stringify({...C,filter:o.filter,isolate:o.isolate,preload:v,planPath:O[M]})]);await W(j,(F)=>o.suites[F]);let z=await Promise.all(O.map(async(F)=>{let{tasks:M}=await Bun.file(F).json();return M})),V=await Promise.all(E.map(t)),_=[];for(let F=0;F<z.length;F++)for(let M of z[F])if(M.isolate)_.push({suiteIndex:F,taskIds:[M.id]});let J=_.map((F,M)=>`${c}/${e("bench-item",N[F.suiteIndex],M)}.json`),K=_.map((F,M)=>["bun",...D,Te,N[F.suiteIndex],J[M],JSON.stringify({...C,taskIds:F.taskIds,preload:v,markIsolated:!0})]);await W(K,(F)=>o.suites[_[F].suiteIndex]);let G=await Promise.all(J.map(t)),L=[],A=[];for(let F=0;F<z.length;F++){let M=V[F],H=0,Y=new Map;_.forEach((q,Q)=>{if(q.suiteIndex===F)Y.set(q.taskIds[0],G[Q])});for(let q of z[F])if(q.isolate){let Q=Y.get(q.id);L.push(Q.workloads[0]),A.push(Q.runs[0])}else L.push(M.workloads[H]),A.push(M.runs[H]),H++}return r(L,A)}finally{await Bun.spawn(["rm","-rf",c]).exited}}function S(o,U,c=8){if(c<=1)throw RangeError(`range: multiplier must be > 1, got ${c}`);if(o<=0)throw RangeError(`range: start must be > 0, got ${o}`);let R=[];for(let m=o;m<=U;m*=c)R.push(m);if(!R.includes(U))R.push(U);return R}var a={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000};function ce(o,U){if(o===0)return U===0?0:1/0;return(U-o)/o*100}function se(o,U,c){return o.runs.find((R)=>R.workloadId===U&&R.phase===c)}function f(o,U,c=a){let R=new Set(U.workloads.map((C)=>C.id)),m=[];for(let C of o.workloads){if(!R.has(C.id))continue;let N=y(o,U,C.id,c);if(N)m.push(N)}return m}function y(o,U,c,R=a){let m=se(o,c,"timing"),C=se(U,c,"timing"),N=se(o,c,"cpu"),v=se(U,c,"cpu"),D=se(o,c,"heap"),W=se(U,c,"heap"),O=m?.id??N?.id??D?.id,E=C?.id??v?.id??W?.id;if(!O||!E)return;let j=!1,z;if(m?.timing&&C?.timing){let J=ce(m.timing.median,C.timing.median),K=ce(m.timing.mean,C.timing.mean),G=J>R.timingPct?"regressed":J<-R.timingPct?"improved":"unchanged";if(G==="regressed")j=!0;z={medianDeltaPct:J,meanDeltaPct:K,verdict:G}}let V;if(N?.cpu&&v?.cpu){let J=new Map(N.cpu.totals.map((F)=>[N.cpu.frames[F.frameIx].key,F])),K=new Map(v.cpu.totals.map((F)=>[v.cpu.frames[F.frameIx].key,F])),G=new Map(N.cpu.frames.map((F)=>[F.key,F.name])),L=new Map(v.cpu.frames.map((F)=>[F.key,F.name]));V=[...new Set([...J.keys(),...K.keys()])].map((F)=>{let M=J.get(F)?.selfUs??0,H=K.get(F)?.selfUs??0;return{frameKey:F,name:L.get(F)??G.get(F)??F,baseSelfUs:M,candSelfUs:H,deltaPct:ce(M,H)}}).sort((F,M)=>Math.abs(M.deltaPct)-Math.abs(F.deltaPct));for(let F of V)if((F.baseSelfUs>=R.minFrameSelfUs||F.candSelfUs>=R.minFrameSelfUs)&&F.deltaPct>R.frameSelfPct)j=!0}let _;if(D?.heap&&W?.heap){let J=new Map(D.heap.typeCounts.map((L)=>[L.type,L])),K=new Map(W.heap.typeCounts.map((L)=>[L.type,L]));_=[...new Set([...J.keys(),...K.keys()])].map((L)=>{let A=J.get(L),F=K.get(L);return{type:L,baseCount:A?.count??0,candCount:F?.count??0,baseBytes:A?.retainedBytes,candBytes:F?.retainedBytes,deltaPct:ce(A?.count??0,F?.count??0)}}).sort((L,A)=>Math.abs(A.deltaPct)-Math.abs(L.deltaPct));for(let L of _)if(L.deltaPct>R.heapTypePct)j=!0}return{id:e("cmp",O,E),baselineRunId:O,candidateRunId:E,timing:z,frames:V,heapTypes:_,thresholds:R,verdict:j?"fail":"pass"}}function ne(o,U){if(U){let c=o.runs.find((R)=>R.id===U);return c?.cpu?[c]:[]}return o.runs.filter((c)=>c.phase==="cpu"&&c.cpu)}function oe(o){let U=o.nodes,c=U.length,R=tn(o),m=new Int32Array(c).fill(-1);for(let D=0;D<c;D++)for(let W of U[D].children){let O=R(W);if(O!==-1)m[O]=D}let C=[];for(let D=0;D<c;D++)if(m[D]===-1)C.push(D);let N=[],v=[];for(let D=C.length-1;D>=0;D--)v.push(C[D]);while(v.length>0){let D=v.pop();N.push(D);for(let W of U[D].children){let O=R(W);if(O!==-1&&m[O]===D)v.push(O)}}return{count:c,indexOf:R,parentIx:m,roots:C,order:N}}function tn(o){let U=o.nodes,c=U.length,R=1/0,m=-1/0,C=!0;for(let v=0;v<c;v++){let D=U[v].id;if(!Number.isInteger(D)){C=!1;break}if(D<R)R=D;if(D>m)m=D}if(C&&c>0&&m-R<c*4+64){let v=m-R+1,D=new Int32Array(v).fill(-1);for(let W=0;W<c;W++)D[U[W].id-R]=W;return(W)=>{let O=W-R;return O>=0&&O<v?D[O]:-1}}let N=new Map;for(let v=0;v<c;v++)N.set(U[v].id,v);return(v)=>N.get(v)??-1}function $e(o,U){let{count:c,indexOf:R,parentIx:m,order:C}=U,N=new Float64Array(c),v=new Float64Array(c),D=o.samples?.nodeIds??[],W=o.samples?.timeDeltasUs??[];for(let E=0;E<D.length;E++){let j=R(D[E]);if(j===-1)continue;N[j]+=W[E]??0,v[j]+=1}let O=new Float64Array(c);for(let E=C.length-1;E>=0;E--){let j=C[E];O[j]+=N[j];let z=m[j];if(z>=0)O[z]+=O[j]}return{selfUs:N,totalUs:O,samples:v}}var ke={name:"collapsed",async render(o,U={}){return{files:ne(o,U.runId).map((m)=>{let C=m.cpu,{nodes:N,frames:v}=C,D=oe(C),W=Array(D.count);for(let V of D.order){let _=v[N[V].frameIx].name||"(anonymous)",J=D.parentIx[V];W[V]=J===-1?_:`${W[J]};${_}`}let O=new Float64Array(D.count),E=[],j=C.samples?.nodeIds??[];for(let V=0;V<j.length;V++){let _=D.indexOf(j[V]);if(_===-1)continue;if(O[_]++===0)E.push(_)}let z=Array(E.length);for(let V=0;V<E.length;V++){let _=E[V];z[V]=`${W[_]} ${O[_]}`}return{path:`${m.id}.collapsed.txt`,content:z.join(`
|
|
3
|
+
`)+(z.length>0?`
|
|
4
|
+
`:"")}})}}};var Ie={name:"cpuprofile",async render(o,U={}){let c=ne(o,U.runId),R=[],m=[];for(let C of c){if(C.cpu?.origin!=="cpu-prof"&&C.cpu?.origin!=="inspector"){m.push(`${C.id} (origin ${C.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let N=C.artifacts.find((D)=>D.kind==="cpuprofile");if(!N){m.push(`${C.id} (no cpuprofile artifact recorded on this run)`);continue}let v=Bun.file(N.path);if(!await v.exists()){m.push(`${C.id} (artifact missing on disk: ${N.path})`);continue}R.push({path:`${C.id}.cpuprofile`,content:await v.text()})}if(R.length===0&&m.length>0)return{text:`No .cpuprofile artifacts available:
|
|
5
|
+
${m.map((C)=>` - ${C}`).join(`
|
|
6
|
+
`)}
|
|
7
|
+
`};return{files:R}}};var ve={name:"json",async render(o){return{text:x(o)}}};var Ce={name:"jsonl",async render(o){let{runs:U,...c}=o;return{text:`${[h(c),...U.map((m)=>h(m))].join(`
|
|
8
|
+
`)}
|
|
9
|
+
`}}};function te(o){return(o/1e6).toFixed(3)}function ue(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??o?.id??"unknown"}var Ne=10,Ue=10,De={name:"markdown",async render(o){let U=new Map(o.workloads.map((m)=>[m.id,m])),c=[];c.push("# Profile Report",""),c.push(`Bun ${o.bunVersion} \xB7 ostia ${o.toolVersion} \xB7 ${o.platform.os}/${o.platform.arch} \xB7 ${o.createdAt}`,"");let R=o.runs.filter((m)=>m.phase==="timing"&&m.timing!==void 0);if(R.length>0){c.push("## Timing",""),c.push("| Command | Mean \xB1 SD (ms) | Min\u2026Max (ms) | Median (ms) |","|---|---|---|---|");for(let C of R){let N=ue(U.get(C.workloadId)),v=C.timing;c.push(`| ${N} | ${te(v.mean)} \xB1 ${te(v.stddev)} | ${te(v.min)}\u2026${te(v.max)} | ${te(v.median)} |`)}c.push("");let m=R.filter((C)=>C.warnings.length>0);if(m.length>0){c.push("### Warnings","");for(let C of m){let N=ue(U.get(C.workloadId));for(let v of C.warnings)c.push(`- **${N}**: ${v.message} (\`${v.code}\`)`)}c.push("")}}for(let m of o.runs){if(m.phase!=="cpu"&&m.phase!=="heap")continue;let C=ue(U.get(m.workloadId));if(m.phase==="cpu"){if(c.push(`## CPU capture - ${C}`,""),c.push(`instrumented, diagnostic wall ${te(m.diagnosticWallNs??0)}ms`,""),m.cpu){c.push(`origin: \`${m.cpu.origin}\`, interval: ${m.cpu.samplingIntervalUs}\xB5s`,""),c.push("| Self % | Self (ms) | Total (ms) | Frame |","|---|---|---|---|");let N=m.cpu.totals.reduce((v,D)=>v+D.selfUs,0)||1;for(let v of m.cpu.totals.slice(0,Ne)){let D=m.cpu.frames[v.frameIx],W=(v.selfUs/N*100).toFixed(1);c.push(`| ${W}% | ${(v.selfUs/1000).toFixed(2)} | ${(v.totalUs/1000).toFixed(2)} | ${D?.name||"(anonymous)"} |`)}if(c.push(""),m.jit){let v=m.jit.tiers;c.push(`JIT tiers: LLInt ${v.llint} \xB7 Baseline ${v.baseline} \xB7 DFG ${v.dfg} \xB7 FTL ${v.ftl}`,"")}}}else if(c.push(`## Heap snapshot - ${C}`,""),c.push(`instrumented, diagnostic wall ${te(m.diagnosticWallNs??0)}ms`,""),m.heap){c.push(`${m.heap.objectCount??"?"} objects, ${((m.heap.heapSizeBytes??0)/1e6).toFixed(2)}MB`,""),c.push("| Count | Type |","|---|---|");for(let N of m.heap.typeCounts.slice(0,Ue))c.push(`| ${N.count} | ${N.type} |`);c.push("")}for(let N of m.artifacts)c.push(`- artifact: \`${N.path}\``);for(let N of m.warnings)c.push(`- ! ${N.message} (\`${N.code}\`)`);if(m.artifacts.length>0||m.warnings.length>0)c.push("")}if(o.comparisons&&o.comparisons.length>0){c.push("## Comparisons","");for(let m of o.comparisons){let C=o.runs.find((v)=>v.id===m.candidateRunId),N=ue(C?U.get(C.workloadId):void 0);if(c.push(`### ${m.verdict==="pass"?"\u2713":"\u2717"} ${N}`,""),m.timing){let v=m.timing.medianDeltaPct>0?"+":"";c.push(`- timing: ${v}${m.timing.medianDeltaPct.toFixed(1)}% median (**${m.timing.verdict}**)`)}for(let v of m.frames?.slice(0,Ne)??[]){if(Math.abs(v.deltaPct)<0.5)continue;let D=v.deltaPct>0?"+":"";c.push(`- frame \`${v.name}\`: ${D}${v.deltaPct.toFixed(1)}% self-time (${(v.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(v.candSelfUs/1000).toFixed(2)}ms)`)}for(let v of m.heapTypes?.slice(0,Ue)??[]){if(Math.abs(v.deltaPct)<0.5)continue;let D=v.deltaPct>0?"+":"";c.push(`- heap \`${v.type}\`: ${D}${v.deltaPct.toFixed(1)}% count (${v.baseCount} \u2192 ${v.candCount})`)}c.push("")}}return{text:c.join(`
|
|
10
|
+
`)}}};var rn=15;function me(o){return`n${o}`}function sn(o,U,c){return`${(o||"(anonymous)").replace(/"/g,"'")} (self ${(U/1000).toFixed(2)}ms, total ${(c/1000).toFixed(2)}ms)`}function on(o,U,c,R){let m=[];if(R<=0)return m;for(let C=0;C<U;C++){if(C===c)continue;let N=o[C];if(m.length===R&&N<=o[m[R-1]])continue;let v=m.length;while(v>0&&o[m[v-1]]<N)v--;if(m.splice(v,0,C),m.length>R)m.pop()}return m}var Fe={name:"mermaid",async render(o,U={}){let c=U.topN??rn;return{files:ne(o,U.runId).map((C)=>{let N=C.cpu,{nodes:v,frames:D}=N,W=oe(N),{selfUs:O,totalUs:E}=$e(N,W),{parentIx:j}=W,z=W.roots[0]??-1,V=on(O,W.count,z,c),_=new Set(z!==-1?[z]:[]),J=[];for(let G of V){J.length=0;for(let L=G;L!==-1;L=j[L])J.push(L);for(let L=J.length-1;L>=0;L--)_.add(J[L])}let K=["graph TD"];for(let G of _){let L=v[G].id;K.push(` ${me(L)}["${sn(D[v[G].frameIx].name,O[G],E[G])}"]`)}for(let G of _){let L=j[G];if(L!==-1&&_.has(L))K.push(` ${me(v[L].id)} --> ${me(v[G].id)}`)}return{path:`${C.id}.mermaid.md`,content:`${K.join(`
|
|
11
|
+
`)}
|
|
12
|
+
`}})}}};function Me(o){if(!o?.entry)return;if(o.entry.group!==void 0)return o.entry.group;let U=o.entry.task,c=U.lastIndexOf("/");return c===-1?void 0:U.slice(0,c)}function pe(o){let U=Math.min(...o.map((m)=>m.run.timing.median)),c=new Map;for(let m of o){let C=Me(m.workload);if(C===void 0)continue;let N=c.get(C);if(N)N.push(m);else c.set(C,[m])}let R=new Map;for(let m of o){let C=Me(m.workload);if(C===void 0){R.set(m,U);continue}let N=c.get(C)??[m],v=N.find((D)=>D.workload?.baseline);R.set(m,v?v.run.timing.median:Math.min(...N.map((D)=>D.run.timing.median)))}return R}function Z(o){return Number.isFinite(o)?Number(o.toPrecision(6)):o}function an(o,U){return o?.entry?.task??o?.label??o?.command?.join(" ")??U.workloadId}function cn(o){let U=new Map(o.workloads.map((C)=>[C.id,C])),c=o.runs.filter((C)=>C.phase==="timing"&&C.timing!==void 0).map((C)=>({run:C,workload:U.get(C.workloadId)})),R=c.length>1?pe(c):void 0,m=new Map((o.comparisons??[]).map((C)=>[C.candidateRunId,C]));return c.map((C)=>{let{run:N,workload:v}=C,D=N.timing,W={task:an(v,N),unit:"ns",samples:D.samples.length,mean:Z(D.mean),median:Z(D.median),stddev:Z(D.stddev),stddevPct:Z(D.mean===0?0:D.stddev/D.mean*100),min:Z(D.min),max:Z(D.max),warnings:N.warnings.map((E)=>E.data?{code:E.code,data:E.data}:{code:E.code})};if(v?.entry?.group!==void 0)W.group=v.entry.group;if(v?.description!==void 0)W.description=v.description;if(v?.groupDescription!==void 0)W.groupDescription=v.groupDescription;if(R)W.relative=Z(D.median/(R.get(C)??D.median));if(v?.baseline)W.baseline=!0;let O=m.get(N.id);if(O?.timing)W.delta={medianPct:Z(O.timing.medianDeltaPct),meanPct:Z(O.timing.meanDeltaPct),verdict:O.timing.verdict,pass:O.verdict==="pass"};return W})}var Se={name:"minimal",async render(o){let U=cn(o).map((c)=>JSON.stringify(c));return{text:U.length>0?`${U.join(`
|
|
13
|
+
`)}
|
|
14
|
+
`:""}}};var un="https://www.speedscope.app/file-format-schema.json";function Be(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??"profile"}var Oe={name:"speedscope",async render(o,U={}){let c=ne(o,U.runId),R=new Map(o.workloads.map((C)=>[C.id,C]));return{files:c.map((C)=>{let N=C.cpu,{nodes:v}=N,D=oe(N),W=N.samples?.nodeIds??[],O=N.samples?.timeDeltasUs??[],E=Array(D.count);for(let _ of D.order){let J=D.parentIx[_],K=v[_].frameIx;E[_]=J===-1?[K]:[...E[J],K]}let j=Array(W.length);for(let _=0;_<W.length;_++){let J=D.indexOf(W[_]);j[_]=J===-1?[]:E[J]}let z=0;for(let _=0;_<O.length;_++)z+=O[_];let V={$schema:un,exporter:"ostia",name:Be(R.get(C.workloadId)),activeProfileIndex:0,shared:{frames:N.frames.map((_)=>({name:_.name||"(anonymous)",file:_.url,line:_.line!==void 0?_.line+1:void 0}))},profiles:[{type:"sampled",name:Be(R.get(C.workloadId)),unit:"microseconds",startValue:0,endValue:z,samples:j,weights:O}]};return{path:`${C.id}.speedscope.json`,content:`${JSON.stringify(V,null,2)}
|
|
15
|
+
`}})}}};function ie(o){return(o/1e6).toFixed(3)}function de(o){return o.label??o.command?.join(" ")??o.entry?.task??o.id}var Ee={name:"table",async render(o){let U=o.runs.filter((E)=>E.phase==="timing"&&E.timing!==void 0),c=new Map(o.workloads.map((E)=>[E.id,E]));if(U.length===0){let E=We(o,c);return{text:E.length>0?`${E.join(`
|
|
16
|
+
`)}
|
|
17
|
+
`:`(no timing runs)
|
|
18
|
+
`}}let R=U.map((E)=>{let j=c.get(E.workloadId);return{run:E,workload:j,label:j?de(j):E.workloadId}}),m=R.length>1,C=pe(R),N=[],v=Math.max(7,...R.map((E)=>E.label.length)),D=m?`${"Command".padEnd(v)} Mean [ms] Min\u2026Max [ms] Relative`:`${"Command".padEnd(v)} Mean [ms] Min\u2026Max [ms]`;N.push(D),N.push("-".repeat(D.length));for(let E of R){let{run:j,label:z,workload:V}=E,_=j.timing,J=`${ie(_.mean)} \xB1 ${ie(_.stddev)}`,K=`${ie(_.min)}\u2026${ie(_.max)}`,G=`${z.padEnd(v)} ${J.padEnd(15)} ${K.padEnd(18)}`;if(m){let L=_.median/(C.get(E)??_.median);if(L===1)G+=V?.baseline?" 1.00\xD7 (baseline)":" 1.00\xD7";else if(L>1)G+=` ${L.toFixed(2)}\xD7 slower`;else G+=` ${(1/L).toFixed(2)}\xD7 faster`}N.push(G);for(let L of j.warnings)N.push(` ! ${L.message}`)}let W=ln(o,c);if(W.length>0)N.push(""),N.push(...W);let O=We(o,c);if(O.length>0)N.push(""),N.push(...O);return{text:`${N.join(`
|
|
19
|
+
`)}
|
|
20
|
+
`}}};function pn(o,U,c){let R=o.runs.find((C)=>C.id===c),m=R?U.get(R.workloadId):void 0;return m?de(m):c}function We(o,U){if(!o.comparisons||o.comparisons.length===0)return[];let c=[];for(let R of o.comparisons){let m=pn(o,U,R.candidateRunId),C=R.verdict==="pass"?"\u2713":"\u2717";if(c.push(`${C} ${m}`),R.timing){let N=R.timing.medianDeltaPct>0?"+":"";c.push(` timing: ${N}${R.timing.medianDeltaPct.toFixed(1)}% median (${R.timing.verdict})`)}if(R.frames)for(let N of R.frames.slice(0,Ae)){if(Math.abs(N.deltaPct)<0.5)continue;let v=N.deltaPct>0?"+":"";c.push(` frame ${N.name}: ${v}${N.deltaPct.toFixed(1)}% self-time (${(N.baseSelfUs/1000).toFixed(2)}ms -> ${(N.candSelfUs/1000).toFixed(2)}ms)`)}if(R.heapTypes)for(let N of R.heapTypes.slice(0,je)){if(Math.abs(N.deltaPct)<0.5)continue;let v=N.deltaPct>0?"+":"";c.push(` heap ${N.type}: ${v}${N.deltaPct.toFixed(1)}% count (${N.baseCount} -> ${N.candCount})`)}}return c}var Ae=5,je=5;function ln(o,U){let c=[];for(let R of o.runs){if(R.phase!=="cpu"&&R.phase!=="heap")continue;let m=U.get(R.workloadId),C=m?de(m):R.workloadId;if(R.phase==="cpu")if(R.cpu){c.push(`CPU capture - ${C} (instrumented, ${R.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${ie(R.diagnosticWallNs??0)}ms)`);let N=R.cpu.totals.reduce((v,D)=>v+D.selfUs,0)||1;for(let v of R.cpu.totals.slice(0,Ae)){let D=R.cpu.frames[v.frameIx],W=(v.selfUs/N*100).toFixed(1);c.push(` ${W.padStart(5)}% ${(v.selfUs/1000).toFixed(2).padStart(8)}ms self ${D?.name??"?"}`)}}else c.push(`CPU capture - ${C} (instrumented, no evidence captured)`);else if(R.heap){let N=((R.heap.heapSizeBytes??0)/1e6).toFixed(2);c.push(`Heap snapshot - ${C} (instrumented, ${R.heap.objectCount??"?"} objects, ${N}MB)`);for(let v of R.heap.typeCounts.slice(0,je))c.push(` ${String(v.count).padStart(6)} ${v.type}`)}else c.push(`Heap snapshot - ${C} (instrumented, no evidence captured)`);for(let N of R.artifacts)c.push(` artifact: ${N.path}`);for(let N of R.warnings)c.push(` ! ${N.message}`)}return c}var n={table:Ee,json:ve,markdown:De,jsonl:Ce,minimal:Se,collapsed:ke,mermaid:Fe,speedscope:Oe,cpuprofile:Ie};var mn="node_modules/.cache/ostia",fe=1000;async function k(o){let U=s({runs:o.runs??null,warmup:o.warmup??null,cpu:o.cpu??!1,heap:o.heap??!1,cpuIntervalUs:o.cpuIntervalUs??fe}),R=`${o.outDir??mn}/artifacts`,m=[],C=[];for(let N of o.commands){let v=Array.isArray(N)?N:Pe(N),D=u(v,Array.isArray(N)?void 0:N);m.push(D);let W=await g({argv:v,cwd:o.cwd,env:o.env,runs:o.runs,warmup:o.warmup}),O=i({workload:D,configFingerprint:U,trials:W.trials,timing:W.timing,warnings:W.warnings});if(C.push(O),o.cpu){let E=`${O.id}-cpu.cpuprofile`,j=await ge({argv:v,cwd:o.cwd,env:o.env,artifactDir:R,fileName:E,intervalUs:o.cpuIntervalUs??fe});C.push(await _e({workload:D,phase:"cpu",configFingerprint:U,diagnosticWallNs:j.diagnosticWallNs,exitCode:j.exitCode,cpu:j.cpu,artifactPath:j.artifactPath,artifactKind:"cpuprofile",warnings:j.warnings}))}if(o.heap){let E=`${O.id}-heap.heapsnapshot`,j=await be({argv:v,cwd:o.cwd,env:o.env,artifactDir:R,fileName:E});C.push(await _e({workload:D,phase:"heap",configFingerprint:U,diagnosticWallNs:j.diagnosticWallNs,exitCode:j.exitCode,heap:j.heap,artifactPath:j.artifactPath,artifactKind:"heapsnapshot",warnings:j.warnings}))}}return r(m,C)}async function _e(o){let U=`${o.workload.id}-${o.phase}-${o.configFingerprint}`,c=o.artifactPath?[await I(U,o.artifactKind,o.artifactPath)]:[];return b({workload:o.workload,phase:o.phase,configFingerprint:o.configFingerprint,diagnosticWallNs:o.diagnosticWallNs,exitCode:o.exitCode,cpu:o.cpu,heap:o.heap,warnings:o.warnings,artifacts:c})}async function B(o,U={}){let c=T(o),R=s({intervalUs:U.intervalUs??fe,origin:U.origin??"inspector"}),m=(W)=>W.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(U.origin==="jsc"){let{result:W,cpu:O,jit:E,diagnosticWallNs:j}=await Re(o,U),z=b({workload:c,phase:"cpu",configFingerprint:R,diagnosticWallNs:j,cpu:O,jit:E,warnings:m(O),artifacts:[]});return{result:W,run:z}}let{result:C,cpu:N,diagnosticWallNs:v}=await ye(o,U),D=b({workload:c,phase:"cpu",configFingerprint:R,diagnosticWallNs:v,cpu:N,warnings:m(N),artifacts:[]});return{result:C,run:D}}
|
|
21
|
+
export{w,P,d,a,f,y,g,S,n,k,B};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
function h(n){return JSON.stringify(
|
|
3
|
-
`}async function o(n,a){await Bun.write(a,
|
|
4
|
-
export{h,e,c,r,u,
|
|
2
|
+
function h(n){return JSON.stringify(O(n))}function O(n){if(Array.isArray(n))return n.map(O);if(n!==null&&typeof n==="object"){let a={};for(let d of Object.keys(n).sort())a[d]=O(n[d]);return a}return n}function e(n,...a){let d=Bun.CryptoHasher.hash("sha256",h(a),"hex");return`${n}_${d.slice(0,16)}`}var c="0.1.0";function r(n,a){return{schemaVersion:1,toolVersion:c,bunVersion:Bun.version,platform:{os:process.platform,arch:process.arch},createdAt:new Date().toISOString(),workloads:n,runs:a}}function u(n,a){return{id:e("wl","subprocess",n,process.cwd()),kind:"subprocess",command:n,label:a}}function T(n,a){return{id:e("wl","inprocess",n.name,n.toString()),kind:"inprocess",label:a}}function C(n,a,d={}){return{id:e("wl","inprocess-entry",n,a),kind:"inprocess",entry:{file:n,task:a,...d.group!==void 0&&{group:d.group}},...d.label!==void 0&&{label:d.label},...d.baseline!==void 0&&{baseline:d.baseline},...d.description!==void 0&&{description:d.description},...d.groupDescription!==void 0&&{groupDescription:d.groupDescription},...d.isolated!==void 0&&{isolated:d.isolated}}}function i(n){return{id:e("run",n.workload.id,"timing",n.configFingerprint,Bun.version,c),workloadId:n.workload.id,phase:"timing",instrumented:!1,configFingerprint:n.configFingerprint,trials:n.trials,timing:n.timing,warnings:n.warnings,artifacts:[],memory:Q(n.trials)}}function Q(n){let a=n.map((d)=>d.maxRssBytes).filter((d)=>d!==void 0);if(a.length===0)return;return{origin:"resourceUsage",perTrial:n.map((d)=>({rssBytes:d.maxRssBytes})),maxRssBytes:Math.max(...a)}}function b(n){return{id:e("run",n.workload.id,n.phase,n.configFingerprint,Bun.version,c),workloadId:n.workload.id,phase:n.phase,instrumented:!0,configFingerprint:n.configFingerprint,trials:[{i:0,wallNs:n.diagnosticWallNs,exitCode:n.exitCode}],diagnosticWallNs:n.diagnosticWallNs,cpu:n.cpu,heap:n.heap,jit:n.jit,warnings:n.warnings,artifacts:n.artifacts}}async function I(n,a,d){let f=await Bun.file(d).arrayBuffer(),k=new Bun.CryptoHasher("sha256");return k.update(f),{id:e("art",n,a,d),kind:a,path:d,sha256:k.digest("hex"),bytes:f.byteLength}}function s(n){return e("cfg",n)}function x(n){return`${JSON.stringify(O(n),null,2)}
|
|
3
|
+
`}async function o(n,a){await Bun.write(a,x(n))}async function t(n){let a=await Bun.file(n).text();return JSON.parse(a)}var G=[],W;function U(n,a,d){let g=W;W={name:n,description:d?.description,isolate:d?.isolate,gc:d?.gc};try{a()}finally{W=g}}function M(n,a,d){G.push({groupName:W?.name,groupDescription:W?.description,groupIsolate:W?.isolate,groupGc:W?.gc,name:n,fn:a,baseline:d?.baseline,opts:d})}function N(){return G}function v(){G.length=0,W=void 0}function m(n){return n.groupName?`${n.groupName}/${n.name}`:n.name}function R(n,a){return n.opts?.isolate??n.groupIsolate??a}function D(n,a){return n.opts?.gc??n.groupGc??a}function F(n,a){if(!a)return[...n];let d=new RegExp(a);return n.filter((g)=>d.test(m(g)))}function l(n){if(n.length===0)throw Error("computeTimingStats: samples must be non-empty");let a=n.length,d=L(n),g=0;for(let y=0;y<a;y++)g+=n[y];let f=g/a,k=B(d,0.5),w=0;for(let y=0;y<a;y++){let S=n[y]-f;w+=S*S}let P=Math.sqrt(w/a),H=d[0],E=d[a-1],q=B(d,0.25),_=B(d,0.75),A=_-q,z=q-1.5*A,V=_+1.5*A,K=q-3*A,Z=_+3*A,J=0,j=0;for(let y=0;y<a;y++){let S=n[y];if(S<K||S>Z)j++;else if(S<z||S>V)J++}return{unit:"ns",samples:n,mean:f,median:k,stddev:P,min:H,max:E,outliers:{mild:J,severe:j}}}function L(n){let a=new Float64Array(n.length);return a.set(n),a.sort(),a}function B(n,a){let d=n.length;if(d===1)return n[0];let g=a*(d-1),f=Math.floor(g),k=Math.ceil(g);if(f===k)return n[f];let w=g-f;return n[f]*(1-w)+n[k]*w}var X=5000000,Y=200;function p(n,a,d="subprocess"){let g=[],f=n.samples[0];if(f!==void 0){let w=L(n.samples),P=B(w,0.25),E=B(w,0.75)-P;if(f>n.median+3*E&&E>0)g.push({code:"slow-first-run",message:`First run took ${(f/1e6).toFixed(2)}ms, much slower than the median ${(n.median/1e6).toFixed(2)}ms. Consider more warmup.`,data:{firstNs:f,medianNs:n.median}})}if(n.outliers.mild+n.outliers.severe>0)g.push({code:"outliers-detected",message:`${n.outliers.mild+n.outliers.severe} outlier(s) detected (${n.outliers.severe} severe, ${n.outliers.mild} mild).`,data:n.outliers});if(d==="subprocess"&&n.median<X)g.push({code:"fast-command",message:`Median run time (${(n.median/1e6).toFixed(3)}ms) is very fast; results may be dominated by spawn overhead.`,data:{medianNs:n.median}});if(d==="inprocess"&&n.median<Y)g.push({code:"below-timer-resolution",message:`Median run time (${n.median.toFixed(0)}ns) is close to timer resolution; consider a larger batch size or a coarser operation.`,data:{medianNs:n.median}});let k=a.filter((w)=>w!==void 0&&w!==0);if(k.length>0)g.push({code:"nonzero-exit",message:`${k.length} of ${a.length} trial(s) exited non-zero.`,data:{exitCodes:k}});return g}
|
|
4
|
+
export{h,e,c,r,u,T,C,i,b,I,s,x,o,t,l,p,U,M,N,v,m,R,D,F};
|
package/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{
|
|
4
|
-
`)}var
|
|
3
|
+
import{w,P,d,a,f,y,g,n,k}from"./chunk-3qbcj1m9.js";import{e,c,r,u,i,s,o,t}from"./chunk-zrck2q0b.js";function L(p){return e("cache",p.workloadId,p.phase,p.configFingerprint,p.bunVersion,p.toolVersion,p.instrumented,p.inputsDigest??null)}async function W(p,l=process.cwd()){if(p.length===0)return;let m=new Set;for(let b of p){let C=new Bun.Glob(b);for await(let j of C.scan({cwd:l,absolute:!1}))m.add(j)}let x=[...m].sort(),h=await Promise.all(x.map(async(b)=>{let C=await Bun.file(`${l}/${b}`).arrayBuffer();return{path:b,sha256:Bun.CryptoHasher.hash("sha256",C,"hex")}}));return e("inputs",h)}function z(p,l){return`${p}/cache/${l}.json`}async function M(p,l){let m=Bun.file(z(p,l));if(!await m.exists())return;return await m.json()}async function V(p,l,m){await Bun.write(z(p,l),`${JSON.stringify(m,null,2)}
|
|
4
|
+
`)}var Y="node_modules/.cache/ostia",ee=".ostia/baselines",te={runs:null,warmup:3,outDir:Y,baselineDir:ee,baseline:"main",cpuIntervalUs:1000,thresholds:a,workloads:[]};async function q(p="ostia.config.json"){let l=Bun.file(p);if(!await l.exists())return;let m=await l.json();return{...te,...m,thresholds:{...a,...m.thresholds??{}}}}function G(p,l){return`${p.baselineDir}/${l??p.baseline}.json`}class U 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 K(p){let{config:l}=p,m=G(l,p.baselineName);if(!await Bun.file(m).exists())throw new U(m);let h=await t(m),b=[],C=0,j=0,F=0;for(let R of l.workloads){let E=u(R.command,R.label),N=await W(R.inputs??[]),I=s({runs:l.runs,warmup:l.warmup}),S=L({workloadId:E.id,phase:"timing",configFingerprint:I,bunVersion:Bun.version,toolVersion:c,instrumented:!1,inputsDigest:N}),_=p.full?void 0:await M(l.outDir,S),O,H;if(_)O=_,H="cached",j++;else{C++;let J=await g({argv:R.command,runs:l.runs??void 0,warmup:l.warmup});O=i({workload:E,configFingerprint:I,trials:J.trials,timing:J.timing,warnings:J.warnings}),await V(l.outDir,S,O),H="executed",F++}b.push({workload:E,status:H,run:O})}let D=r(b.map((R)=>R.workload),b.map((R)=>R.run)),v=0,B=0,A=0;for(let R of b){let E=y(h,D,R.workload.id,l.thresholds);if(!E){A++;continue}if(R.comparison=E,E.verdict==="pass")v++;else B++}return D.comparisons=b.map((R)=>R.comparison).filter((R)=>R!==void 0),{document:D,summary:{total:l.workloads.length,affected:C,cached:j,executed:F,passed:v,regressed:B,missingBaseline:A,results:b}}}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 m=p.results.filter((x)=>x.comparison?.verdict==="fail").map((x)=>{let h=x.comparison.timing,b=x.workload.label??x.workload.command?.join(" ")??x.workload.id;return h?`${h.medianDeltaPct>0?"+":""}${h.medianDeltaPct.toFixed(1)}% median on ${b}`:b});return l.push(`${p.passed} passed ${p.regressed} regressed${m.length>0?` (${m.join(", ")})`:""}`),l.push(""),l.push(`Profile CI: ${p.regressed>0?"\u2717":"\u2713"}`),`${l.join(`
|
|
5
5
|
`)}
|
|
6
|
-
`}async function
|
|
6
|
+
`}async function T(p,l){if(p.text)process.stdout.write(p.text);if(!p.files||p.files.length===0)return;if(l)for(let m of p.files){let x=m.path?`${l}/${m.path}`:l;await Bun.write(x,m.content),process.stdout.write(`wrote ${x}
|
|
7
7
|
`)}else if(p.files.length===1)process.stdout.write(p.files[0].content);else for(let m of p.files)process.stdout.write(`--- ${m.path??"(unnamed)"} ---
|
|
8
8
|
${m.content}
|
|
9
|
-
`)}var
|
|
9
|
+
`)}var se=`ostia run [flags] <command...>
|
|
10
10
|
|
|
11
11
|
Run one or more commands N times with warmup and report timing statistics.
|
|
12
12
|
|
|
@@ -30,7 +30,7 @@ Examples:
|
|
|
30
30
|
ostia run --runs 25 --warmup 3 "bun a.ts" "bun b.ts"
|
|
31
31
|
ostia run --cpu --heap "bun src/server.ts"
|
|
32
32
|
ostia run --format json "bun a.ts"
|
|
33
|
-
`,
|
|
33
|
+
`,X=`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).
|
|
@@ -64,6 +64,11 @@ Flags:
|
|
|
64
64
|
subprocess (repeatable; runs in the order given). Use it to
|
|
65
65
|
install globals (jsdom's document/window) or register a
|
|
66
66
|
Bun.plugin() file-loader before the suite's own code runs.
|
|
67
|
+
--bun-flags FLAGS extra flags passed through to the \`bun\` invocation that runs each
|
|
68
|
+
suite file (repeatable; space-separated flags in one value are all
|
|
69
|
+
appended). Useful for packages whose exports map branches on a
|
|
70
|
+
resolution condition Bun doesn't set by default, e.g. Svelte/Vue's
|
|
71
|
+
"browser" vs "default" build: --bun-flags="--conditions=browser"
|
|
67
72
|
--out-dir PATH directory for scratch IPC files (default: node_modules/.cache/ostia)
|
|
68
73
|
--export-json PATH write the full ProfileDocument to PATH
|
|
69
74
|
--format FORMAT table | json | jsonl | markdown | minimal (default: table)
|
|
@@ -95,13 +100,23 @@ generation, default multiplier 8, always ending on the end value):
|
|
|
95
100
|
}
|
|
96
101
|
})
|
|
97
102
|
|
|
103
|
+
Project defaults: with no suite files given on the command line, ostia falls back to
|
|
104
|
+
ostia.config.json's "bench" section in the current directory - suites is a list of globs
|
|
105
|
+
(expanded with Bun.Glob), the rest are the same defaults as their matching flag:
|
|
106
|
+
{ "bench": { "suites": ["bench/**/*.bench.ts"], "preload": ["./bench/setup.ts"], "jobs": "auto" } }
|
|
107
|
+
Any suite files given on the command line replace (not merge with) the config's "suites"
|
|
108
|
+
list; every other flag/config field is overridden individually, so "ostia bench --jobs 1"
|
|
109
|
+
still works as a one-off override without editing the config.
|
|
110
|
+
|
|
98
111
|
Examples:
|
|
99
112
|
ostia bench benches/parse.ts
|
|
100
113
|
ostia bench --time-budget 1000 --min-samples 50 benches/*.ts
|
|
101
114
|
ostia bench benches/*.ts --filter parse
|
|
102
115
|
ostia bench benches/*.ts --jobs auto --format minimal
|
|
103
116
|
ostia bench --preload ./bench/jsdom-setup.ts benches/*.dom.bench.ts
|
|
104
|
-
|
|
117
|
+
ostia bench --bun-flags="--conditions=browser" bench/*.dom.bench.ts
|
|
118
|
+
ostia bench # picks up suites/preload/jobs from ostia.config.json
|
|
119
|
+
`,Q=`ostia compare <base.json> <candidate.json>
|
|
105
120
|
ostia compare <candidate.json> --baseline <path.json>
|
|
106
121
|
|
|
107
122
|
Compare two ProfileDocuments (matched by workload id) and rank timing/frame/heap deltas.
|
|
@@ -119,7 +134,7 @@ Examples:
|
|
|
119
134
|
`,re=`ostia report <document.json> [--format table|json|markdown|jsonl|minimal]
|
|
120
135
|
|
|
121
136
|
Render a saved ProfileDocument.
|
|
122
|
-
`,
|
|
137
|
+
`,ne=`ostia viz <document.json> --format FORMAT [--run <id>] [--out-dir PATH]
|
|
123
138
|
|
|
124
139
|
Render CPU evidence from a saved ProfileDocument as a visualization artifact. Files,
|
|
125
140
|
not a GUI - hand the output to speedscope.app, flamegraph.pl, or
|
|
@@ -140,7 +155,7 @@ Flags:
|
|
|
140
155
|
Examples:
|
|
141
156
|
ostia viz run.json --format speedscope --out-dir node_modules/.cache/ostia/viz
|
|
142
157
|
ostia viz run.json --format collapsed | flamegraph.pl > flame.svg
|
|
143
|
-
`,
|
|
158
|
+
`,oe=`ostia ci [--full] [--baseline NAME]
|
|
144
159
|
|
|
145
160
|
Load ostia.config.json, run configured workloads (reusing cached results when their
|
|
146
161
|
fingerprint is unchanged), compare against the named baseline, and gate on regressions.
|
|
@@ -153,22 +168,22 @@ Flags:
|
|
|
153
168
|
--help show this message
|
|
154
169
|
|
|
155
170
|
Exit codes: 0 pass, 1 regression, 2 harness error (missing config/baseline, spawn failure).
|
|
156
|
-
`;function
|
|
157
|
-
`),2;let m;try{m=await
|
|
158
|
-
`),2}if(l.exportJson)await o(m,l.exportJson);if(!l.quiet){let b=await n[l.format].render(m,{});await
|
|
159
|
-
`),2;if(
|
|
160
|
-
`),2;let
|
|
161
|
-
`),2}if(l.exportJson)await o(
|
|
162
|
-
`),2}let
|
|
163
|
-
`),2}let h=await n[l.format].render(m,{});return await
|
|
171
|
+
`;function ae(p){let l=[],m,x,h=!1,b=!1,C,j,F,D="table",v=!1,B=!1;for(let A=0;A<p.length;A++){let R=p[A];switch(R){case"--runs":m=Number(p[++A]);break;case"--warmup":x=Number(p[++A]);break;case"--cpu":h=!0;break;case"--heap":b=!0;break;case"--cpu-interval":C=Number(p[++A]);break;case"--out-dir":j=p[++A];break;case"--export-json":F=p[++A];break;case"--format":D=p[++A];break;case"--quiet":v=!0;break;case"--help":case"-h":B=!0;break;default:l.push(R)}}return{commands:l,runs:m,warmup:x,cpu:h,heap:b,cpuIntervalUs:C,outDir:j,exportJson:F,format:D,quiet:v,help:B}}async function ie(p){let l=ae(p);if(l.help||l.commands.length===0)return process.stdout.write(se),l.help?0:2;if(!(l.format in n))return process.stderr.write(`Unknown --format "${l.format}". Expected one of: ${Object.keys(n).join(", ")}
|
|
172
|
+
`),2;let m;try{m=await k({commands:l.commands,runs:l.runs,warmup:l.warmup,cpu:l.cpu,heap:l.heap,cpuIntervalUs:l.cpuIntervalUs,outDir:l.outDir})}catch(h){return process.stderr.write(`Run failed: ${h instanceof Error?h.message:String(h)}
|
|
173
|
+
`),2}if(l.exportJson)await o(m,l.exportJson);if(!l.quiet){let b=await n[l.format].render(m,{});await T(b)}return m.runs.some((h)=>h.trials.some((b)=>b.exitCode!==void 0&&b.exitCode!==0))?1:0}function le(p){let l=[],m,x,h,b=!1,C,j=!1,F=[],D=[],v,B,A="table",R=!1,E=!1;for(let N=0;N<p.length;N++){let I=p[N];if(I==="--bun-flags"||I.startsWith("--bun-flags=")){let S=I.startsWith("--bun-flags=")?I.slice(12):p[++N]??"";D.push(...S.split(/\s+/).filter(Boolean));continue}switch(I){case"--time-budget":m=Number(p[++N]);break;case"--min-samples":x=Number(p[++N]);break;case"--jobs":{let S=p[++N];h=S==="auto"?w():Number(S);break}case"--gc":b=!0;break;case"--filter":C=p[++N];break;case"--isolate":j=!0;break;case"--preload":F.push(p[++N]);break;case"--out-dir":v=p[++N];break;case"--export-json":B=p[++N];break;case"--format":A=p[++N];break;case"--quiet":R=!0;break;case"--help":case"-h":E=!0;break;default:l.push(I)}}return{suites:l,timeBudgetMs:m,minSamples:x,jobs:h,gc:b,filter:C,isolate:j,preload:F,bunFlags:D,outDir:v,exportJson:B,format:A,quiet:R,help:E}}async function ue(p){let l=le(p);if(l.help)return process.stdout.write(X),0;if(!(l.format in n))return process.stderr.write(`Unknown --format "${l.format}". Expected one of: ${Object.keys(n).join(", ")}
|
|
174
|
+
`),2;let m=await q(),x=await P(l,m?.bench);if(x.suites.length===0)return process.stdout.write(X),2;if(x.jobs!==void 0&&!(x.jobs>=1))return process.stderr.write(`--jobs expects a positive integer or "auto".
|
|
175
|
+
`),2;let h;try{h=await d(x)}catch(b){return process.stderr.write(`Bench failed: ${b instanceof Error?b.message:String(b)}
|
|
176
|
+
`),2}if(l.exportJson)await o(h,l.exportJson);if(!l.quiet){let C=await n[l.format].render(h,{});await T(C)}return 0}function ce(p){let l=[],m,x,h="table",b=!1,C=!1;for(let j=0;j<p.length;j++){let F=p[j];switch(F){case"--baseline":m=p[++j];break;case"--export-json":x=p[++j];break;case"--format":h=p[++j];break;case"--quiet":b=!0;break;case"--help":case"-h":C=!0;break;default:l.push(F)}}return{paths:l,baseline:m,exportJson:x,format:h,quiet:b,help:C}}async function de(p){let l=ce(p);if(l.help)return process.stdout.write(Q),0;let m,x;if(l.baseline)m=l.baseline,x=l.paths[0];else m=l.paths[0],x=l.paths[1];if(!m||!x)return process.stdout.write(Q),2;let h,b;try{[h,b]=await Promise.all([t(m),t(x)])}catch(D){return process.stderr.write(`Failed to load documents: ${D instanceof Error?D.message:String(D)}
|
|
177
|
+
`),2}let C=f(h,b),j={...b,comparisons:C};if(l.exportJson)await o(j,l.exportJson);if(!l.quiet){let v=await n[l.format].render(j,{});await T(v)}return C.some((D)=>D.verdict==="fail")?1:0}function pe(p){let l,m="table",x=!1;for(let h=0;h<p.length;h++){let b=p[h];switch(b){case"--format":m=p[++h];break;case"--help":case"-h":x=!0;break;default:l=b}}return{path:l,format:m,help:x}}async function me(p){let l=pe(p);if(l.help||!l.path)return process.stdout.write(re),l.help?0:2;let m;try{m=await t(l.path)}catch(b){return process.stderr.write(`Failed to load ${l.path}: ${b instanceof Error?b.message:String(b)}
|
|
178
|
+
`),2}let h=await n[l.format].render(m,{});return await T(h),0}var fe={ascii:"table"};function he(p){let l,m,x,h,b=!1;for(let C=0;C<p.length;C++){let j=p[C];switch(j){case"--format":{let F=p[++C]??"";m=fe[F]??F;break}case"--run":x=p[++C];break;case"--out-dir":h=p[++C];break;case"--help":case"-h":b=!0;break;default:l=j}}return{path:l,format:m,runId:x,outDir:h,help:b}}async function ge(p){let l=he(p);if(l.help||!l.path||!l.format)return process.stdout.write(ne),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
|
|
164
179
|
`),2;let m;try{m=await t(l.path)}catch(b){return process.stderr.write(`Failed to load ${l.path}: ${b instanceof Error?b.message:String(b)}
|
|
165
180
|
`),2}let h=await n[l.format].render(m,{runId:l.runId});if(!h.text&&(!h.files||h.files.length===0))return process.stderr.write(l.runId?`No CPU evidence found for run "${l.runId}".
|
|
166
181
|
`:`No CPU evidence found in this document (no cpu-phase runs). Capture some with "ostia run --cpu ...".
|
|
167
|
-
`),2;return await
|
|
182
|
+
`),2;return await T(h,l.outDir),0}function be(p){let l=!1,m,x,h=!1,b=!1;for(let C=0;C<p.length;C++)switch(p[C]){case"--full":l=!0;break;case"--baseline":m=p[++C];break;case"--export-json":x=p[++C];break;case"--quiet":h=!0;break;case"--help":case"-h":b=!0;break}return{full:l,baseline:m,exportJson:x,quiet:h,help:b}}async function we(p){let l=be(p);if(l.help)return process.stdout.write(oe),0;let m=await q();if(!m)return process.stderr.write(`No ostia.config.json found. "ostia ci" needs configured workloads.
|
|
168
183
|
`),2;if(m.workloads.length===0)return process.stderr.write(`ostia.config.json has no "workloads" configured.
|
|
169
|
-
`),2;let
|
|
184
|
+
`),2;let x;try{x=await K({config:m,full:l.full,baselineName:l.baseline})}catch(h){if(h instanceof U)return process.stderr.write(`${h.message}
|
|
170
185
|
`),2;return process.stderr.write(`CI run failed: ${h instanceof Error?h.message:String(h)}
|
|
171
|
-
`),2}if(l.exportJson)await o(
|
|
186
|
+
`),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 ke(){let[p,...l]=process.argv.slice(2);switch(p){case"run":return ie(l);case"bench":return ue(l);case"compare":return de(l);case"report":return me(l);case"ci":return we(l);case"viz":return ge(l);case void 0:case"--help":case"-h":return process.stdout.write(`ostia - Bun-native profile IR engine
|
|
172
187
|
|
|
173
188
|
Commands:
|
|
174
189
|
run Run commands N times and report timing/CPU/heap
|
|
@@ -180,4 +195,4 @@ Commands:
|
|
|
180
195
|
|
|
181
196
|
Run "ostia <command> --help" for details.
|
|
182
197
|
`),p===void 0?2:0;default:return process.stderr.write(`Unknown subcommand "${p}". Run "ostia --help".
|
|
183
|
-
`),2}}if(import.meta.main)
|
|
198
|
+
`),2}}if(import.meta.main)ke().then((p)=>process.exit(p));
|
package/index.d.ts
CHANGED
|
@@ -263,10 +263,26 @@ interface BenchOptions {
|
|
|
263
263
|
* of the suite's own top-level code. Consumer-authored; ostia ships no
|
|
264
264
|
* preload scripts itself. */
|
|
265
265
|
preload?: string[];
|
|
266
|
+
/** Extra flags passed through to the `bun` invocation that runs each suite
|
|
267
|
+
* file (e.g. `["--conditions", "browser"]`), inserted before the runner
|
|
268
|
+
* script path so `bun` itself parses them rather than the runner. Useful
|
|
269
|
+
* for suites that import packages whose `exports` map branches on a
|
|
270
|
+
* resolution condition Bun doesn't set by default (e.g. Svelte/Vue's
|
|
271
|
+
* `browser` vs `default` builds). */
|
|
272
|
+
bunFlags?: string[];
|
|
266
273
|
}
|
|
267
274
|
|
|
268
275
|
export declare function bench(opts: BenchOptions): Promise<ProfileDocument>;
|
|
269
276
|
|
|
277
|
+
interface Thresholds {
|
|
278
|
+
timingPct: number;
|
|
279
|
+
frameSelfPct: number;
|
|
280
|
+
heapTypePct: number;
|
|
281
|
+
minFrameSelfUs: number;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export declare function compareDocuments(base: ProfileDocument, cand: ProfileDocument, thresholds?: Thresholds): Comparison[];
|
|
285
|
+
|
|
270
286
|
export declare function range(start: number, end: number, multiplier?: number): number[];
|
|
271
287
|
|
|
272
288
|
export interface TaskOptions {
|
|
@@ -307,15 +323,6 @@ export declare function group(name: string, fn: () => void, opts?: GroupOptions)
|
|
|
307
323
|
|
|
308
324
|
export declare function task(name: string, fn: () => unknown | Promise<unknown>, opts?: TaskOptions): void;
|
|
309
325
|
|
|
310
|
-
interface Thresholds {
|
|
311
|
-
timingPct: number;
|
|
312
|
-
frameSelfPct: number;
|
|
313
|
-
heapTypePct: number;
|
|
314
|
-
minFrameSelfUs: number;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
export declare function compareDocuments(base: ProfileDocument, cand: ProfileDocument, thresholds?: Thresholds): Comparison[];
|
|
318
|
-
|
|
319
326
|
export declare function saveDocument(doc: ProfileDocument, path: string): Promise<void>;
|
|
320
327
|
|
|
321
328
|
export declare function loadDocument(path: string): Promise<ProfileDocument>;
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{d,f,
|
|
2
|
+
import{d,f,S,n,k,B}from"./chunk-3qbcj1m9.js";import{o,t,U,M}from"./chunk-zrck2q0b.js";export{d as bench,f as compareDocuments,U as group,t as loadDocument,B as profile,S as range,n as renderers,k as run,o as saveDocument,M as task};
|
package/package.json
CHANGED
package/runner.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{r,
|
|
4
|
-
`),2;let
|
|
5
|
-
`),2;let
|
|
6
|
-
`),2;if(
|
|
3
|
+
import{r,C,i,s,o,l,p,N,v,m,R,D,F}from"./chunk-zrck2q0b.js";var z=500,H=20,A=3,j=10,X=2,q=0.1,K=1000,Q=1e4;function J(t){let a=Math.log10(Math.max(1,t)/1e6),c=Math.round(A+X*a);return Math.min(j,Math.max(A,c))}function V(t,a){let c=Math.floor(a/t);return Math.min(H,Math.max(c,J(t)))}var L=0;function O(t){if(typeof t==="number")L+=t;else if(t!==void 0&&t!==null)L+=1}function I(t){return t!==null&&typeof t==="object"&&typeof t.then==="function"}function G(t,a){return Math.max(1,Math.ceil(K/t),Math.ceil(a/(t*Q)))}async function U(t,a={}){let c=(a.timeBudgetMs??z)*1e6,e=c*(a.warmupFraction??q),S=Bun.nanoseconds(),g=0,B=0;while(B<e){let u=t();O(I(u)?await u:u),g++,B=Bun.nanoseconds()-S}let f;if(g>0)f=Math.max(1,B/g);else{let u=Bun.nanoseconds(),b=t();O(I(b)?await b:b),f=Math.max(1,Bun.nanoseconds()-u)}let d=G(f,c);if(d>1){let u=Bun.nanoseconds();for(let b=0;b<d;b++){let M=t();O(I(M)?await M:M)}f=Math.max(1,(Bun.nanoseconds()-u)/d),d=G(f,c)}let n=f*d,h=a.minSamples??V(n,c),w=[],k=Bun.nanoseconds(),T=0,x=0;while(x<h||T<c){let u=Bun.nanoseconds();for(let M=0;M<d;M++){let P=t();O(I(P)?await P:P)}let b=Bun.nanoseconds();if(w.push({i:x,wallNs:(b-u)/d}),x++,T=Bun.nanoseconds()-k,a.gc)Bun.gc(!0)}let W=w.map((u)=>u.wallNs),E=l(W),y=p(E,[],"inprocess"),_=J(n);if(w.length<_)y.push({code:"low-sample-count",message:`Only ${w.length} sample(s) at ~${Y(n)} per trial; ${_} is the floor for this cost class. Raise minSamples or the time budget for a steadier number.`,data:{samples:w.length,target:_,trialCostNs:n}});return{trials:w,timing:E,warnings:y}}function Y(t){if(t>=1e9)return`${(t/1e9).toFixed(2)}s`;if(t>=1e6)return`${(t/1e6).toFixed(1)}ms`;if(t>=1000)return`${(t/1000).toFixed(1)}\xB5s`;return`${t.toFixed(0)}ns`}async function Z(){let[t,a,c]=process.argv.slice(2);if(!t||!a)return process.stderr.write(`bench runner: usage: runner.ts <suiteFile> <outputPath> [optsJson]
|
|
4
|
+
`),2;let e=c?JSON.parse(c):{};for(let n of e.preload??[])await import(n);v(),await import(t);let S=N();if(S.length===0)return process.stderr.write(`bench runner: ${t} registered no tasks (no task() calls found).
|
|
5
|
+
`),2;let g=F(S,e.filter);if(e.taskIds){let n=new Set(e.taskIds);g=g.filter((h)=>n.has(m(h)))}if(g.length===0)return process.stderr.write(`bench runner: --filter ${JSON.stringify(e.filter)} matched zero of ${S.length} registered tasks in ${t}.
|
|
6
|
+
`),2;if(e.planPath){let n=g.map((h)=>({id:m(h),isolate:R(h,e.isolate??!1)}));await Bun.write(e.planPath,JSON.stringify({tasks:n}))}let B=e.taskIds?g:g.filter((n)=>!R(n,e.isolate??!1)),f=[],d=[];for(let n of B){let h=m(n),w=C(t,h,{label:h,baseline:n.baseline,group:n.groupName,description:n.opts?.description,groupDescription:n.groupDescription,isolated:e.markIsolated});f.push(w);let k={...e,...n.opts?.timeBudgetMs!==void 0&&{timeBudgetMs:n.opts.timeBudgetMs},...n.opts?.minSamples!==void 0&&{minSamples:n.opts.minSamples},gc:D(n,e.gc??!1)},T=await U(n.fn,k);d.push(i({workload:w,configFingerprint:s({timeBudgetMs:k.timeBudgetMs??null,minSamples:k.minSamples??null,gc:k.gc??!1}),trials:T.trials,timing:T.timing,warnings:T.warnings}))}return await o(r(f,d),a),0}Z().then((t)=>process.exit(t));
|
package/chunk-tw064qem.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import{h,e,r,u,R,i,b,T,s,k,t,l,p}from"./chunk-nfgy545q.js";function _e(o){return o.startsWith("file://")?o.slice(7):o}function ie(o,N,c){let I=o.nodes,m=I.length,v=new Map,C=[],P=new Map,U=new Int32Array(m);for(let W=0;W<m;W++){let E=I[W],B=E.callFrame,H=_e(B.url),G=v.get(B.functionName);if(G===void 0)G=new Map,v.set(B.functionName,G);let Y=G.get(H);if(Y===void 0)Y=C.length,G.set(H,Y),C.push({key:e("fr",B.functionName,H),name:B.functionName,url:H||void 0,line:B.lineNumber>=0?B.lineNumber:void 0,col:B.columnNumber>=0?B.columnNumber:void 0});U[W]=Y,P.set(E.id,W)}let D=Array(m);for(let W=0;W<m;W++){let E=I[W];D[W]={id:E.id,frameIx:U[P.get(E.id)],children:E.children??[]}}let M=new Float64Array(m),O=new Float64Array(m),{samples:A,timeDeltas:z}=o;for(let W=0;W<A.length;W++){let E=P.get(A[W]);if(E===void 0)continue;M[E]+=z[W]??0,O[E]+=1}let K=new Int32Array(m).fill(-1);for(let W=0;W<m;W++){let E=I[W].children;if(!E)continue;for(let B of E){let H=P.get(B);if(H!==void 0)K[H]=W}}let _=[],J=[];for(let W=m-1;W>=0;W--)if(K[W]===-1)J.push(W);while(J.length>0){let W=J.pop();_.push(W);let E=I[W].children;if(!E)continue;for(let B of E){let H=P.get(B);if(H!==void 0&&K[H]===W)J.push(H)}}let V=new Float64Array(m);for(let W=_.length-1;W>=0;W--){let E=_[W];V[E]+=M[E];let B=K[E];if(B>=0)V[B]+=V[E]}let L=Array(C.length),j=[];for(let W=0;W<m;W++){let E=D[W].frameIx,B=L[E];if(B)B.selfUs+=M[W],B.totalUs+=V[W],B.samples+=O[W];else{let H={frameIx:E,selfUs:M[W],totalUs:V[W],samples:O[W]};L[E]=H,j.push(H)}}return{origin:N,samplingIntervalUs:c,frames:C,nodes:D,totals:j.sort((W,E)=>E.selfUs-W.selfUs),samples:{nodeIds:o.samples,timeDeltasUs:o.timeDeltas}}}function Le(o,N,c,I){let m=["--cpu-prof","--cpu-prof-dir",N,"--cpu-prof-name",c,"--cpu-prof-interval",String(I)],v=o[0];if(v==="bun"||v?.endsWith("/bun"))return[v,...m,...o.slice(1)];return o}async function fe(o){let N=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],I=c==="bun"||c?.endsWith("/bun"),m=Le(o.argv,o.artifactDir,o.fileName,o.intervalUs),v=I?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}`},C=Bun.nanoseconds(),U=await Bun.spawn(m,{cwd:o.cwd,env:v,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,D=Bun.nanoseconds()-C,M=Bun.file(N);if(!await M.exists())return{diagnosticWallNs:D,exitCode:U,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${N} after exit ${U}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:N,argv:o.argv}}]};let O=await M.json(),A=ie(O,"cpu-prof",o.intervalUs),z=O.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:D,exitCode:U,artifactPath:N,cpu:A,warnings:z}}function ge(o,N="heap-prof"){let{node_fields:c,node_types:I}=o.snapshot.meta,m=c.indexOf("type"),v=c.indexOf("self_size"),C=c.length,P=I[0];if(m===-1||v===-1||!Array.isArray(P))return{origin:N,typeCounts:[],objectCount:o.snapshot.node_count};let U=P.length,D=Array(U),M=new Map,O=[],A=0,z=o.nodes,K=z.length;for(let j=0;j<K;j+=C){let W=z[j+m],E=z[j+v]??0;A+=E;let B;if(W>=0&&W<U){if(B=D[W],B===void 0)B={type:P[W],count:0,bytes:0},D[W]=B,O.push(B)}else{let H=`unknown(${W})`;if(B=M.get(H),B===void 0)B={type:H,count:0,bytes:0},M.set(H,B),O.push(B)}B.count++,B.bytes+=E}let _=O.sort((j,W)=>W.count-j.count),J=_.slice(0,20),V=_.slice(20),L=J.map(({type:j,count:W,bytes:E})=>({type:j,count:W,retainedBytes:E}));if(V.length>0){let j=0,W=0;for(let E of V)j+=E.count,W+=E.bytes;L.push({type:"other",count:j,retainedBytes:W})}return{origin:N,heapSizeBytes:A,objectCount:o.snapshot.node_count,typeCounts:L}}function He(o,N,c){let I=["--heap-prof","--heap-prof-dir",N,"--heap-prof-name",c],m=o[0];if(m==="bun"||m?.endsWith("/bun"))return[m,...I,...o.slice(1)];return o}async function he(o){let N=`${o.artifactDir}/${o.fileName}`,c=o.argv[0],I=c==="bun"||c?.endsWith("/bun"),m=He(o.argv,o.artifactDir,o.fileName),v=I?o.env:{...process.env,...o.env,BUN_OPTIONS:`--heap-prof --heap-prof-dir ${o.artifactDir} --heap-prof-name ${o.fileName}`},C=Bun.nanoseconds(),U=await Bun.spawn(m,{cwd:o.cwd,env:v,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,D=Bun.nanoseconds()-C,M=Bun.file(N);if(!await M.exists())return{diagnosticWallNs:D,exitCode:U,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${N} after exit ${U}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:N,argv:o.argv}}]};let O=await M.json(),A=ge(O,"heap-prof");return{diagnosticWallNs:D,exitCode:U,artifactPath:N,heap:A,warnings:[]}}import{Session as Je}from"inspector/promises";var ze=1000;async function be(o,N={}){let c=N.intervalUs??ze,I=new Je;I.connect();let m=Bun.nanoseconds();try{await I.post("Profiler.enable"),await I.post("Profiler.setSamplingInterval",{interval:c}),await I.post("Profiler.start");let v=await o(),{profile:C}=await I.post("Profiler.stop"),P=Bun.nanoseconds()-m,U=ie(C,"inspector",c);return{result:v,cpu:U,diagnosticWallNs:P}}finally{I.disconnect()}}import{profile as Ke}from"bun:jsc";var Ve=new Map([["LLInt","llint"],["Baseline","baseline"],["DFG","dfg"],["FTL","ftl"]]),ye=4294967295;function we(o,N){let c=N??o.interval*1e6,I=new Map,m=[];function v(B,H,G,Y){let Q=I.get(B);if(Q===void 0)Q=new Map,I.set(B,Q);let q=H??"",Z=Q.get(q);if(Z===void 0)Z=m.length,Q.set(q,Z),m.push({key:e("fr",B,q),name:B,url:H,line:G,col:Y});return Z}function C(B){let H=B.line===ye,G=H?void 0:B.line-1,Y=H||B.column===ye?void 0:B.column-1;return v(B.name,B.sourceURL,G,Y)}let P=v("(root)",void 0,void 0,void 0),U=1,D={id:0,frameIx:P,children:new Map,selfUs:0,samples:0,totalUs:0},M=new Map([[0,D]]),O={llint:0,baseline:0,dfg:0,ftl:0},A=new Map,z=[],K=[];for(let B of o.traces){let H=B.frames,G=D;for(let q=H.length-1;q>=0;q--){let Z=C(H[q]),te=G.children.get(Z);if(!te)te={id:U++,frameIx:Z,children:new Map,selfUs:0,samples:0,totalUs:0},G.children.set(Z,te),M.set(te.id,te);G=te}G.selfUs+=c,G.samples+=1,z.push(G.id),K.push(c);let Y=H[0],Q=Y&&Ve.get(Y.category);if(Q){O[Q]++;let q=A.get(Q)??new Map;q.set(G.frameIx,(q.get(G.frameIx)??0)+1),A.set(Q,q)}}function _(B){let H=B.selfUs;for(let G of B.children.values())H+=_(G);return B.totalUs=H,H}_(D);let J=new Map;function V(B){let H=J.get(B.frameIx);if(H)H.selfUs+=B.selfUs,H.totalUs+=B.totalUs,H.samples+=B.samples;else J.set(B.frameIx,{frameIx:B.frameIx,selfUs:B.selfUs,totalUs:B.totalUs,samples:B.samples});for(let G of B.children.values())V(G)}V(D);let L=[...M.values()].map((B)=>({id:B.id,frameIx:B.frameIx,children:[...B.children.values()].map((H)=>H.id)})),j={origin:"jsc-profile",samplingIntervalUs:c,frames:m,nodes:L,totals:[...J.values()].sort((B,H)=>H.selfUs-B.selfUs),samples:{nodeIds:z,timeDeltasUs:K}},W=[...A.entries()].flatMap(([B,H])=>[...H.entries()].sort((G,Y)=>Y[1]-G[1]).slice(0,3).map(([G,Y])=>({tier:B,frameKey:m[G].key,samples:Y})));return{cpu:j,jit:{origin:"jsc-profile",tiers:O,topFramesByTier:W}}}var Ge=1000;async function xe(o,N={}){let c=N.intervalUs??Ge,I,m=Bun.nanoseconds(),v=await Ke(async()=>(I=await o(),I),c),C=Bun.nanoseconds()-m,{cpu:P,jit:U}=we(v.stackTraces,c);return{result:I,cpu:P,jit:U,diagnosticWallNs:C}}async function le(o){let N=Bun.nanoseconds(),c=Bun.spawn(o.argv,{cwd:o.cwd,env:o.env,stdout:"ignore",stderr:"ignore",stdin:"ignore"}),I=await c.exited,m=Bun.nanoseconds(),v=c.resourceUsage?.();return{wallNs:m-N,exitCode:I,userNs:v?Number(v.cpuTime.user)*1000:void 0,systemNs:v?Number(v.cpuTime.system)*1000:void 0,maxRssBytes:v?.maxRSS}}function Re(o){return o.trim().split(/\s+/).filter(Boolean)}var Ye=10,qe=3000000000,Qe=3;async function g(o){let N=o.warmup??Qe;for(let M=0;M<N;M++)await le(o);let c=[],I=o.runs??o.minRuns??Ye,m=o.runs!==void 0?0:o.minTotalNs??qe,v=0,C=0;while(C<I||v<m){let M=await le(o);if(c.push({i:C,wallNs:M.wallNs,exitCode:M.exitCode,userNs:M.userNs,systemNs:M.systemNs,maxRssBytes:M.maxRssBytes}),v+=M.wallNs,C++,o.runs!==void 0&&C>=o.runs)break}let P=c.map((M)=>M.wallNs),U=l(P),D=p(U,c.map((M)=>M.exitCode));return{trials:c,timing:U,warnings:D}}var Pe=new URL("./runner.ts",import.meta.url).pathname,Xe="node_modules/.cache/ostia";function x(){return Math.max(1,navigator.hardwareConcurrency||1)}async function d(o){let c=`${o.outDir??Xe}/bench-tmp`,I=o.cwd??process.cwd(),m=Math.max(1,Math.floor(o.jobs??1)),v={timeBudgetMs:o.timeBudgetMs,minSamples:o.minSamples,gc:o.gc},C=o.suites.map((D)=>D.startsWith("/")?D:`${I}/${D}`),P=(o.preload??[]).map((D)=>D.startsWith("/")?D:`${I}/${D}`),U=async(D,M)=>{let O=new Set,A=0,z,K=async()=>{while(z===void 0&&A<D.length){let _=A++;try{let J=Bun.spawn(D[_],{cwd:I,stdout:"inherit",stderr:"inherit",stdin:"ignore"});O.add(J);let V=await J.exited;if(O.delete(J),V!==0)throw Error(`Bench suite failed: ${M(_)} (runner exited ${V})`)}catch(J){z??=J instanceof Error?J:Error(String(J));for(let V of O)V.kill()}}};if(await Promise.all(Array.from({length:Math.min(m,D.length)},K)),z)throw z};try{let D=C.map((L)=>`${c}/${e("bench-plan",L)}.json`),M=C.map((L,j)=>["bun",Pe,L,D[j],JSON.stringify({...v,filter:o.filter,isolate:o.isolate,preload:P,planOnly:!0})]);await U(M,(L)=>o.suites[L]);let O=await Promise.all(D.map(async(L)=>{let{tasks:j}=await Bun.file(L).json();return j})),A=[];for(let L=0;L<O.length;L++){let j=O[L].filter((W)=>!W.isolate).map((W)=>W.id);if(j.length>0)A.push({suiteIndex:L,taskIds:j,markIsolated:!1});for(let W of O[L])if(W.isolate)A.push({suiteIndex:L,taskIds:[W.id],markIsolated:!0})}let z=A.map((L,j)=>`${c}/${e("bench-item",C[L.suiteIndex],j)}.json`),K=A.map((L,j)=>["bun",Pe,C[L.suiteIndex],z[j],JSON.stringify({...v,taskIds:L.taskIds,preload:P,...L.markIsolated&&{markIsolated:!0}})]);await U(K,(L)=>o.suites[A[L].suiteIndex]);let _=await Promise.all(z.map(t)),J=[],V=[];for(let L=0;L<O.length;L++){let j=A.findIndex((H)=>H.suiteIndex===L&&!H.markIsolated),W=j>=0?_[j]:void 0,E=0,B=new Map;A.forEach((H,G)=>{if(H.suiteIndex===L&&H.markIsolated)B.set(H.taskIds[0],_[G])});for(let H of O[L])if(H.isolate){let G=B.get(H.id);J.push(G.workloads[0]),V.push(G.runs[0])}else J.push(W.workloads[E]),V.push(W.runs[E]),E++}return r(J,V)}finally{await Bun.spawn(["rm","-rf",c]).exited}}function F(o,N,c=8){if(c<=1)throw RangeError(`range: multiplier must be > 1, got ${c}`);if(o<=0)throw RangeError(`range: start must be > 0, got ${o}`);let I=[];for(let m=o;m<=N;m*=c)I.push(m);if(!I.includes(N))I.push(N);return I}var a={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000};function ae(o,N){if(o===0)return N===0?0:1/0;return(N-o)/o*100}function re(o,N,c){return o.runs.find((I)=>I.workloadId===N&&I.phase===c)}function f(o,N,c=a){let I=new Set(N.workloads.map((v)=>v.id)),m=[];for(let v of o.workloads){if(!I.has(v.id))continue;let C=w(o,N,v.id,c);if(C)m.push(C)}return m}function w(o,N,c,I=a){let m=re(o,c,"timing"),v=re(N,c,"timing"),C=re(o,c,"cpu"),P=re(N,c,"cpu"),U=re(o,c,"heap"),D=re(N,c,"heap"),M=m?.id??C?.id??U?.id,O=v?.id??P?.id??D?.id;if(!M||!O)return;let A=!1,z;if(m?.timing&&v?.timing){let J=ae(m.timing.median,v.timing.median),V=ae(m.timing.mean,v.timing.mean),L=J>I.timingPct?"regressed":J<-I.timingPct?"improved":"unchanged";if(L==="regressed")A=!0;z={medianDeltaPct:J,meanDeltaPct:V,verdict:L}}let K;if(C?.cpu&&P?.cpu){let J=new Map(C.cpu.totals.map((E)=>[C.cpu.frames[E.frameIx].key,E])),V=new Map(P.cpu.totals.map((E)=>[P.cpu.frames[E.frameIx].key,E])),L=new Map(C.cpu.frames.map((E)=>[E.key,E.name])),j=new Map(P.cpu.frames.map((E)=>[E.key,E.name]));K=[...new Set([...J.keys(),...V.keys()])].map((E)=>{let B=J.get(E)?.selfUs??0,H=V.get(E)?.selfUs??0;return{frameKey:E,name:j.get(E)??L.get(E)??E,baseSelfUs:B,candSelfUs:H,deltaPct:ae(B,H)}}).sort((E,B)=>Math.abs(B.deltaPct)-Math.abs(E.deltaPct));for(let E of K)if((E.baseSelfUs>=I.minFrameSelfUs||E.candSelfUs>=I.minFrameSelfUs)&&E.deltaPct>I.frameSelfPct)A=!0}let _;if(U?.heap&&D?.heap){let J=new Map(U.heap.typeCounts.map((j)=>[j.type,j])),V=new Map(D.heap.typeCounts.map((j)=>[j.type,j]));_=[...new Set([...J.keys(),...V.keys()])].map((j)=>{let W=J.get(j),E=V.get(j);return{type:j,baseCount:W?.count??0,candCount:E?.count??0,baseBytes:W?.retainedBytes,candBytes:E?.retainedBytes,deltaPct:ae(W?.count??0,E?.count??0)}}).sort((j,W)=>Math.abs(W.deltaPct)-Math.abs(j.deltaPct));for(let j of _)if(j.deltaPct>I.heapTypePct)A=!0}return{id:e("cmp",M,O),baselineRunId:M,candidateRunId:O,timing:z,frames:K,heapTypes:_,thresholds:I,verdict:A?"fail":"pass"}}function ee(o,N){if(N){let c=o.runs.find((I)=>I.id===N);return c?.cpu?[c]:[]}return o.runs.filter((c)=>c.phase==="cpu"&&c.cpu)}function se(o){let N=o.nodes,c=N.length,I=Ze(o),m=new Int32Array(c).fill(-1);for(let U=0;U<c;U++)for(let D of N[U].children){let M=I(D);if(M!==-1)m[M]=U}let v=[];for(let U=0;U<c;U++)if(m[U]===-1)v.push(U);let C=[],P=[];for(let U=v.length-1;U>=0;U--)P.push(v[U]);while(P.length>0){let U=P.pop();C.push(U);for(let D of N[U].children){let M=I(D);if(M!==-1&&m[M]===U)P.push(M)}}return{count:c,indexOf:I,parentIx:m,roots:v,order:C}}function Ze(o){let N=o.nodes,c=N.length,I=1/0,m=-1/0,v=!0;for(let P=0;P<c;P++){let U=N[P].id;if(!Number.isInteger(U)){v=!1;break}if(U<I)I=U;if(U>m)m=U}if(v&&c>0&&m-I<c*4+64){let P=m-I+1,U=new Int32Array(P).fill(-1);for(let D=0;D<c;D++)U[N[D].id-I]=D;return(D)=>{let M=D-I;return M>=0&&M<P?U[M]:-1}}let C=new Map;for(let P=0;P<c;P++)C.set(N[P].id,P);return(P)=>C.get(P)??-1}function ke(o,N){let{count:c,indexOf:I,parentIx:m,order:v}=N,C=new Float64Array(c),P=new Float64Array(c),U=o.samples?.nodeIds??[],D=o.samples?.timeDeltasUs??[];for(let O=0;O<U.length;O++){let A=I(U[O]);if(A===-1)continue;C[A]+=D[O]??0,P[A]+=1}let M=new Float64Array(c);for(let O=v.length-1;O>=0;O--){let A=v[O];M[A]+=C[A];let z=m[A];if(z>=0)M[z]+=M[A]}return{selfUs:C,totalUs:M,samples:P}}var Te={name:"collapsed",async render(o,N={}){return{files:ee(o,N.runId).map((m)=>{let v=m.cpu,{nodes:C,frames:P}=v,U=se(v),D=Array(U.count);for(let K of U.order){let _=P[C[K].frameIx].name||"(anonymous)",J=U.parentIx[K];D[K]=J===-1?_:`${D[J]};${_}`}let M=new Float64Array(U.count),O=[],A=v.samples?.nodeIds??[];for(let K=0;K<A.length;K++){let _=U.indexOf(A[K]);if(_===-1)continue;if(M[_]++===0)O.push(_)}let z=Array(O.length);for(let K=0;K<O.length;K++){let _=O[K];z[K]=`${D[_]} ${M[_]}`}return{path:`${m.id}.collapsed.txt`,content:z.join(`
|
|
3
|
-
`)+(z.length>0?`
|
|
4
|
-
`:"")}})}}};var Ie={name:"cpuprofile",async render(o,N={}){let c=ee(o,N.runId),I=[],m=[];for(let v of c){if(v.cpu?.origin!=="cpu-prof"&&v.cpu?.origin!=="inspector"){m.push(`${v.id} (origin ${v.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let C=v.artifacts.find((U)=>U.kind==="cpuprofile");if(!C){m.push(`${v.id} (no cpuprofile artifact recorded on this run)`);continue}let P=Bun.file(C.path);if(!await P.exists()){m.push(`${v.id} (artifact missing on disk: ${C.path})`);continue}I.push({path:`${v.id}.cpuprofile`,content:await P.text()})}if(I.length===0&&m.length>0)return{text:`No .cpuprofile artifacts available:
|
|
5
|
-
${m.map((v)=>` - ${v}`).join(`
|
|
6
|
-
`)}
|
|
7
|
-
`};return{files:I}}};var $e={name:"json",async render(o){return{text:k(o)}}};var ve={name:"jsonl",async render(o){let{runs:N,...c}=o;return{text:`${[h(c),...N.map((m)=>h(m))].join(`
|
|
8
|
-
`)}
|
|
9
|
-
`}}};function ne(o){return(o/1e6).toFixed(3)}function ce(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??o?.id??"unknown"}var Ce=10,Ne=10,Ue={name:"markdown",async render(o){let N=new Map(o.workloads.map((m)=>[m.id,m])),c=[];c.push("# Profile Report",""),c.push(`Bun ${o.bunVersion} \xB7 ostia ${o.toolVersion} \xB7 ${o.platform.os}/${o.platform.arch} \xB7 ${o.createdAt}`,"");let I=o.runs.filter((m)=>m.phase==="timing"&&m.timing!==void 0);if(I.length>0){c.push("## Timing",""),c.push("| Command | Mean \xB1 SD (ms) | Min\u2026Max (ms) | Median (ms) |","|---|---|---|---|");for(let v of I){let C=ce(N.get(v.workloadId)),P=v.timing;c.push(`| ${C} | ${ne(P.mean)} \xB1 ${ne(P.stddev)} | ${ne(P.min)}\u2026${ne(P.max)} | ${ne(P.median)} |`)}c.push("");let m=I.filter((v)=>v.warnings.length>0);if(m.length>0){c.push("### Warnings","");for(let v of m){let C=ce(N.get(v.workloadId));for(let P of v.warnings)c.push(`- **${C}**: ${P.message} (\`${P.code}\`)`)}c.push("")}}for(let m of o.runs){if(m.phase!=="cpu"&&m.phase!=="heap")continue;let v=ce(N.get(m.workloadId));if(m.phase==="cpu"){if(c.push(`## CPU capture - ${v}`,""),c.push(`instrumented, diagnostic wall ${ne(m.diagnosticWallNs??0)}ms`,""),m.cpu){c.push(`origin: \`${m.cpu.origin}\`, interval: ${m.cpu.samplingIntervalUs}\xB5s`,""),c.push("| Self % | Self (ms) | Total (ms) | Frame |","|---|---|---|---|");let C=m.cpu.totals.reduce((P,U)=>P+U.selfUs,0)||1;for(let P of m.cpu.totals.slice(0,Ce)){let U=m.cpu.frames[P.frameIx],D=(P.selfUs/C*100).toFixed(1);c.push(`| ${D}% | ${(P.selfUs/1000).toFixed(2)} | ${(P.totalUs/1000).toFixed(2)} | ${U?.name||"(anonymous)"} |`)}if(c.push(""),m.jit){let P=m.jit.tiers;c.push(`JIT tiers: LLInt ${P.llint} \xB7 Baseline ${P.baseline} \xB7 DFG ${P.dfg} \xB7 FTL ${P.ftl}`,"")}}}else if(c.push(`## Heap snapshot - ${v}`,""),c.push(`instrumented, diagnostic wall ${ne(m.diagnosticWallNs??0)}ms`,""),m.heap){c.push(`${m.heap.objectCount??"?"} objects, ${((m.heap.heapSizeBytes??0)/1e6).toFixed(2)}MB`,""),c.push("| Count | Type |","|---|---|");for(let C of m.heap.typeCounts.slice(0,Ne))c.push(`| ${C.count} | ${C.type} |`);c.push("")}for(let C of m.artifacts)c.push(`- artifact: \`${C.path}\``);for(let C of m.warnings)c.push(`- ! ${C.message} (\`${C.code}\`)`);if(m.artifacts.length>0||m.warnings.length>0)c.push("")}if(o.comparisons&&o.comparisons.length>0){c.push("## Comparisons","");for(let m of o.comparisons){let v=o.runs.find((P)=>P.id===m.candidateRunId),C=ce(v?N.get(v.workloadId):void 0);if(c.push(`### ${m.verdict==="pass"?"\u2713":"\u2717"} ${C}`,""),m.timing){let P=m.timing.medianDeltaPct>0?"+":"";c.push(`- timing: ${P}${m.timing.medianDeltaPct.toFixed(1)}% median (**${m.timing.verdict}**)`)}for(let P of m.frames?.slice(0,Ce)??[]){if(Math.abs(P.deltaPct)<0.5)continue;let U=P.deltaPct>0?"+":"";c.push(`- frame \`${P.name}\`: ${U}${P.deltaPct.toFixed(1)}% self-time (${(P.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(P.candSelfUs/1000).toFixed(2)}ms)`)}for(let P of m.heapTypes?.slice(0,Ne)??[]){if(Math.abs(P.deltaPct)<0.5)continue;let U=P.deltaPct>0?"+":"";c.push(`- heap \`${P.type}\`: ${U}${P.deltaPct.toFixed(1)}% count (${P.baseCount} \u2192 ${P.candCount})`)}c.push("")}}return{text:c.join(`
|
|
10
|
-
`)}}};var en=15;function pe(o){return`n${o}`}function nn(o,N,c){return`${(o||"(anonymous)").replace(/"/g,"'")} (self ${(N/1000).toFixed(2)}ms, total ${(c/1000).toFixed(2)}ms)`}function tn(o,N,c,I){let m=[];if(I<=0)return m;for(let v=0;v<N;v++){if(v===c)continue;let C=o[v];if(m.length===I&&C<=o[m[I-1]])continue;let P=m.length;while(P>0&&o[m[P-1]]<C)P--;if(m.splice(P,0,v),m.length>I)m.pop()}return m}var De={name:"mermaid",async render(o,N={}){let c=N.topN??en;return{files:ee(o,N.runId).map((v)=>{let C=v.cpu,{nodes:P,frames:U}=C,D=se(C),{selfUs:M,totalUs:O}=ke(C,D),{parentIx:A}=D,z=D.roots[0]??-1,K=tn(M,D.count,z,c),_=new Set(z!==-1?[z]:[]),J=[];for(let L of K){J.length=0;for(let j=L;j!==-1;j=A[j])J.push(j);for(let j=J.length-1;j>=0;j--)_.add(J[j])}let V=["graph TD"];for(let L of _){let j=P[L].id;V.push(` ${pe(j)}["${nn(U[P[L].frameIx].name,M[L],O[L])}"]`)}for(let L of _){let j=A[L];if(j!==-1&&_.has(j))V.push(` ${pe(P[j].id)} --> ${pe(P[L].id)}`)}return{path:`${v.id}.mermaid.md`,content:`${V.join(`
|
|
11
|
-
`)}
|
|
12
|
-
`}})}}};function Fe(o){if(!o?.entry)return;if(o.entry.group!==void 0)return o.entry.group;let N=o.entry.task,c=N.lastIndexOf("/");return c===-1?void 0:N.slice(0,c)}function ue(o){let N=Math.min(...o.map((m)=>m.run.timing.median)),c=new Map;for(let m of o){let v=Fe(m.workload);if(v===void 0)continue;let C=c.get(v);if(C)C.push(m);else c.set(v,[m])}let I=new Map;for(let m of o){let v=Fe(m.workload);if(v===void 0){I.set(m,N);continue}let C=c.get(v)??[m],P=C.find((U)=>U.workload?.baseline);I.set(m,P?P.run.timing.median:Math.min(...C.map((U)=>U.run.timing.median)))}return I}function X(o){return Number.isFinite(o)?Number(o.toPrecision(6)):o}function rn(o,N){return o?.entry?.task??o?.label??o?.command?.join(" ")??N.workloadId}function sn(o){let N=new Map(o.workloads.map((v)=>[v.id,v])),c=o.runs.filter((v)=>v.phase==="timing"&&v.timing!==void 0).map((v)=>({run:v,workload:N.get(v.workloadId)})),I=c.length>1?ue(c):void 0,m=new Map((o.comparisons??[]).map((v)=>[v.candidateRunId,v]));return c.map((v)=>{let{run:C,workload:P}=v,U=C.timing,D={task:rn(P,C),unit:"ns",samples:U.samples.length,mean:X(U.mean),median:X(U.median),stddev:X(U.stddev),stddevPct:X(U.mean===0?0:U.stddev/U.mean*100),min:X(U.min),max:X(U.max),warnings:C.warnings.map((O)=>O.data?{code:O.code,data:O.data}:{code:O.code})};if(P?.entry?.group!==void 0)D.group=P.entry.group;if(P?.description!==void 0)D.description=P.description;if(P?.groupDescription!==void 0)D.groupDescription=P.groupDescription;if(I)D.relative=X(U.median/(I.get(v)??U.median));if(P?.baseline)D.baseline=!0;let M=m.get(C.id);if(M?.timing)D.delta={medianPct:X(M.timing.medianDeltaPct),meanPct:X(M.timing.meanDeltaPct),verdict:M.timing.verdict,pass:M.verdict==="pass"};return D})}var Me={name:"minimal",async render(o){let N=sn(o).map((c)=>JSON.stringify(c));return{text:N.length>0?`${N.join(`
|
|
13
|
-
`)}
|
|
14
|
-
`:""}}};var on="https://www.speedscope.app/file-format-schema.json";function Se(o){return o?.label??o?.command?.join(" ")??o?.entry?.task??"profile"}var Be={name:"speedscope",async render(o,N={}){let c=ee(o,N.runId),I=new Map(o.workloads.map((v)=>[v.id,v]));return{files:c.map((v)=>{let C=v.cpu,{nodes:P}=C,U=se(C),D=C.samples?.nodeIds??[],M=C.samples?.timeDeltasUs??[],O=Array(U.count);for(let _ of U.order){let J=U.parentIx[_],V=P[_].frameIx;O[_]=J===-1?[V]:[...O[J],V]}let A=Array(D.length);for(let _=0;_<D.length;_++){let J=U.indexOf(D[_]);A[_]=J===-1?[]:O[J]}let z=0;for(let _=0;_<M.length;_++)z+=M[_];let K={$schema:on,exporter:"ostia",name:Se(I.get(v.workloadId)),activeProfileIndex:0,shared:{frames:C.frames.map((_)=>({name:_.name||"(anonymous)",file:_.url,line:_.line!==void 0?_.line+1:void 0}))},profiles:[{type:"sampled",name:Se(I.get(v.workloadId)),unit:"microseconds",startValue:0,endValue:z,samples:A,weights:M}]};return{path:`${v.id}.speedscope.json`,content:`${JSON.stringify(K,null,2)}
|
|
15
|
-
`}})}}};function oe(o){return(o/1e6).toFixed(3)}function me(o){return o.label??o.command?.join(" ")??o.entry?.task??o.id}var We={name:"table",async render(o){let N=o.runs.filter((O)=>O.phase==="timing"&&O.timing!==void 0),c=new Map(o.workloads.map((O)=>[O.id,O]));if(N.length===0){let O=Oe(o,c);return{text:O.length>0?`${O.join(`
|
|
16
|
-
`)}
|
|
17
|
-
`:`(no timing runs)
|
|
18
|
-
`}}let I=N.map((O)=>{let A=c.get(O.workloadId);return{run:O,workload:A,label:A?me(A):O.workloadId}}),m=I.length>1,v=ue(I),C=[],P=Math.max(7,...I.map((O)=>O.label.length)),U=m?`${"Command".padEnd(P)} Mean [ms] Min\u2026Max [ms] Relative`:`${"Command".padEnd(P)} Mean [ms] Min\u2026Max [ms]`;C.push(U),C.push("-".repeat(U.length));for(let O of I){let{run:A,label:z,workload:K}=O,_=A.timing,J=`${oe(_.mean)} \xB1 ${oe(_.stddev)}`,V=`${oe(_.min)}\u2026${oe(_.max)}`,L=`${z.padEnd(P)} ${J.padEnd(15)} ${V.padEnd(18)}`;if(m){let j=_.median/(v.get(O)??_.median);if(j===1)L+=K?.baseline?" 1.00\xD7 (baseline)":" 1.00\xD7";else if(j>1)L+=` ${j.toFixed(2)}\xD7 slower`;else L+=` ${(1/j).toFixed(2)}\xD7 faster`}C.push(L);for(let j of A.warnings)C.push(` ! ${j.message}`)}let D=cn(o,c);if(D.length>0)C.push(""),C.push(...D);let M=Oe(o,c);if(M.length>0)C.push(""),C.push(...M);return{text:`${C.join(`
|
|
19
|
-
`)}
|
|
20
|
-
`}}};function an(o,N,c){let I=o.runs.find((v)=>v.id===c),m=I?N.get(I.workloadId):void 0;return m?me(m):c}function Oe(o,N){if(!o.comparisons||o.comparisons.length===0)return[];let c=[];for(let I of o.comparisons){let m=an(o,N,I.candidateRunId),v=I.verdict==="pass"?"\u2713":"\u2717";if(c.push(`${v} ${m}`),I.timing){let C=I.timing.medianDeltaPct>0?"+":"";c.push(` timing: ${C}${I.timing.medianDeltaPct.toFixed(1)}% median (${I.timing.verdict})`)}if(I.frames)for(let C of I.frames.slice(0,Ee)){if(Math.abs(C.deltaPct)<0.5)continue;let P=C.deltaPct>0?"+":"";c.push(` frame ${C.name}: ${P}${C.deltaPct.toFixed(1)}% self-time (${(C.baseSelfUs/1000).toFixed(2)}ms -> ${(C.candSelfUs/1000).toFixed(2)}ms)`)}if(I.heapTypes)for(let C of I.heapTypes.slice(0,Ae)){if(Math.abs(C.deltaPct)<0.5)continue;let P=C.deltaPct>0?"+":"";c.push(` heap ${C.type}: ${P}${C.deltaPct.toFixed(1)}% count (${C.baseCount} -> ${C.candCount})`)}}return c}var Ee=5,Ae=5;function cn(o,N){let c=[];for(let I of o.runs){if(I.phase!=="cpu"&&I.phase!=="heap")continue;let m=N.get(I.workloadId),v=m?me(m):I.workloadId;if(I.phase==="cpu")if(I.cpu){c.push(`CPU capture - ${v} (instrumented, ${I.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${oe(I.diagnosticWallNs??0)}ms)`);let C=I.cpu.totals.reduce((P,U)=>P+U.selfUs,0)||1;for(let P of I.cpu.totals.slice(0,Ee)){let U=I.cpu.frames[P.frameIx],D=(P.selfUs/C*100).toFixed(1);c.push(` ${D.padStart(5)}% ${(P.selfUs/1000).toFixed(2).padStart(8)}ms self ${U?.name??"?"}`)}}else c.push(`CPU capture - ${v} (instrumented, no evidence captured)`);else if(I.heap){let C=((I.heap.heapSizeBytes??0)/1e6).toFixed(2);c.push(`Heap snapshot - ${v} (instrumented, ${I.heap.objectCount??"?"} objects, ${C}MB)`);for(let P of I.heap.typeCounts.slice(0,Ae))c.push(` ${String(P.count).padStart(6)} ${P.type}`)}else c.push(`Heap snapshot - ${v} (instrumented, no evidence captured)`);for(let C of I.artifacts)c.push(` artifact: ${C.path}`);for(let C of I.warnings)c.push(` ! ${C.message}`)}return c}var n={table:We,json:$e,markdown:Ue,jsonl:ve,minimal:Me,collapsed:Te,mermaid:De,speedscope:Be,cpuprofile:Ie};var un="node_modules/.cache/ostia",de=1000;async function y(o){let N=s({runs:o.runs??null,warmup:o.warmup??null,cpu:o.cpu??!1,heap:o.heap??!1,cpuIntervalUs:o.cpuIntervalUs??de}),I=`${o.outDir??un}/artifacts`,m=[],v=[];for(let C of o.commands){let P=Array.isArray(C)?C:Re(C),U=u(P,Array.isArray(C)?void 0:C);m.push(U);let D=await g({argv:P,cwd:o.cwd,env:o.env,runs:o.runs,warmup:o.warmup}),M=i({workload:U,configFingerprint:N,trials:D.trials,timing:D.timing,warnings:D.warnings});if(v.push(M),o.cpu){let O=`${M.id}-cpu.cpuprofile`,A=await fe({argv:P,cwd:o.cwd,env:o.env,artifactDir:I,fileName:O,intervalUs:o.cpuIntervalUs??de});v.push(await je({workload:U,phase:"cpu",configFingerprint:N,diagnosticWallNs:A.diagnosticWallNs,exitCode:A.exitCode,cpu:A.cpu,artifactPath:A.artifactPath,artifactKind:"cpuprofile",warnings:A.warnings}))}if(o.heap){let O=`${M.id}-heap.heapsnapshot`,A=await he({argv:P,cwd:o.cwd,env:o.env,artifactDir:I,fileName:O});v.push(await je({workload:U,phase:"heap",configFingerprint:N,diagnosticWallNs:A.diagnosticWallNs,exitCode:A.exitCode,heap:A.heap,artifactPath:A.artifactPath,artifactKind:"heapsnapshot",warnings:A.warnings}))}}return r(m,v)}async function je(o){let N=`${o.workload.id}-${o.phase}-${o.configFingerprint}`,c=o.artifactPath?[await T(N,o.artifactKind,o.artifactPath)]:[];return b({workload:o.workload,phase:o.phase,configFingerprint:o.configFingerprint,diagnosticWallNs:o.diagnosticWallNs,exitCode:o.exitCode,cpu:o.cpu,heap:o.heap,warnings:o.warnings,artifacts:c})}async function S(o,N={}){let c=R(o),I=s({intervalUs:N.intervalUs??de,origin:N.origin??"inspector"}),m=(D)=>D.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(N.origin==="jsc"){let{result:D,cpu:M,jit:O,diagnosticWallNs:A}=await xe(o,N),z=b({workload:c,phase:"cpu",configFingerprint:I,diagnosticWallNs:A,cpu:M,jit:O,warnings:m(M),artifacts:[]});return{result:D,run:z}}let{result:v,cpu:C,diagnosticWallNs:P}=await be(o,N),U=b({workload:c,phase:"cpu",configFingerprint:I,diagnosticWallNs:P,cpu:C,warnings:m(C),artifacts:[]});return{result:v,run:U}}
|
|
21
|
-
export{x,d,a,f,w,g,F,n,y,S};
|