ostia 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +301 -40
- package/chunk-1wydyvyj.js +12 -0
- package/chunk-cf9hya3b.js +22 -0
- package/cli.js +124 -62
- package/index.d.ts +334 -39
- package/index.js +1 -1
- package/package.json +4 -1
- package/runner.ts +5 -5
- package/chunk-pesqame2.js +0 -8
- package/chunk-ym89ds9x.js +0 -21
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{y,e,k,l,O,N,D,q,F,m,t,P,K,d,p,Y,o,f,r,g,h,B,M,Z,T,R}from"./chunk-1wydyvyj.js";function _e(a,x,v){let E=a[0];if(E==="bun"||E?.endsWith("/bun"))return{argv:[E,...x,...a.slice(1)],env:v};return{argv:a,env:{...process.env,...v,BUN_OPTIONS:x.join(" ")}}}function Gn(a){return a.startsWith("file://")?a.slice(7):a}function je(a,x,v){let E=a.nodes,U=E.length,ie=new Map,G=[],A=new Map,ae=new Int32Array(U);for(let se=0;se<U;se++){let ge=E[se],ce=ge.callFrame,we=Gn(ce.url),Me=ie.get(ce.functionName);if(Me===void 0)Me=new Map,ie.set(ce.functionName,Me);let Pe=Me.get(we);if(Pe===void 0)Pe=G.length,Me.set(we,Pe),G.push({key:e("fr",ce.functionName,we),name:ce.functionName,url:we||void 0,line:ce.lineNumber>=0?ce.lineNumber:void 0,col:ce.columnNumber>=0?ce.columnNumber:void 0});ae[se]=Pe,A.set(ge.id,se)}let X=Array(U);for(let se=0;se<U;se++){let ge=E[se];X[se]={id:ge.id,frameIx:ae[A.get(ge.id)],children:ge.children??[]}}let oe=new Float64Array(U),ue=new Float64Array(U),{samples:me,timeDeltas:le}=a;for(let se=0;se<me.length;se++){let ge=A.get(me[se]);if(ge===void 0)continue;oe[ge]+=le[se]??0,ue[ge]+=1}let de=new Int32Array(U).fill(-1);for(let se=0;se<U;se++){let ge=E[se].children;if(!ge)continue;for(let ce of ge){let we=A.get(ce);if(we!==void 0)de[we]=se}}let fe=[],pe=[];for(let se=U-1;se>=0;se--)if(de[se]===-1)pe.push(se);while(pe.length>0){let se=pe.pop();fe.push(se);let ge=E[se].children;if(!ge)continue;for(let ce of ge){let we=A.get(ce);if(we!==void 0&&de[we]===se)pe.push(we)}}let he=new Float64Array(U);for(let se=fe.length-1;se>=0;se--){let ge=fe[se];he[ge]+=oe[ge];let ce=de[ge];if(ce>=0)he[ce]+=he[ge]}let ye=Array(G.length),be=[];for(let se=0;se<U;se++){let ge=X[se].frameIx,ce=ye[ge];if(ce)ce.selfUs+=oe[se],ce.totalUs+=he[se],ce.samples+=ue[se];else{let we={frameIx:ge,selfUs:oe[se],totalUs:he[se],samples:ue[se]};ye[ge]=we,be.push(we)}}return{origin:x,samplingIntervalUs:v,frames:G,nodes:X,totals:be.sort((se,ge)=>ge.selfUs-se.selfUs),samples:{nodeIds:a.samples,timeDeltasUs:a.timeDeltas}}}async function on(a){let x=`${a.artifactDir}/${a.fileName}`,{argv:v,env:E}=_e(a.argv,["--cpu-prof","--cpu-prof-dir",a.artifactDir,"--cpu-prof-name",a.fileName,"--cpu-prof-interval",String(a.intervalUs)],a.env),U=Bun.nanoseconds(),G=await Bun.spawn(v,{cwd:a.cwd,env:E,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,A=Bun.nanoseconds()-U,ae=Bun.file(x);if(!await ae.exists())return{diagnosticWallNs:A,exitCode:G,warnings:[{code:"artifact-missing",message:`Expected a .cpuprofile at ${x} after exit ${G}, found nothing. The workload's argv[0] must be a \`bun\` binary for CPU capture.`,data:{artifactPath:x,argv:a.argv}}]};let X=await ae.json(),oe=je(X,"cpu-prof",a.intervalUs),ue=X.samples.length===0?[{code:"empty-profile",message:"CPU capture produced zero samples."}]:[];return{diagnosticWallNs:A,exitCode:G,artifactPath:x,cpu:oe,warnings:ue}}function sn(a,x="heap-prof"){let{node_fields:v,node_types:E}=a.snapshot.meta,U=v.indexOf("type"),ie=v.indexOf("self_size"),G=v.length,A=E[0];if(U===-1||ie===-1||!Array.isArray(A))return{origin:x,typeCounts:[],objectCount:a.snapshot.node_count};let ae=A.length,X=Array(ae),oe=new Map,ue=[],me=0,le=a.nodes,de=le.length;for(let be=0;be<de;be+=G){let se=le[be+U],ge=le[be+ie]??0;me+=ge;let ce;if(se>=0&&se<ae){if(ce=X[se],ce===void 0)ce={type:A[se],count:0,bytes:0},X[se]=ce,ue.push(ce)}else{let we=`unknown(${se})`;if(ce=oe.get(we),ce===void 0)ce={type:we,count:0,bytes:0},oe.set(we,ce),ue.push(ce)}ce.count++,ce.bytes+=ge}let fe=ue.sort((be,se)=>se.count-be.count),pe=fe.slice(0,20),he=fe.slice(20),ye=pe.map(({type:be,count:se,bytes:ge})=>({type:be,count:se,retainedBytes:ge}));if(he.length>0){let be=0,se=0;for(let ge of he)be+=ge.count,se+=ge.bytes;ye.push({type:"other",count:be,retainedBytes:se})}return{origin:x,heapSizeBytes:me,objectCount:a.snapshot.node_count,typeCounts:ye}}async function an(a){let x=`${a.artifactDir}/${a.fileName}`,{argv:v,env:E}=_e(a.argv,["--heap-prof","--heap-prof-dir",a.artifactDir,"--heap-prof-name",a.fileName],a.env),U=Bun.nanoseconds(),G=await Bun.spawn(v,{cwd:a.cwd,env:E,stdout:"ignore",stderr:"ignore",stdin:"ignore"}).exited,A=Bun.nanoseconds()-U,ae=Bun.file(x);if(!await ae.exists())return{diagnosticWallNs:A,exitCode:G,warnings:[{code:"artifact-missing",message:`Expected a heap snapshot at ${x} after exit ${G}, found nothing. The workload's argv[0] must be a \`bun\` binary for heap capture.`,data:{artifactPath:x,argv:a.argv}}]};let X=await ae.json(),oe=sn(X,"heap-prof");return{diagnosticWallNs:A,exitCode:G,artifactPath:x,heap:oe,warnings:[]}}var Kn=1000;async function mn(a,x={}){let v=x.intervalUs??Kn,{Session:E}=await import("inspector/promises"),U=new E;U.connect();let ie=Bun.nanoseconds();try{await U.post("Profiler.enable"),await U.post("Profiler.setSamplingInterval",{interval:v}),await U.post("Profiler.start");let G=await a(),{profile:A}=await U.post("Profiler.stop"),ae=Bun.nanoseconds()-ie,X=je(A,"inspector",v);return{result:G,cpu:X,diagnosticWallNs:ae}}finally{U.disconnect()}}function Jn(a){let x=a>>>0;return()=>{x=x+1831565813|0;let v=Math.imul(x^x>>>15,1|x);return v=v+Math.imul(v^v>>>7,61|v)^v,((v^v>>>14)>>>0)/4294967296}}var Ve=2000,Yn=2000;function qn(a){let x=a.length,v=x>>1;return x%2===0?(a[v-1]+a[v])/2:a[v]}function cn(a,x,v){if(a.length<=v)return a;let E=[...a];for(let U=0;U<v;U++){let ie=U+Math.floor(x()*(E.length-U)),G=E[U];E[U]=E[ie],E[ie]=G}return E.slice(0,v)}class Qe{sorted;rankOf;counts;n;constructor(a){let x=a.length,v=new Uint32Array(x);for(let E=0;E<x;E++)v[E]=E;v.sort((E,U)=>a[E]-a[U]),this.sorted=new Float64Array(x),this.rankOf=new Uint32Array(x);for(let E=0;E<x;E++)this.sorted[E]=a[v[E]],this.rankOf[v[E]]=E;this.n=x,this.counts=new Uint32Array(x)}resampleMedian(a){let{n:x,counts:v,sorted:E,rankOf:U}=this;v.fill(0);for(let X=0;X<x;X++)v[U[Math.floor(a()*x)]]++;let ie=x+1>>1,G=x%2===0?ie+1:ie,A=0,ae=-1;for(let X=0;X<x;X++){if(A+=v[X],ae<0&&A>=ie)ae=X;if(A>=G)return ae===X?E[X]:(E[ae]+E[X])/2}return E[x-1]}}function un(a,x,v={}){let E=v.seed??(Date.now()^Math.imul(a.length,2654435761))>>>0,U=Jn(E),ie=v.iterations??Yn,G=a.length>Ve||x.length>Ve,A=new Qe(cn(a,U,Ve)),ae=new Qe(cn(x,U,Ve)),X=qn(A.sorted),oe=new Float64Array(ie);for(let ue=0;ue<ie;ue++){let me=A.resampleMedian(U),le=ae.resampleMedian(U);oe[ue]=X===0?le-me===0?0:1/0:(le-me)/X*100}return oe.sort(),{ci95:[l(oe,0.025),l(oe,0.975)],seed:E,data:{subsampled:G,iterations:ie}}}function Qn(a){let x=a<0?-1:1,v=Math.abs(a),E=0.254829592,U=-0.284496736,ie=1.421413741,G=-1.453152027,A=1.061405429,ae=0.3275911,X=1/(1+0.3275911*v),oe=1-((((1.061405429*X+-1.453152027)*X+1.421413741)*X+-0.284496736)*X+0.254829592)*X*Math.exp(-v*v);return x*oe}function Xn(a){return 0.5*(1+Qn(a/Math.SQRT2))}function ln(a,x){let v=a.length,E=x.length,U=v+E,ie=new Float64Array(a),G=new Float64Array(x);ie.sort(),G.sort();let A=0,ae=0,X=0,oe=0,ue=0;while(X<v||oe<E){let he=oe>=E||X<v&&ie[X]<=G[oe]?ie[X]:G[oe],ye=0;while(X<v&&ie[X]===he)ye++,X++;let be=0;while(oe<E&&G[oe]===he)be++,oe++;let se=ye+be,ge=ue+(se+1)/2;if(A+=ye*ge,se>1)ae+=se**3-se;ue+=se}let me=A-v*(v+1)/2,le=v*E/2,de=Math.sqrt(v*E*(U+1-ae/(U*(U-1)))/12),fe=de===0?0:(me-le)/de,pe=Math.min(1,Math.max(0,2*(1-Xn(Math.abs(fe)))));return{u:me,z:fe,pValue:pe}}var c={timingPct:5,frameSelfPct:10,heapTypePct:10,minFrameSelfUs:1000,alpha:0.01,bootstrapIterations:2000},Xe=5;function He(a,x){if(a===0)return x===0?0:1/0;return(x-a)/a*100}function dn(a){let x=new Map;for(let v of a.measurements){let E=`${v.workloadId}\x00${v.phase}`;if(!x.has(E))x.set(E,v)}return x}function Zn(a,x,v){return{base:a,cand:x,baseByPhase:dn(a),candByPhase:dn(x),candWorkloads:new Map(x.workloads.map((E)=>[E.id,E])),environmentMismatch:et(a,x),effectiveTimingPct:Math.max(v.timingPct,a.environment?.noise.floorPct??0,x.environment?.noise.floorPct??0)}}function et(a,x){let v=[];if(a.platform.os!==x.platform.os)v.push({field:"platform.os",base:a.platform.os,cand:x.platform.os});if(a.platform.arch!==x.platform.arch)v.push({field:"platform.arch",base:a.platform.arch,cand:x.platform.arch});if(a.bunVersion!==x.bunVersion)v.push({field:"bunVersion",base:a.bunVersion,cand:x.bunVersion});if(a.environment&&x.environment){if(a.environment.cpuModel!==x.environment.cpuModel)v.push({field:"cpuModel",base:a.environment.cpuModel,cand:x.environment.cpuModel});if(a.environment.cores!==x.environment.cores)v.push({field:"cores",base:a.environment.cores,cand:x.environment.cores})}if(v.length===0)return;return{code:"environment-mismatch",message:`Base and candidate were measured on different environments (${v.map((E)=>E.field).join(", ")}); a timing delta may reflect that instead of the code change.`,data:{fields:v}}}function nt(a){let x=[];for(let E of a){if(!E.timing)continue;let U=1+E.timing.medianDeltaPct/100;if(Number.isFinite(U)&&U>0)x.push(Math.log(U))}if(x.length===0)return null;let v=x.reduce((E,U)=>E+U,0)/x.length;return(Math.exp(v)-1)*100}function W(a,x,v=c){let E=Zn(a,x,v);return{effectiveTimingPct:E.effectiveTimingPct,compare:(U)=>tt(E,U,v),unmatched(){let U=new Set(a.workloads.map((ie)=>ie.id));return{baseOnly:a.workloads.filter((ie)=>!E.candWorkloads.has(ie.id)),candOnly:x.workloads.filter((ie)=>!U.has(ie.id))}}}}function j(a,x){let v=0,E=0,U=0;for(let ie of a){if(!ie.timing)continue;if(ie.timing.verdict==="regressed")v++;else if(ie.timing.verdict==="improved")E++;else U++}return{matched:a.length,regressed:v,improved:E,unchanged:U,geomeanPct:nt(a),effectiveTimingPct:x,verdict:a.some((ie)=>ie.verdict==="fail")?"fail":"pass"}}function C(a,x,v=c){let E=W(a,x,v),U=[];for(let ie of a.workloads){let G=E.compare(ie.id);if(G)U.push(G)}return{comparisons:U,unmatched:E.unmatched(),summary:j(U,E.effectiveTimingPct)}}function tt(a,x,v){let{baseByPhase:E,candByPhase:U,effectiveTimingPct:ie}=a,G=E.get(`${x}\x00timing`),A=U.get(`${x}\x00timing`),ae=E.get(`${x}\x00cpu`),X=U.get(`${x}\x00cpu`),oe=E.get(`${x}\x00heap`),ue=U.get(`${x}\x00heap`),me=a.candWorkloads.get(x),le=G?.id??ae?.id??oe?.id,de=A?.id??X?.id??ue?.id??me?.id;if(!le||!de)return;let fe=!1,pe=[];if(a.environmentMismatch)pe.push(a.environmentMismatch);let he;if(G?.timing&&me?.skipped&&!A?.timing)he={medianDeltaPct:0,meanDeltaPct:0,verdict:"unchanged"},pe.push({code:"skipped",message:"Candidate has no timing measurement for this workload (task.skip()); treated as unchanged.",data:{workloadId:x}});else if(G?.timing&&A?.timing){let se=G.timing.samples,ge=A.timing.samples,ce=He(G.timing.median,A.timing.median),we=He(G.timing.mean,A.timing.mean),Me=(Pe,xe)=>{if(Pe>ie)return"regressed";if(xe<-ie)return"improved";return"unchanged"};if(se.length<Xe||ge.length<Xe){let Pe=Me(ce,ce);if(Pe==="regressed")fe=!0;he={medianDeltaPct:ce,meanDeltaPct:we,verdict:Pe},pe.push({code:"thin-comparison",message:`Only ${se.length} baseline / ${ge.length} candidate sample(s); falling back to a point-estimate threshold instead of a bootstrap CI and Mann-Whitney test (needs ${Xe}+ per side).`,data:{baseSamples:se.length,candSamples:ge.length}})}else{let Pe=un(se,ge,{iterations:v.bootstrapIterations}),xe=ln(se,ge),ke=xe.pValue<v.alpha?Me(Pe.ci95[0],Pe.ci95[1]):"unchanged";if(ke==="regressed")fe=!0;he={medianDeltaPct:ce,meanDeltaPct:we,ci95:Pe.ci95,pValue:xe.pValue,seed:Pe.seed,verdict:ke}}}let ye;if(ae?.cpu&&X?.cpu){let se=new Map(ae.cpu.totals.map((Pe)=>[ae.cpu.frames[Pe.frameIx].key,Pe])),ge=new Map(X.cpu.totals.map((Pe)=>[X.cpu.frames[Pe.frameIx].key,Pe])),ce=new Map(ae.cpu.frames.map((Pe)=>[Pe.key,Pe.name])),we=new Map(X.cpu.frames.map((Pe)=>[Pe.key,Pe.name]));ye=[...new Set([...se.keys(),...ge.keys()])].map((Pe)=>{let xe=se.get(Pe)?.selfUs??0,ke=ge.get(Pe)?.selfUs??0;return{frameKey:Pe,name:we.get(Pe)??ce.get(Pe)??Pe,baseSelfUs:xe,candSelfUs:ke,deltaPct:He(xe,ke)}}).sort((Pe,xe)=>Math.abs(xe.deltaPct)-Math.abs(Pe.deltaPct));for(let Pe of ye)if((Pe.baseSelfUs>=v.minFrameSelfUs||Pe.candSelfUs>=v.minFrameSelfUs)&&Pe.deltaPct>v.frameSelfPct)fe=!0}let be;if(oe?.heap&&ue?.heap){let se=new Map(oe.heap.typeCounts.map((we)=>[we.type,we])),ge=new Map(ue.heap.typeCounts.map((we)=>[we.type,we]));be=[...new Set([...se.keys(),...ge.keys()])].map((we)=>{let Me=se.get(we),Pe=ge.get(we);return{type:we,baseCount:Me?.count??0,candCount:Pe?.count??0,baseBytes:Me?.retainedBytes,candBytes:Pe?.retainedBytes,deltaPct:He(Me?.count??0,Pe?.count??0)}}).sort((we,Me)=>Math.abs(Me.deltaPct)-Math.abs(we.deltaPct));for(let we of be)if(we.deltaPct>v.heapTypePct)fe=!0}return{id:e("cmp",le,de),baselineMeasurementId:le,candidateMeasurementId:de,timing:he,...pe.length>0&&{warnings:pe},frames:ye,heapTypes:be,thresholds:{...v,effectiveTimingPct:ie},verdict:fe?"fail":"pass"}}var Be="node_modules/.cache/ostia",rt=".ostia/baselines",it={runs:null,warmup:3,outDir:Be,baselineDir:rt,baseline:"main",cpuIntervalUs:1000,thresholds:c,workloads:[]};function gn(a){return{...it,...a,thresholds:{...c,...a.thresholds??{}}}}async function pn(a){let x=Bun.file(a);if(!await x.exists())return;return gn(await x.json())}async function fn(a){let x=a.startsWith("/")?a:`${process.cwd()}/${a}`;if(!await Bun.file(x).exists())return;let v=await import(x);return gn(v.default??{})}async function S(a){if(a!==void 0)return a.endsWith(".ts")?fn(a):pn(a);return await fn("ostia.config.ts")??pn("ostia.config.json")}function s(a,x){return`${a.baselineDir}/${x??a.baseline}.json`}async function L(){if(await Bun.file("ostia.config.ts").exists())return"ostia.config.ts";if(await Bun.file("ostia.config.json").exists())return"ostia.config.json";return}var ot=10,st=3000000000,at=3;function Ze(a){if(a.timeSource)N(a.timeSource);let x=a.warmup??at,v=a.samples,E=a.minSamples??ot,U=v??E,ie=v!==void 0?0:a.budgetMs!==void 0?a.budgetMs*1e6:st,G=a.timeSource!==void 0,A=a.ignoreExitCodes??[],ae=new Set(A),X=[],oe=0,ue=0,me=!1,le;function de(){if(me)return!0;if(v!==void 0)return ue>=v;return ue>=U&&oe>=ie}async function fe(pe,he){if(a.prepare)await F(a.prepare,{phase:pe,index:he},{cwd:a.cwd,env:a.env,timeoutMs:a.timeoutMs,signal:a.signal});return q(a)}return{async warmup(){for(let pe=0;pe<x;pe++){if(a.signal?.aborted)return;await fe("warmup",pe)}},async step(){if(de()||a.signal?.aborted)return!1;let pe=await fe("timing",ue);if(a.signal?.aborted)return!1;if(pe.timeSourceNoMatch)le??=pe.timeSourceMissOutput;if(X.push({i:ue,wallNs:pe.wallNs,exitCode:pe.exitCode??void 0,userNs:pe.userNs,systemNs:pe.systemNs,maxRssBytes:pe.maxRssBytes,...pe.reportedNs!==void 0&&{reportedNs:pe.reportedNs},...pe.timedOut?{timedOut:!0}:{},...pe.timeSourceNoMatch?{timeSourceNoMatch:!0}:{}}),oe+=pe.wallNs,ue++,a.failOnNonzero&&pe.exitCode!==null&&pe.exitCode!==0&&!ae.has(pe.exitCode))me=!0;return!0},done:de,result(){let pe=X.filter((ce)=>!ce.timedOut&&!ce.timeSourceNoMatch),he=pe.map((ce)=>G?ce.reportedNs:ce.wallNs),ye=[],be=X.filter((ce)=>ce.timedOut).length;if(be>0)ye.push({code:"timeout",message:`${be} of ${X.length} trial(s) timed out after ${a.timeoutMs}ms.`,data:{timeoutMs:a.timeoutMs,trials:be}});let se=X.filter((ce)=>ce.timeSourceNoMatch).length;if(se>0&&a.timeSource){let{pattern:ce}=a.timeSource;ye.push({code:"time-source-no-match",message:`${se} of ${X.length} trial(s) didn't match the timeSource pattern.`,data:{pattern:typeof ce==="string"?ce:ce.source,trials:se,...le!==void 0&&{output:le}}})}if(he.length===0)return{trials:X,warnings:ye};let ge=k(he);return ye.push(...O(ge,pe.map((ce)=>ce.exitCode),G?"reported":"subprocess",A)),{trials:X,timing:ge,warnings:ye}}}}async function en(a){await a.warmup();while(await a.step());}async function z(a){let x=Ze(a);return await en(x),x.result()}async function I(a,x){let v=new Set;for(let E of a)for await(let U of new Bun.Glob(E).scan({cwd:x,absolute:!1}))v.add(U);return[...v].sort()}var hn=new URL("./runner.ts",import.meta.url).pathname;function _(){return Math.max(1,navigator.hardwareConcurrency||1)}async function H(a,x){return I(a,x)}function mt(a){if(a===void 0)return;return a==="auto"?_():a}async function J(a,x,v=process.cwd()){return{suites:a.suites.length>0?a.suites:x?.suites?await H(x.suites,v):[],budgetMs:a.budgetMs??x?.budgetMs,samples:a.samples??x?.samples,minSamples:a.minSamples??x?.minSamples,jobs:a.jobs??mt(x?.jobs),gc:a.gc??x?.gc??!1,cpu:a.cpu??x?.cpu??!1,alloc:a.alloc??x?.alloc??!1,filter:a.filter??x?.filter,isolate:a.isolate??x?.isolate??!1,preload:a.preload.length>0?a.preload:x?.preload??[],bunFlags:a.bunFlags,outDir:a.outDir??x?.outDir,noiseCheck:a.noiseCheck,timeoutMs:a.timeoutMs??x?.timeoutMs,cwd:v}}async function b(a){if(a.samples!==void 0&&(!Number.isFinite(a.samples)||a.samples<1))throw RangeError(`bench: samples must be >= 1, got ${a.samples}`);if(a.minSamples!==void 0&&(!Number.isFinite(a.minSamples)||a.minSamples<1))throw RangeError(`bench: minSamples must be >= 1, got ${a.minSamples}`);if(a.budgetMs!==void 0&&!Number.isFinite(a.budgetMs))throw RangeError(`bench: budgetMs must be finite, got ${a.budgetMs}`);let v=`${a.outDir??Be}/bench-tmp`,E=a.cwd??process.cwd(),U=Math.max(1,Math.floor(a.jobs??1)),ie={budgetMs:a.budgetMs,samples:a.samples,minSamples:a.minSamples,gc:a.gc,cpu:a.cpu,alloc:a.alloc,noiseCheck:a.noiseCheck},G=(ue)=>ue.startsWith("/")?ue:`${E}/${ue}`,A=a.suites.map(G),ae=(a.preload??[]).map(G),X=a.bunFlags??[],oe=async(ue,me)=>{let le=new Set,de=0,fe,pe=async()=>{while(fe===void 0&&!a.signal?.aborted&&de<ue.length){let he=de++;try{let ye=D(a.timeoutMs,a.signal),be=Bun.spawn(ue[he],{cwd:E,stdout:"inherit",stderr:"inherit",stdin:"ignore",...ye.spawn});le.add(be);let se=await be.exited;if(le.delete(be),a.signal?.aborted)return;if(ye.timedOut())throw Error(`Bench suite timed out after ${a.timeoutMs}ms: ${me(he)}`);if(se!==0)throw Error(`Bench suite failed: ${me(he)} (runner exited ${se})`)}catch(ye){fe??=ye instanceof Error?ye:Error(String(ye));for(let be of le)be.kill()}}};if(await Promise.all(Array.from({length:Math.min(U,ue.length)},pe)),fe)throw fe};try{let ue=A.map((ce)=>`${v}/${e("bench-plan",ce)}.json`),me=A.map((ce)=>`${v}/${e("bench-primary",ce)}.json`),le=A.map((ce,we)=>["bun",...X,hn,ce,me[we],JSON.stringify({...ie,filter:a.filter,isolate:a.isolate,preload:ae,planPath:ue[we]})]);await oe(le,(ce)=>a.suites[ce]);let de=await Promise.all(ue.map(async(ce)=>{if(!await Bun.file(ce).exists())return[];let{tasks:we}=await Bun.file(ce).json();return we})),fe=await Promise.all(me.map(async(ce)=>await Bun.file(ce).exists()?r(ce):void 0)),pe=[];for(let ce=0;ce<de.length;ce++)for(let we of de[ce])if(we.isolate)pe.push({suiteIndex:ce,taskIds:[we.id]});let he=pe.map((ce,we)=>`${v}/${e("bench-item",A[ce.suiteIndex],we)}.json`),ye=pe.map((ce,we)=>["bun",...X,hn,A[ce.suiteIndex],he[we],JSON.stringify({...ie,taskIds:ce.taskIds,preload:ae,markIsolated:!0})]);await oe(ye,(ce)=>a.suites[pe[ce].suiteIndex]);let be=await Promise.all(he.map(async(ce)=>await Bun.file(ce).exists()?r(ce):void 0)),se=[],ge=[];for(let ce=0;ce<de.length;ce++){let we=fe[ce];if(!we)continue;let Me=new Map;for(let ke of we.measurements){let $e=Me.get(ke.workloadId)??[];$e.push(ke),Me.set(ke.workloadId,$e)}let Pe=0,xe=new Map;pe.forEach((ke,$e)=>{let Ce=be[$e];if(ke.suiteIndex===ce&&Ce)xe.set(ke.taskIds[0],Ce)});for(let ke of de[ce])if(ke.isolate){let $e=xe.get(ke.id);if(!$e)continue;let Ce=$e.workloads[0];se.push(Ce);for(let Le of $e.measurements)if(Le.workloadId===Ce.id)ge.push(Le)}else{let $e=we.workloads[Pe];se.push($e),Pe++;for(let Ce of Me.get($e.id)??[])ge.push(Ce)}}if(a.signal?.aborted&&ge.length>0){let ce=ge[ge.length-1];ce.warnings=[...ce.warnings,{code:"aborted",message:"Run was cancelled before it finished; this document holds whatever suites/tasks had already completed."}]}return t(se,ge,fe.find((ce)=>ce!==void 0)?.environment)}finally{await Bun.spawn(["rm","-rf",v]).exited}}function Q(a,x,v=8){if(v<=1)throw RangeError(`range: multiplier must be > 1, got ${v}`);if(a<=0)throw RangeError(`range: start must be > 0, got ${a}`);let E=[];for(let U=a;U<=x;U*=v)E.push(U);if(!E.includes(x))E.push(x);return E}function Se(a,x){if(x){let v=a.measurements.find((E)=>E.id===x);return v?.cpu?[v]:[]}return a.measurements.filter((v)=>v.phase==="cpu"&&v.cpu)}function Oe(a){let x=a.nodes,v=x.length,E=ct(a),U=new Int32Array(v).fill(-1);for(let ae=0;ae<v;ae++)for(let X of x[ae].children){let oe=E(X);if(oe!==-1)U[oe]=ae}let ie=[];for(let ae=0;ae<v;ae++)if(U[ae]===-1)ie.push(ae);let G=[],A=[];for(let ae=ie.length-1;ae>=0;ae--)A.push(ie[ae]);while(A.length>0){let ae=A.pop();G.push(ae);for(let X of x[ae].children){let oe=E(X);if(oe!==-1&&U[oe]===ae)A.push(oe)}}return{count:v,indexOf:E,parentIx:U,roots:ie,order:G}}function ct(a){let x=a.nodes,v=x.length,E=1/0,U=-1/0,ie=!0;for(let A=0;A<v;A++){let ae=x[A].id;if(!Number.isInteger(ae)){ie=!1;break}if(ae<E)E=ae;if(ae>U)U=ae}if(ie&&v>0&&U-E<v*4+64){let A=U-E+1,ae=new Int32Array(A).fill(-1);for(let X=0;X<v;X++)ae[x[X].id-E]=X;return(X)=>{let oe=X-E;return oe>=0&&oe<A?ae[oe]:-1}}let G=new Map;for(let A=0;A<v;A++)G.set(x[A].id,A);return(A)=>G.get(A)??-1}function bn(a,x){let{count:v,indexOf:E,parentIx:U,order:ie}=x,G=new Float64Array(v),A=new Float64Array(v),ae=a.samples?.nodeIds??[],X=a.samples?.timeDeltasUs??[];for(let ue=0;ue<ae.length;ue++){let me=E(ae[ue]);if(me===-1)continue;G[me]+=X[ue]??0,A[me]+=1}let oe=new Float64Array(v);for(let ue=ie.length-1;ue>=0;ue--){let me=ie[ue];oe[me]+=G[me];let le=U[me];if(le>=0)oe[le]+=oe[me]}return{selfUs:G,totalUs:oe,samples:A}}var wn={name:"collapsed",async render(a,x={}){return{files:Se(a,x.measurementId).map((U)=>{let ie=U.cpu,{nodes:G,frames:A}=ie,ae=Oe(ie),X=Array(ae.count);for(let de of ae.order){let fe=A[G[de].frameIx].name||"(anonymous)",pe=ae.parentIx[de];X[de]=pe===-1?fe:`${X[pe]};${fe}`}let oe=new Float64Array(ae.count),ue=[],me=ie.samples?.nodeIds??[];for(let de=0;de<me.length;de++){let fe=ae.indexOf(me[de]);if(fe===-1)continue;if(oe[fe]++===0)ue.push(fe)}let le=Array(ue.length);for(let de=0;de<ue.length;de++){let fe=ue[de];le[de]=`${X[fe]} ${oe[fe]}`}return{path:`${U.id}.collapsed.txt`,content:le.join(`
|
|
3
|
+
`)+(le.length>0?`
|
|
4
|
+
`:"")}})}}};var yn={name:"cpuprofile",async render(a,x={}){let v=Se(a,x.measurementId),E=[],U=[];for(let ie of v){if(ie.cpu?.origin!=="cpu-prof"&&ie.cpu?.origin!=="inspector"){U.push(`${ie.id} (origin ${ie.cpu?.origin??"unknown"} has no .cpuprofile artifact to pass through)`);continue}let G=ie.artifacts.find((ae)=>ae.kind==="cpuprofile");if(!G){U.push(`${ie.id} (no cpuprofile artifact recorded on this run)`);continue}let A=Bun.file(G.path);if(!await A.exists()){U.push(`${ie.id} (artifact missing on disk: ${G.path})`);continue}E.push({path:`${ie.id}.cpuprofile`,content:await A.text()})}if(E.length===0&&U.length>0)return{text:`No .cpuprofile artifacts available:
|
|
5
|
+
${U.map((ie)=>` - ${ie}`).join(`
|
|
6
|
+
`)}
|
|
7
|
+
`};return{files:E}}};var xn={name:"json",async render(a){return{text:f(a)}}};var Pn={name:"jsonl",async render(a){let{measurements:x,...v}=a;return{text:`${[y({kind:"document",...v}),...x.map((U)=>y({kind:"measurement",...U}))].join(`
|
|
8
|
+
`)}
|
|
9
|
+
`}}};var Ne=0.5,ut={ns:1,\u{b5}s:1000,ms:1e6,s:1e9};function Ae(a){let x=Math.abs(a);if(x>=1e9)return"s";if(x>=1e6)return"ms";if(x>=1000)return"\xB5s";return"ns"}function lt(a){let x=Math.floor(Math.log10(Math.max(Math.abs(a),1)))+1;return Math.max(1,3-x)}function ve(a,x=Ae(a)){let v=a/ut[x];return`${v.toFixed(lt(v))} ${x}`}function ze(a){return`${a.cpuModel} \xB7 ${a.cores} cores \xB7 load ${a.loadAvg1.toFixed(1)} \xB7 noise floor ${a.noise.floorPct.toFixed(1)}%`}function w(a){return`${a.sha} (${a.branch}${a.dirty?", dirty":""})`}function n(a){return a?.label??a?.command?.join(" ")??a?.entry?.task??a?.id??"unknown"}function Ge(a,x){if(a===1)return x?"1.00\xD7 (baseline)":"1.00\xD7";if(a>1)return`${a.toFixed(2)}\xD7 slower`;return`${(1/a).toFixed(2)}\xD7 faster`}function kn(a){return a.replace(/\|/g,"\\|").replace(/</g,"<").replace(/>/g,">").replace(/`/g,"\\`").replace(/\r\n|\r|\n/g,"<br>")}function Ke(a){if(!a?.entry)return;if(a.entry.group!==void 0)return a.entry.group;let x=a.entry.task,v=x.lastIndexOf("/");return v===-1?void 0:x.slice(0,v)}function Fe(a){let x=Math.min(...a.map((U)=>U.run.timing.median)),v=new Map;for(let U of a){let ie=Ke(U.workload);if(ie===void 0)continue;let G=v.get(ie);if(G)G.push(U);else v.set(ie,[U])}let E=new Map;for(let U of a){let ie=Ke(U.workload);if(ie===void 0){E.set(U,x);continue}let G=v.get(ie)??[U],A=G.find((ae)=>ae.workload?.baseline);E.set(U,A?A.run.timing.median:Math.min(...G.map((ae)=>ae.run.timing.median)))}return E}function We(a){return a.measurements.filter((x)=>x.phase==="timing"&&x.timing!==void 0)}function Ee(a,x){let v=new Set(x.map((E)=>E.workloadId));return a.workloads.filter((E)=>E.skipped&&!v.has(E.id))}function Je(a){for(let x of a.comparisons??[]){let v=x.warnings?.find((E)=>E.code==="environment-mismatch");if(v)return v}return}function Mn(a){return(a/1e6).toFixed(3)}function Rn(a){if(!a?.params)return"";return` (${Object.entries(a.params).map(([v,E])=>`${v}=${E}`).join(", ")})`}function Te(a){return kn(String(a))}function dt(a){let x;for(let v of a){let E=v?.params?Object.keys(v.params):void 0;if(E?.length!==2)return;if(x===void 0)x=E;else if(E.length!==x.length||E.some((U,ie)=>U!==x[ie]))return}return x}var $n=10,vn=10,Cn={name:"markdown",async render(a){let x=new Map(a.workloads.map((A)=>[A.id,A])),v=[];v.push("# Profile Report","");let E=a.git?` \xB7 ${w(a.git)}`:"";if(v.push(`Bun ${a.bunVersion} \xB7 ostia ${a.toolVersion} \xB7 ${a.platform.os}/${a.platform.arch} \xB7 ${a.createdAt}${E}`,""),a.environment)v.push(ze(a.environment),"");let U=Je(a);if(U)v.push(`> \u26A0 ${U.message}`,"");let ie=We(a),G=Ee(a,ie);if(ie.length>0||G.length>0){v.push("## Timing","");let A=new Map,ae=[];for(let ue of ie){let me=x.get(ue.workloadId)?.entry?.group;if(me===void 0){ae.push(ue);continue}let le=A.get(me);if(le)le.push(ue);else A.set(me,[ue])}let X=new Map;for(let[ue,me]of A){let le=dt(me.map((de)=>x.get(de.workloadId)));if(le)X.set(ue,{keys:le,runs:me});else ae.push(...me)}if(ae.length>0||G.length>0){let ue=ie.map((he)=>({run:he,workload:x.get(he.workloadId)})),me=ue.length>1,le=me?Fe(ue):void 0,de=new Map(ue.map((he)=>[he.run.id,le?.get(he)??he.run.timing.median])),fe=me?" Relative |":"",pe=me?"---|":"";v.push(`| Task | Median | Spread (p75\u2026p99) | Mean \xB1 SD | Range | MAD |${fe}`,`|---|---|---|---|---|---|${pe}`);for(let he of ae){let ye=x.get(he.workloadId),be=Te(n(ye)+Rn(ye)),se=he.timing,ge=Ae(se.median),ce=se.p75??se.median,we=se.p99??se.max,Me=se.mad!==void 0?ve(se.mad,ge):"-",Pe=me?` ${Ge(se.median/(de.get(he.id)??se.median),!!ye?.baseline)} |`:"";v.push(`| ${be} | ${ve(se.median,ge)} | ${ve(ce,ge)}\u2026${ve(we,ge)} | ${ve(se.mean,ge)} \xB1 ${ve(se.stddev,ge)} | ${ve(se.min,ge)}\u2026${ve(se.max,ge)} | ${Me} |${Pe}`)}for(let he of G){let ye=Te(n(he)+Rn(he)),be=me?" - |":"";v.push(`| ${ye} | - skipped | - | - | - | - |${be}`)}v.push("")}for(let[ue,{keys:me,runs:le}]of X){let[de,fe]=me,pe=[],he=[],ye=new Map;for(let be of le){let se=x.get(be.workloadId).params,ge=se[de],ce=se[fe];if(!pe.includes(ge))pe.push(ge);if(!he.includes(ce))he.push(ce);ye.set(`${ge}\x00${ce}`,be)}v.push(`### ${Te(ue)} (${Te(de)} \xD7 ${Te(fe)})`,""),v.push(`| ${Te(de)} \\ ${Te(fe)} | ${he.map(Te).join(" | ")} |`,`|---|${he.map(()=>"---").join("|")}|`);for(let be of pe){let se=he.map((ge)=>{let ce=ye.get(`${be}\x00${ge}`);return ce?ve(ce.timing.median):"-"});v.push(`| ${Te(be)} | ${se.join(" | ")} |`)}v.push("")}let oe=ie.filter((ue)=>ue.warnings.length>0);if(oe.length>0){v.push("### Warnings","");for(let ue of oe){let me=n(x.get(ue.workloadId));for(let le of ue.warnings)v.push(`- **${me}**: ${le.message} (\`${le.code}\`)`)}v.push("")}}for(let A of a.measurements){if(A.phase!=="cpu"&&A.phase!=="heap")continue;let ae=n(x.get(A.workloadId));if(A.phase==="cpu"){if(v.push(`## CPU capture - ${ae}`,""),v.push(`instrumented, diagnostic wall ${Mn(A.diagnosticWallNs??0)}ms`,""),A.cpu){v.push(`origin: \`${A.cpu.origin}\`, interval: ${A.cpu.samplingIntervalUs}\xB5s`,""),v.push("| Self % | Self (ms) | Total (ms) | Frame |","|---|---|---|---|");let X=A.cpu.totals.reduce((oe,ue)=>oe+ue.selfUs,0)||1;for(let oe of A.cpu.totals.slice(0,$n)){let ue=A.cpu.frames[oe.frameIx],me=(oe.selfUs/X*100).toFixed(1);v.push(`| ${me}% | ${(oe.selfUs/1000).toFixed(2)} | ${(oe.totalUs/1000).toFixed(2)} | ${Te(ue?.name||"(anonymous)")} |`)}if(v.push(""),A.jit){let oe=A.jit.tiers;v.push(`JIT tiers: LLInt ${oe.llint} \xB7 Baseline ${oe.baseline} \xB7 DFG ${oe.dfg} \xB7 FTL ${oe.ftl}`,"")}}}else if(v.push(`## Heap snapshot - ${ae}`,""),v.push(`instrumented, diagnostic wall ${Mn(A.diagnosticWallNs??0)}ms`,""),A.heap){v.push(`${A.heap.objectCount??"?"} objects, ${((A.heap.heapSizeBytes??0)/1e6).toFixed(2)}MB`,""),v.push("| Count | Type |","|---|---|");for(let X of A.heap.typeCounts.slice(0,vn))v.push(`| ${X.count} | ${Te(X.type)} |`);v.push("")}for(let X of A.artifacts)v.push(`- artifact: \`${X.path}\``);for(let X of A.warnings)v.push(`- ! ${X.message} (\`${X.code}\`)`);if(A.artifacts.length>0||A.warnings.length>0)v.push("")}if(a.comparisons&&a.comparisons.length>0){v.push("## Comparisons","");for(let A of a.comparisons){let ae=a.measurements.find((oe)=>oe.id===A.candidateMeasurementId),X=n(ae?x.get(ae.workloadId):x.get(A.candidateMeasurementId));if(v.push(`### ${A.verdict==="pass"?"\u2713":"\u2717"} ${X}`,""),A.timing){let oe=A.timing.medianDeltaPct>0?"+":"",ue=A.timing.verdict==="unchanged"&&A.timing.pValue!==void 0&&A.timing.pValue>=A.thresholds.alpha?"~":"",me=[];if(ae?.timing)me.push(`n=${ae.timing.samples.length}`);if(A.timing.ci95)me.push(`95% CI [${A.timing.ci95[0]>0?"+":""}${A.timing.ci95[0].toFixed(1)}%, ${A.timing.ci95[1]>0?"+":""}${A.timing.ci95[1].toFixed(1)}%]`);if(A.timing.pValue!==void 0)me.push(`p=${A.timing.pValue.toFixed(4)}`);me.push(`threshold ${A.thresholds.effectiveTimingPct.toFixed(1)}%`),v.push(`- timing: ${ue}${oe}${A.timing.medianDeltaPct.toFixed(1)}% median, ${me.join(", ")} (**${A.timing.verdict}**)`)}for(let oe of A.frames?.slice(0,$n)??[]){if(Math.abs(oe.deltaPct)<Ne)continue;let ue=oe.deltaPct>0?"+":"";v.push(`- frame \`${Te(oe.name)}\`: ${ue}${oe.deltaPct.toFixed(1)}% self-time (${(oe.baseSelfUs/1000).toFixed(2)}ms \u2192 ${(oe.candSelfUs/1000).toFixed(2)}ms)`)}for(let oe of A.heapTypes?.slice(0,vn)??[]){if(Math.abs(oe.deltaPct)<Ne)continue;let ue=oe.deltaPct>0?"+":"";v.push(`- heap \`${Te(oe.type)}\`: ${ue}${oe.deltaPct.toFixed(1)}% count (${oe.baseCount} \u2192 ${oe.candCount})`)}for(let oe of A.warnings??[]){if(oe.code==="environment-mismatch")continue;v.push(`- ! ${oe.message} (\`${oe.code}\`)`)}v.push("")}}return{text:v.join(`
|
|
10
|
+
`)}}};var pt=15;function nn(a){return`n${a}`}function ft(a,x,v){return`${(a||"(anonymous)").replace(/"/g,"'")} (self ${(x/1000).toFixed(2)}ms, total ${(v/1000).toFixed(2)}ms)`}function gt(a,x,v,E){let U=[];if(E<=0)return U;for(let ie=0;ie<x;ie++){if(ie===v)continue;let G=a[ie];if(U.length===E&&G<=a[U[E-1]])continue;let A=U.length;while(A>0&&a[U[A-1]]<G)A--;if(U.splice(A,0,ie),U.length>E)U.pop()}return U}var Tn={name:"mermaid",async render(a,x={}){let v=x.topN??pt;return{files:Se(a,x.measurementId).map((ie)=>{let G=ie.cpu,{nodes:A,frames:ae}=G,X=Oe(G),{selfUs:oe,totalUs:ue}=bn(G,X),{parentIx:me}=X,le=X.roots[0]??-1,de=gt(oe,X.count,le,v),fe=new Set(le!==-1?[le]:[]),pe=[];for(let ye of de){pe.length=0;for(let be=ye;be!==-1;be=me[be])pe.push(be);for(let be=pe.length-1;be>=0;be--)fe.add(pe[be])}let he=["graph TD"];for(let ye of fe){let be=A[ye].id;he.push(` ${nn(be)}["${ft(ae[A[ye].frameIx].name,oe[ye],ue[ye])}"]`)}for(let ye of fe){let be=me[ye];if(be!==-1&&fe.has(be))he.push(` ${nn(A[be].id)} --> ${nn(A[ye].id)}`)}return{path:`${ie.id}.mermaid.md`,content:`${he.join(`
|
|
11
|
+
`)}
|
|
12
|
+
`}})}}};var u=1;function Re(a){return Number.isFinite(a)?Number(a.toPrecision(6)):a}function tn(a,x){return a?.entry?.task??a?.label??a?.command?.join(" ")??x}function In(a,x){if(x?.entry?.group!==void 0)a.group=x.entry.group;if(x?.description!==void 0)a.description=x.description;if(x?.groupDescription!==void 0)a.groupDescription=x.groupDescription;if(x?.params!==void 0)a.params=x.params}function Sn(a){if(!a?.timing)return;let x={medianPct:Re(a.timing.medianDeltaPct),meanPct:Re(a.timing.meanDeltaPct),verdict:a.timing.verdict,pass:a.verdict==="pass",effectiveTimingPct:Re(a.thresholds.effectiveTimingPct),matched:!0};if(a.timing.ci95)x.ci95=[Re(a.timing.ci95[0]),Re(a.timing.ci95[1])];if(a.timing.pValue!==void 0)x.pValue=Re(a.timing.pValue);return x}function ht(a,x,v,E){let U={event:"run",protocolVersion:u,schemaVersion:a.schemaVersion,workloadId:x.id,task:tn(x,x.id),skipped:!0,batch:1,warnings:(v?.warnings??[]).map((G)=>G.data?{code:G.code,data:G.data}:{code:G.code})};if(In(U,x),E!==void 0)U.noiseFloorPct=Re(E);let ie=Sn(v);if(ie)U.delta=ie;return U}function bt(a){let x=new Map(a.workloads.map((X)=>[X.id,X])),v=a.environment?.noise.floorPct,E=We(a).map((X)=>({run:X,workload:x.get(X.workloadId)})),U=E.length>1?Fe(E):void 0,ie=new Map((a.comparisons??[]).map((X)=>[X.candidateMeasurementId,X])),G=new Map;for(let X of a.measurements){if(X.phase!=="cpu"||X.warnings.length===0)continue;let oe=G.get(X.workloadId)??[];G.set(X.workloadId,[...oe,...X.warnings])}let A=Ee(a,E.map((X)=>X.run)).map((X)=>ht(a,X,ie.get(X.id),v));return[...E.map((X)=>{let{run:oe,workload:ue}=X,me=oe.timing,le=ie.get(oe.id),de={event:"run",protocolVersion:u,schemaVersion:a.schemaVersion,workloadId:oe.workloadId,task:tn(ue,oe.workloadId),unit:"ns",samples:me.samples.length,batch:me.batch??1,mean:Re(me.mean),median:Re(me.median),stddev:Re(me.stddev),stddevPct:Re(me.mean===0?0:me.stddev/me.mean*100),min:Re(me.min),max:Re(me.max),warnings:[...oe.warnings,...G.get(oe.workloadId)??[],...le?.warnings??[]].map((pe)=>pe.data?{code:pe.code,data:pe.data}:{code:pe.code})};if(me.p75!==void 0)de.p75=Re(me.p75);if(me.p99!==void 0)de.p99=Re(me.p99);if(me.mad!==void 0)de.mad=Re(me.mad);if(In(de,ue),U)de.relative=Re(me.median/(U.get(X)??me.median));if(ue?.baseline)de.baseline=!0;if(v!==void 0)de.noiseFloorPct=Re(v);let fe=Sn(le);if(fe)de.delta=fe;return de}),...A]}function wt(a){if(!a.unmatched)return[];let x=(v,E)=>({event:"unmatched",protocolVersion:u,workloadId:v.id,task:tn(v,v.id),side:E});return[...a.unmatched.baseOnly.map((v)=>x(v,"base")),...a.unmatched.candOnly.map((v)=>x(v,"cand"))]}function yt(a,x){let v=a.comparisonSummary,E=(x.unmatched?.baseOnly.length??0)+(x.unmatched?.candOnly.length??0),U={event:"summary",protocolVersion:u,command:x.command,matched:v?.matched??0,regressed:v?.regressed??0,improved:v?.improved??0,unchanged:v?.unchanged??0,unmatched:E,geomeanPct:v?.geomeanPct!==void 0?v.geomeanPct:null,effectiveTimingPct:Re(v?.effectiveTimingPct??0),verdict:x.exitCode===0?"pass":"fail",exitCode:x.exitCode};if(x.command==="ci"){if(U.cached=x.cached??0,U.executed=x.executed??0,U.failed=x.failed??0,U.missingBaseline=x.missingBaseline??0,x.baseline)U.baseline=x.baseline}if(a.environment)U.noiseFloorPct=Re(a.environment.noise.floorPct);if(x.baseGit||x.candGit)U.git={...x.baseGit&&{base:x.baseGit},...x.candGit&&{cand:x.candGit}};if(x.exportedTo)U.exportedTo=x.exportedTo;return U}var Dn={name:"minimal",async render(a,x={}){let v=[...bt(a)];if(x.protocol)v.push(...wt(x.protocol)),v.push(yt(a,x.protocol));let E=v.map((U)=>JSON.stringify(U));return{text:E.length>0?`${E.join(`
|
|
13
|
+
`)}
|
|
14
|
+
`:""}}};var xt="https://www.speedscope.app/file-format-schema.json";function On(a){return a?.label??a?.command?.join(" ")??a?.entry?.task??"profile"}var Nn={name:"speedscope",async render(a,x={}){let v=Se(a,x.measurementId),E=new Map(a.workloads.map((ie)=>[ie.id,ie]));return{files:v.map((ie)=>{let G=ie.cpu,{nodes:A}=G,ae=Oe(G),X=G.samples?.nodeIds??[],oe=G.samples?.timeDeltasUs??[],ue=Array(ae.count);for(let fe of ae.order){let pe=ae.parentIx[fe],he=A[fe].frameIx;ue[fe]=pe===-1?[he]:[...ue[pe],he]}let me=Array(X.length);for(let fe=0;fe<X.length;fe++){let pe=ae.indexOf(X[fe]);me[fe]=pe===-1?[]:ue[pe]}let le=0;for(let fe=0;fe<oe.length;fe++)le+=oe[fe];let de={$schema:xt,exporter:"ostia",name:On(E.get(ie.workloadId)),activeProfileIndex:0,shared:{frames:G.frames.map((fe)=>({name:fe.name||"(anonymous)",file:fe.url,line:fe.line!==void 0?fe.line+1:void 0}))},profiles:[{type:"sampled",name:On(E.get(ie.workloadId)),unit:"microseconds",startValue:0,endValue:le,samples:me,weights:oe}]};return{path:`${ie.id}.speedscope.json`,content:`${JSON.stringify(de,null,2)}
|
|
15
|
+
`}})}}};function Pt(a){return(a/1e6).toFixed(3)}function kt(a){if(a<1024)return`${a.toFixed(0)}B`;if(a<1048576)return`${(a/1024).toFixed(2)}KB`;return`${(a/1048576).toFixed(2)}MB`}var Wn={name:"table",async render(a){let x=We(a),v=new Map(a.workloads.map((xe)=>[xe.id,xe])),E=a.environment?[ze(a.environment),""]:[],U=Ee(a,x);if(x.length===0&&U.length===0){let xe=Fn(a,v);return{text:xe.length>0?`${[...E,...xe].join(`
|
|
16
|
+
`)}
|
|
17
|
+
`:`(no timing runs)
|
|
18
|
+
`}}let ie=new Map(x.map((xe)=>[xe.workloadId,xe])),G=[],A=[];for(let xe of a.workloads){let ke=ie.get(xe.id),$e=n(xe);if(ke){let Ce={kind:"measured",run:ke,workload:xe,label:$e};G.push(Ce),A.push(Ce)}else if(xe.skipped)G.push({kind:"skipped",workload:xe,label:$e})}let ae=new Map(a.measurements.filter((xe)=>xe.phase==="memstats"&&xe.memory?.bytesPerOp!==void 0).map((xe)=>[xe.workloadId,xe.memory.bytesPerOp])),X=ae.size>0,oe=A.length>1,ue=Fe(A),me=new Map,le=new Map,de;for(let xe of G){let ke=Ke(xe.workload);if(ke!==de){if(ke!==void 0)le.set(xe,ke);de=ke}me.set(xe,ke!==void 0?" ":"")}let fe=Math.max(4,...G.map((xe)=>me.get(xe).length+xe.label.length)),pe=10,he=18,ye=18,be=10,se=[...E],ge=X?` ${"Alloc/op".padEnd(be)}`:"",ce=`${"Task".padEnd(fe)} ${"Median".padEnd(pe)} ${"Spread".padEnd(he)} ${"Range".padEnd(ye)}${ge}${oe?" Relative":""}`;se.push(ce),se.push("-".repeat(ce.length));let we=[];for(let xe of G){let ke=le.get(xe);if(ke!==void 0)se.push(`${ke}:`);let $e=me.get(xe);if(xe.kind==="skipped"){se.push(`${($e+xe.label).padEnd(fe)} - skipped`);continue}let{run:Ce,label:Le,workload:Ye}=xe,Ie=Ce.timing,Ue=Ae(Ie.median),Ln=Ie.p75??Ie.median,_n=Ie.p99??Ie.max,jn=ve(Ie.median,Ue),Vn=`${ve(Ln,Ue)}\u2026${ve(_n,Ue)}`,Hn=`${ve(Ie.min,Ue)}\u2026${ve(Ie.max,Ue)}`,qe=`${($e+Le).padEnd(fe)} ${jn.padEnd(pe)} ${Vn.padEnd(he)} ${Hn.padEnd(ye)}`;if(X){let De=Ye?ae.get(Ye.id):void 0,zn=De!==void 0?kt(De):"";qe+=` ${zn.padEnd(be)}`}if(oe){let De=Ie.median/(ue.get(xe)??Ie.median);qe+=` ${Ge(De,!!Ye?.baseline)}`}if(se.push(qe),Ce.warnings.length>0)se.push(`${" ".repeat($e.length)} ! ${Ce.warnings.map((De)=>De.code).join(", ")}`),we.push(xe)}if(we.length>0){se.push(""),se.push("Warnings:");for(let xe of we)for(let ke of xe.run.warnings)se.push(` ${xe.label}: ${ke.message}`)}let Me=Mt(a,v);if(Me.length>0)se.push(""),se.push(...Me);let Pe=Fn(a,v);if(Pe.length>0)se.push(""),se.push(...Pe);return{text:`${se.map((xe)=>xe.trimEnd()).join(`
|
|
19
|
+
`)}
|
|
20
|
+
`}}};function Fn(a,x){if(!a.comparisons||a.comparisons.length===0)return[];let v=[],E=new Map(a.measurements.map((G)=>[G.id,G])),U=Je(a);if(U)v.push(`\u26A0 ${U.message}`,"");let ie=[];for(let G of a.comparisons){let A=E.get(G.candidateMeasurementId),ae=x.get(A?.workloadId??G.candidateMeasurementId),X=ae?n(ae):G.candidateMeasurementId,oe=G.verdict==="pass"?"\u2713":"\u2717";if(v.push(`${oe} ${X}`),G.timing){let me=(le)=>`${le>=0?"+":""}${le.toFixed(1)}%`;if(G.timing.ci95&&G.timing.pValue!==void 0){let le=G.timing.pValue<0.001?"p<0.001":`p=${G.timing.pValue.toFixed(3)}`;v.push(` timing: ${me(G.timing.medianDeltaPct)} median, 95% CI [${me(G.timing.ci95[0])}, ${me(G.timing.ci95[1])}], ${le} (${G.timing.verdict})`)}else v.push(` timing: ${me(G.timing.medianDeltaPct)} median (${G.timing.verdict})`)}if(G.frames)for(let me of G.frames.slice(0,En)){if(Math.abs(me.deltaPct)<Ne)continue;let le=me.deltaPct>0?"+":"";v.push(` frame ${me.name}: ${le}${me.deltaPct.toFixed(1)}% self-time (${(me.baseSelfUs/1000).toFixed(2)}ms -> ${(me.candSelfUs/1000).toFixed(2)}ms)`)}if(G.heapTypes)for(let me of G.heapTypes.slice(0,Un)){if(Math.abs(me.deltaPct)<Ne)continue;let le=me.deltaPct>0?"+":"";v.push(` heap ${me.type}: ${le}${me.deltaPct.toFixed(1)}% count (${me.baseCount} -> ${me.candCount})`)}let ue=(G.warnings??[]).filter((me)=>me.code!=="environment-mismatch");if(ue.length>0){v.push(` ! ${ue.map((me)=>me.code).join(", ")}`);for(let me of ue)ie.push({label:X,message:me.message})}}if(ie.length>0){v.push("","Comparison warnings:");for(let G of ie)v.push(` ${G.label}: ${G.message}`)}return v}var En=5,Un=5;function Mt(a,x){let v=[];for(let E of a.measurements){if(E.phase!=="cpu"&&E.phase!=="heap")continue;let U=x.get(E.workloadId),ie=U?n(U):E.workloadId;if(E.phase==="cpu")if(E.cpu){v.push(`CPU capture - ${ie} (instrumented, ${E.cpu.samplingIntervalUs}\xB5s interval, diagnostic wall ${Pt(E.diagnosticWallNs??0)}ms)`);let G=E.cpu.totals.reduce((A,ae)=>A+ae.selfUs,0)||1;for(let A of E.cpu.totals.slice(0,En)){let ae=E.cpu.frames[A.frameIx],X=(A.selfUs/G*100).toFixed(1);v.push(` ${X.padStart(5)}% ${(A.selfUs/1000).toFixed(2).padStart(8)}ms self ${ae?.name??"?"}`)}}else v.push(`CPU capture - ${ie} (instrumented, no evidence captured)`);else if(E.heap){let G=((E.heap.heapSizeBytes??0)/1e6).toFixed(2);v.push(`Heap snapshot - ${ie} (instrumented, ${E.heap.objectCount??"?"} objects, ${G}MB)`);for(let A of E.heap.typeCounts.slice(0,Un))v.push(` ${String(A.count).padStart(6)} ${A.type}`)}else v.push(`Heap snapshot - ${ie} (instrumented, no evidence captured)`);for(let G of E.artifacts)v.push(` artifact: ${G.path}`);for(let G of E.warnings)v.push(` ! ${G.message}`)}return v}var i={table:Wn,json:xn,markdown:Cn,jsonl:Pn,minimal:Dn,collapsed:wn,mermaid:Tn,speedscope:Nn,cpuprofile:yn};async function ee(a={}){let x=M();if(x.length===0)throw Error("run(): no tasks registered - call group()/task() before run() in the same file.");let v=x.filter((A)=>A.only),E=v.length>0?v:x;if(v.length>0)process.stderr.write(`bench: ${v.length} task(s) selected by .only
|
|
21
|
+
`);let U=T(E,a.filter);if(U.length===0)throw Error(`run(): filter ${JSON.stringify(a.filter)} matched zero of ${E.length} registered task(s).`);let ie=Bun.main,G=await R(ie,U,a);if(!a.quiet){let A=a.format??"table",{text:ae}=await i[A].render(G,{});if(ae)process.stdout.write(ae)}return G}function ne(a,x){let v=Object.keys(a),E=(U,ie)=>{if(U===v.length){Z(ie,()=>x(ie));return}let G=v[U];for(let A of a[G])E(U+1,{...ie,[G]:A})};E(0,{})}function te(a){return a}var rn=1000;async function V(a){if(a.samples!==void 0&&(!Number.isFinite(a.samples)||a.samples<1))throw RangeError(`time: samples must be >= 1, got ${a.samples}`);if(a.minSamples!==void 0&&(!Number.isFinite(a.minSamples)||a.minSamples<1))throw RangeError(`time: minSamples must be >= 1, got ${a.minSamples}`);if(a.warmup!==void 0&&(!Number.isFinite(a.warmup)||a.warmup<0))throw RangeError(`time: warmup must be >= 0, got ${a.warmup}`);if(a.budgetMs!==void 0&&!Number.isFinite(a.budgetMs))throw RangeError(`time: budgetMs must be finite, got ${a.budgetMs}`);let x=o({samples:a.samples??null,budgetMs:a.budgetMs??null,minSamples:a.minSamples??null,warmup:a.warmup??null,cpu:a.cpu??!1,heap:a.heap??!1,cpuIntervalUs:a.cpuIntervalUs??rn}),E=`${a.outDir??Be}/artifacts`,U=a.noiseCheck===!1?void 0:g(),ie=U?h(U):void 0,G=[],A=[],ae=a.commands.map((le)=>{let de=typeof le==="string"||Array.isArray(le)?{command:le}:le,fe=Array.isArray(de.command)?de.command:m(de.command),pe=de.prepare??a.prepare,he=de.timeSource??a.timeSource,ye=de.timeoutMs??a.timeoutMs,be=de.ignoreExitCodes??a.ignoreExitCodes,se=de.failOnNonzero??a.failOnNonzero,ge=P(fe,de.label??(Array.isArray(de.command)?void 0:de.command),{prepare:pe,timeSource:he});return{argv:fe,workload:ge,prepare:pe,timeSource:he,timeoutMs:ye,ignoreExitCodes:be,failOnNonzero:se}}),X=(a.interleave??!0)&&ae.length>1,oe=(le)=>({argv:le.argv,cwd:a.cwd,env:a.env,samples:a.samples,budgetMs:a.budgetMs,minSamples:a.minSamples,warmup:a.warmup,prepare:le.prepare,timeSource:le.timeSource,timeoutMs:le.timeoutMs,ignoreExitCodes:le.ignoreExitCodes,failOnNonzero:le.failOnNonzero,signal:a.signal}),ue=ae.map((le)=>Ze(oe(le))),me=async(le)=>{let{argv:de,workload:fe,prepare:pe}=ae[le];G.push(fe);let he=ue[le].result(),ye=d({workload:fe,configFingerprint:x,trials:he.trials,timing:he.timing,warnings:ie&&A.length===0?[...he.warnings,ie]:he.warnings,interleaved:X?!0:void 0});if(A.push(ye),!a.signal?.aborted)A.push(...await Rt({workload:fe,argv:de,timingMeasurementId:ye.id,cfgFp:x,opts:a,artifactDir:E,prepare:pe}))};if(X){for(let de of ue)await de.warmup();let le=!0;while(le){le=!1;for(let de of ue)if(await de.step())le=!0}for(let de=0;de<ae.length;de++)await me(de)}else for(let le=0;le<ae.length;le++)await en(ue[le]),await me(le);if(a.signal?.aborted&&A.length>0){let le=A[A.length-1];le.warnings=[...le.warnings,An()]}return t(G,A,U)}function An(){return{code:"aborted",message:"Run was cancelled before it finished; this document holds whatever measurements had already completed."}}async function Rt({workload:a,argv:x,timingMeasurementId:v,cfgFp:E,opts:U,artifactDir:ie,prepare:G}){let A=[],ae=async(X)=>{if(G)await F(G,{phase:X,index:0},{cwd:U.cwd,env:U.env})};if(U.cpu){await ae("cpu");let X=`${v}-cpu.cpuprofile`,oe=await on({argv:x,cwd:U.cwd,env:U.env,artifactDir:ie,fileName:X,intervalUs:U.cpuIntervalUs??rn});A.push(await Bn({workload:a,phase:"cpu",configFingerprint:E,diagnosticWallNs:oe.diagnosticWallNs,exitCode:oe.exitCode,cpu:oe.cpu,artifactPath:oe.artifactPath,artifactKind:"cpuprofile",warnings:oe.warnings}))}if(U.heap){await ae("heap");let X=`${v}-heap.heapsnapshot`,oe=await an({argv:x,cwd:U.cwd,env:U.env,artifactDir:ie,fileName:X});A.push(await Bn({workload:a,phase:"heap",configFingerprint:E,diagnosticWallNs:oe.diagnosticWallNs,exitCode:oe.exitCode,heap:oe.heap,artifactPath:oe.artifactPath,artifactKind:"heapsnapshot",warnings:oe.warnings}))}return A}async function Bn(a){let x=`${a.workload.id}-${a.phase}-${a.configFingerprint}`,v=a.artifactPath?[await Y(x,a.artifactKind,a.artifactPath)]:[];return p({workload:a.workload,phase:a.phase,configFingerprint:a.configFingerprint,diagnosticWallNs:a.diagnosticWallNs,exitCode:a.exitCode,cpu:a.cpu,heap:a.heap,warnings:a.warnings,artifacts:v})}async function re(a,x={}){let v=K(a),E=o({intervalUs:x.intervalUs??rn,origin:x.origin??"inspector"}),U=(A)=>A.samples?.nodeIds.length===0?[{code:"empty-profile",message:"In-process capture produced zero samples."}]:[];if(x.signal?.aborted){let A=Bun.nanoseconds(),ae=await a(),X=p({workload:v,phase:"cpu",configFingerprint:E,diagnosticWallNs:Bun.nanoseconds()-A,warnings:[An()],artifacts:[]});return{result:ae,measurement:X,document:t([v],[X])}}let ie=x.origin==="jsc"?await B(a,x):{...await mn(a,x),jit:void 0},G=p({workload:v,phase:"cpu",configFingerprint:E,diagnosticWallNs:ie.diagnosticWallNs,cpu:ie.cpu,jit:ie.jit,warnings:U(ie.cpu),artifacts:[]});return{result:ie.result,measurement:G,document:t([v],[G])}}
|
|
22
|
+
export{c,W,j,C,S,s,L,I,_,H,J,b,z,w,n,Q,u,i,ee,ne,te,V,re};
|
package/cli.js
CHANGED
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{
|
|
4
|
-
`)}class
|
|
3
|
+
import{e,m,x,t,P,d,o,f,E,a,r,g,h}from"./chunk-1wydyvyj.js";import{c,W,j,C,S,s,L,I,_,H,J,b,z,w,n,u,i,V}from"./chunk-cf9hya3b.js";function he(p){return e("cache",p.workloadId,p.phase,p.configFingerprint,p.bunVersion,p.toolVersion,p.instrumented,p.inputsDigest??null)}async function ge(p,l=process.cwd()){if(p.length===0)return;let k=await I(p,l),y=await Promise.all(k.map(async(v)=>{let M=await Bun.file(`${l}/${v}`).arrayBuffer();return{path:v,sha256:Bun.CryptoHasher.hash("sha256",M,"hex")}}));return e("inputs",y)}function be(p,l){return`${p}/cache/${l}.json`}async function we(p,l){let k=Bun.file(be(p,l));if(!await k.exists())return;return await k.json()}async function ke(p,l,k){await Bun.write(be(p,l),`${JSON.stringify(k,null,2)}
|
|
4
|
+
`)}var ve=600000;class ie extends Error{path;constructor(p){super(`No baseline document at ${p}. Create one with: ostia time --export-json ${p} <command...>`);this.path=p}}class re extends Error{path;missing;total;constructor(p,l,k){super(`${l} of ${k} configured workload(s) have no matching row in baseline ${p} (by workload id). Re-seed with: ostia baseline save`);this.path=p;this.missing=l;this.total=k}}function De(p,l,k){if(p)return p;return l===k?"fail":"warn"}function Ie(p,l=[]){let k=new Set(l),y=p.filter((v)=>!v.timedOut&&!v.timeSourceNoMatch).map((v)=>v.exitCode).filter((v)=>v!==void 0);return y.length>0&&y.every((v)=>v!==0&&!k.has(v))}async function me(p,l){let k=p.noiseCheck===!1?void 0:g(),y=k?h(k):void 0,v=[];for(let M of p.workloads){if(M.suites){let D=await H(M.suites,process.cwd()),ee=await b({suites:D,outDir:p.outDir,noiseCheck:!1,budgetMs:p.bench?.budgetMs,samples:p.bench?.samples,minSamples:p.bench?.minSamples,gc:p.bench?.gc,cpu:p.bench?.cpu,alloc:p.bench?.alloc,filter:p.bench?.filter,isolate:p.bench?.isolate,preload:p.bench?.preload,jobs:typeof p.bench?.jobs==="number"?p.bench.jobs:void 0,timeoutMs:p.bench?.timeoutMs??ve});for(let Y of ee.workloads){let X=ee.measurements.find((N)=>N.workloadId===Y.id&&N.phase==="timing");if(!X)continue;if(y)X.warnings.push(y);v.push({workload:Y,status:"executed",run:X,harnessFailed:!1})}continue}let R=P(M.command,M.label,{prepare:M.prepare,timeSource:M.timeSource}),A=await ge(M.inputs??[]),T=o({runs:p.runs,warmup:p.warmup}),K=typeof M.prepare!=="function",B=he({workloadId:R.id,phase:"timing",configFingerprint:T,bunVersion:Bun.version,toolVersion:x,instrumented:!1,inputsDigest:A}),U=l||!K?void 0:await we(p.outDir,B),G,O;if(U)G=U,O="cached";else{let D=await z({argv:M.command,samples:p.runs??void 0,warmup:p.warmup,prepare:M.prepare,timeSource:M.timeSource,timeoutMs:M.timeoutMs??ve,ignoreExitCodes:M.ignoreExitCodes,failOnNonzero:M.failOnNonzero});if(G=d({workload:R,configFingerprint:T,trials:D.trials,timing:D.timing,warnings:y?[...D.warnings,y]:D.warnings}),K)await ke(p.outDir,B,G);O="executed"}v.push({workload:R,status:O,run:G,harnessFailed:Ie(G.trials,M.ignoreExitCodes)})}return{results:v,environment:k}}async function ye(p){let{config:l}=p,k=s(l,p.baselineName);if(!await Bun.file(k).exists())throw new ie(k);let v=await r(k),{results:M,environment:R}=await me(l,p.full),A=M.map((N)=>({...N})),T=A.filter((N)=>N.status==="executed").length,K=A.length-T,B=A.filter((N)=>N.harnessFailed).length,U=t(A.map((N)=>N.workload),A.map((N)=>N.run),R),G=0,O=0,D=0,ee=W(v,U,l.thresholds);for(let N of A){let de=ee.compare(N.workload.id);if(!de){D++;continue}if(N.comparison=de,de.verdict==="pass")G++;else O++}if(D>0){if(De(l.onMissingBaseline,D,A.length)==="fail")throw new re(k,D,A.length)}let Y=A.map((N)=>N.comparison).filter((N)=>N!==void 0);U.comparisons=Y;let X=ee.unmatched();return U.unmatched={baseOnly:X.baseOnly.map((N)=>N.id),candOnly:X.candOnly.map((N)=>N.id)},U.comparisonSummary=j(Y,ee.effectiveTimingPct),{document:U,summary:{total:A.length,cached:K,executed:T,passed:G,regressed:O,missingBaseline:D,failed:B,results:A,unmatched:X},baseline:v}}function Ce(p){let l=[];if(l.push(`${p.total} workloads`),l.push(`${p.cached} cached`),l.push(`${p.executed} executed`),p.missingBaseline>0)l.push(`${p.missingBaseline} skipped (no matching baseline workload)`);if(p.failed>0){let y=p.results.filter((v)=>v.harnessFailed).map((v)=>n(v.workload));l.push(`${p.failed} failed (harness error, every trial exited non-zero: ${y.join(", ")})`)}let k=p.results.filter((y)=>y.comparison?.verdict==="fail").map((y)=>{let v=y.comparison.timing,M=n(y.workload);return v?`${v.medianDeltaPct>0?"+":""}${v.medianDeltaPct.toFixed(1)}% median on ${M}`:M});return l.push(`${p.passed} passed ${p.regressed} regressed${k.length>0?` (${k.join(", ")})`:""}`),l.push(""),l.push(`Profile CI: ${p.regressed>0||p.failed>0?"\u2717":"\u2713"}`),`${l.join(`
|
|
5
5
|
`)}
|
|
6
|
-
`}async function
|
|
7
|
-
`)
|
|
8
|
-
|
|
9
|
-
`)
|
|
10
|
-
`)
|
|
11
|
-
|
|
12
|
-
${
|
|
13
|
-
`)}
|
|
6
|
+
`}async function xe(p,l){let{results:k,environment:y}=await me(p,!1),v=t(k.map((R)=>R.workload),k.map((R)=>R.run),y),M=s(p,l);return await a(v,M),M}async function Pe(p){let l=[];try{let y=new Bun.Glob("*.json");for await(let v of y.scan({cwd:p.baselineDir,absolute:!1}))l.push(v.replace(/\.json$/,""))}catch{return[]}return l.sort(),(await Promise.all(l.map(async(y)=>{let v=s(p,y);try{let M=await r(v);return{name:y,path:v,createdAt:M.createdAt,toolVersion:M.toolVersion,bunVersion:M.bunVersion,workloads:M.workloads.length,...M.git!==void 0&&{git:M.git}}}catch{return}}))).filter((y)=>y!==void 0)}function te(p){return p instanceof Error?p.message:String(p)}var q=(p)=>Bun.write(Bun.stdout,p),$e=(p)=>Bun.write(Bun.stderr,p);class Q extends Error{}async function F(p,l,k){await $e(l.endsWith(`
|
|
7
|
+
`)?l:`${l}
|
|
8
|
+
`),await $e(`${JSON.stringify({event:"error",protocolVersion:u,code:p,message:l.split(`
|
|
9
|
+
`)[0],...k&&{data:k}})}
|
|
10
|
+
`)}async function Z(p,l){return await q(p),l?0:2}async function Fe(p,l){if(!(p instanceof Q))throw p;return await F("invalid-flag",`${p.message}
|
|
11
|
+
Run 'ostia ${l} --help'.`),2}function Be(p,l,k={}){if(k.allowAuto&&l==="auto")return _();let y=k.min??1,v=Number(l);if(!Number.isInteger(v)||v<y)throw new Q(`Invalid ${p} "${l}": expected an integer \u2265 ${y}${k.allowAuto?' (or "auto")':""}`);return v}function Le(p,l,k={}){let y=k.min??0,v=Number(l);if(!Number.isFinite(v)||v<y)throw new Q(`Invalid ${p} "${l}": expected a number \u2265 ${y}`);return v}var se=["table","json","jsonl","markdown","minimal"],pe=["collapsed","mermaid","speedscope","cpuprofile"],Ue=[...se,...pe];function oe(p,l){if(l.includes(p))return;throw new Q(`Unknown --format "${p}". Expected one of: ${l.join(", ")}`)}var ue=`No CPU evidence in this document; rerun with --cpu (ostia time) or --cpu (ostia bench)
|
|
12
|
+
`;function Ee(p){return p.measurements.some((l)=>l.phase==="cpu")}async function fe(p,l,k={}){if(l.format==="json"&&l.exportJson){let y=f(p);if(await E(y,l.exportJson),!l.quiet)await q(y);return 0}if(l.exportJson)await a(p,l.exportJson);if(l.quiet)return 0;if(pe.includes(l.format)&&!Ee(p))return await F("no-cpu-evidence",ue),2;return await ne(await i[l.format].render(p,k)),0}async function le(p){let l=await S();if(!l){await F("config-missing",p?`No ostia.config.json found. "${p}" needs configured workloads.`:"No ostia.config.json found.");return}if(p&&l.workloads.length===0){let k=await L()??"ostia.config.json";await F("config-missing",`${k} has no "workloads" configured.`);return}return l}async function ne(p,l){if(p.text)await q(p.text);if(!p.files||p.files.length===0)return;if(l)for(let k of p.files){let y=k.path?`${l}/${k.path}`:l;await Bun.write(y,k.content),await q(`wrote ${y}
|
|
13
|
+
`)}else if(p.files.length===1)await q(p.files[0].content);else for(let k of p.files)await q(`--- ${k.path??"(unnamed)"} ---
|
|
14
|
+
${k.content}
|
|
15
|
+
`)}var _e=`ostia time [flags] <command...>
|
|
16
|
+
ostia time [flags] -- <argv...>
|
|
14
17
|
|
|
15
|
-
Time one or more commands N times with warmup and report timing statistics.
|
|
18
|
+
Time one or more commands N times with warmup and report timing statistics. Each
|
|
19
|
+
<command> is a string, whitespace-split into argv exactly like hyperfine -N (no shell,
|
|
20
|
+
so no quoting/globbing/pipes/redirection) - it can't express an argument containing a
|
|
21
|
+
space. \`-- <argv...>\` is the escape hatch: everything after -- is one command's argv
|
|
22
|
+
verbatim, space-preserving, not further flag-parsed. It's one more command alongside any
|
|
23
|
+
given as regular arguments, not a replacement for them.
|
|
16
24
|
|
|
17
25
|
Flags:
|
|
18
|
-
--samples N exact number of timed trials
|
|
26
|
+
--samples N exact number of timed trials per command (each command gets its
|
|
27
|
+
own N trials, not a total split across them)
|
|
19
28
|
--budget MS wall-clock time budget for the sampling loop (default: a
|
|
20
29
|
hyperfine-style ~3s min-total-time loop when neither
|
|
21
30
|
--samples nor --budget is given)
|
|
@@ -30,18 +39,36 @@ Flags:
|
|
|
30
39
|
command. Interleaved measurements carry Measurement.interleaved: true.
|
|
31
40
|
--prepare CMD run CMD before every trial (warmup and --cpu/--heap trials
|
|
32
41
|
included), unmeasured, in the same cwd; it must exit 0. Whitespace-
|
|
33
|
-
split like the commands themselves (no shell)
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
split like the commands themselves (no shell) - there's no --
|
|
43
|
+
equivalent for --prepare, so a hook needing an argument with a
|
|
44
|
+
space needs ostia.config.ts's array form (prepare: ["a", "b c"])
|
|
45
|
+
instead. Given once it applies to every command; given once per
|
|
46
|
+
command it pairs up in order, so the same command can be timed
|
|
47
|
+
warm and cold side by side. Its stderr is captured (bounded to
|
|
48
|
+
1 MiB) rather than streamed live, and folded into the error on a
|
|
49
|
+
trial where it times out or exits non-zero.
|
|
36
50
|
--time-source REGEX take each trial's time from the first REGEX match in the command's
|
|
37
51
|
own stdout (then stderr), capture group 1, instead of its wall clock -
|
|
38
52
|
e.g. --time-source "built in (\\d+)ms" for a build tool whose own
|
|
39
|
-
summary excludes runtime startup.
|
|
40
|
-
|
|
53
|
+
summary excludes runtime startup. A trial whose output doesn't match
|
|
54
|
+
contributes no sample (a time-source-no-match warning records it); if
|
|
55
|
+
every trial misses, that command has no timing stats. Trials keep
|
|
56
|
+
wallNs alongside the reported value.
|
|
41
57
|
--time-unit UNIT unit of the --time-source number: ns | us | ms | s (default: ms)
|
|
42
58
|
--cpu capture one instrumented CPU-profile trial (subprocess --cpu-prof)
|
|
43
59
|
--heap capture one instrumented heap-snapshot trial (subprocess --heap-prof)
|
|
44
60
|
--cpu-interval USEC CPU sampling interval in microseconds (default: 1000)
|
|
61
|
+
--timeout MS kill a trial (or --prepare hook) with SIGKILL if it hasn't finished
|
|
62
|
+
after this many ms. No default: unset never times out. A timed-out
|
|
63
|
+
trial contributes no sample; if every trial of a command times out,
|
|
64
|
+
that command has no timing stats.
|
|
65
|
+
--ignore-failure[=CODE,...]
|
|
66
|
+
treat the given exit codes as success (default with no value: every
|
|
67
|
+
code). A matching trial still contributes its sample and gets no
|
|
68
|
+
nonzero-exit warning, as if it had exited 0. Repeatable.
|
|
69
|
+
--fail-on-nonzero stop a command's trial loop after its first non-zero, non-ignored
|
|
70
|
+
exit (that trial's sample is still recorded) instead of always
|
|
71
|
+
running its full sample count.
|
|
45
72
|
--out-dir PATH directory for captured artifacts (default: node_modules/.cache/ostia)
|
|
46
73
|
--no-noise-check skip the ~200ms machine noise floor reference measurement
|
|
47
74
|
--export-json PATH write the full ProfileDocument to PATH
|
|
@@ -52,6 +79,11 @@ Flags:
|
|
|
52
79
|
Instrumented runs (--cpu, --heap) are labeled separately from clean timing and never
|
|
53
80
|
mixed into the timing statistics.
|
|
54
81
|
|
|
82
|
+
Exit codes: 0 pass, 2 harness error (a command had a non-zero, non-ignored exit; a
|
|
83
|
+
timed-out or --time-source-mismatched command had no timing stats at all; or a bad flag).
|
|
84
|
+
130 if cancelled with Ctrl-C. 1 is never returned by "time" - it's reserved for
|
|
85
|
+
"compare"/"ci" regressions.
|
|
86
|
+
|
|
55
87
|
Examples:
|
|
56
88
|
ostia time "bun ./fixtures/work.ts"
|
|
57
89
|
ostia time --samples 25 --warmup 3 "bun a.ts" "bun b.ts"
|
|
@@ -60,7 +92,10 @@ Examples:
|
|
|
60
92
|
ostia time --time-source "built in (\\d+)ms" "bun build.ts"
|
|
61
93
|
ostia time --cpu --heap "bun src/server.ts"
|
|
62
94
|
ostia time --format json "bun a.ts"
|
|
63
|
-
|
|
95
|
+
ostia time --ignore-failure=3 "bun flaky.ts"
|
|
96
|
+
ostia time --fail-on-nonzero "bun might-hang-if-broken.ts"
|
|
97
|
+
ostia time -- bun -e "console.log('a b')" # argument with a space, unsplit
|
|
98
|
+
`,We=Array.from({length:255},(p,l)=>l+1),je=`ostia bench [flags] <suite.ts...>
|
|
64
99
|
|
|
65
100
|
Run in-process benchmark suites (registered via group()/task()). Each suite file runs
|
|
66
101
|
in its own spawned child process (isolated from CLI startup state).
|
|
@@ -81,25 +116,30 @@ Flags:
|
|
|
81
116
|
Concurrent CPU-bound processes contend for cores, caches and turbo
|
|
82
117
|
headroom, so numbers taken at --jobs > 1 are noisier and not
|
|
83
118
|
like-for-like with a baseline measured at 1. "auto" = CPU count.
|
|
84
|
-
--gc
|
|
85
|
-
Per-task { gc } / per-group { gc } override this default
|
|
86
|
-
|
|
119
|
+
--gc / --no-gc Bun.gc(true) between trials (default: off - hides allocation cost).
|
|
120
|
+
Per-task { gc } / per-group { gc } override this default; --no-gc /
|
|
121
|
+
--gc on the CLI overrides those and ostia.config.json individually,
|
|
122
|
+
so a config-wide default can be turned off for one invocation.
|
|
123
|
+
--cpu / --no-cpu capture an extra phase: "cpu" measurement per task (200ms of the
|
|
87
124
|
task looped under the JSC sampling profiler, JIT tiers included) on
|
|
88
125
|
top of its timing numbers. Per-task { cpu } / per-group { cpu }
|
|
89
126
|
override this default. Once captured, "ostia compare" reports
|
|
90
127
|
per-frame CPU deltas the same way it already does for "ostia time --cpu".
|
|
91
|
-
--alloc
|
|
128
|
+
--alloc / --no-alloc capture an extra phase: "memstats" measurement per task: bytes
|
|
92
129
|
allocated per call, from a Bun.gc(true)-bracketed batch of 100 calls.
|
|
93
130
|
Per-task { alloc } / per-group { alloc } override this default.
|
|
94
131
|
--filter REGEX only run tasks whose "group/name" id matches this regex (substring,
|
|
95
132
|
case-sensitive; unmatched tasks are skipped, not timed)
|
|
96
|
-
--isolate
|
|
97
|
-
file's, isolating JIT tier state and heap shape between tasks
|
|
98
|
-
way suite files are already isolated from each other. Per-task
|
|
133
|
+
--isolate / --no-isolate give every task its own subprocess instead of sharing its
|
|
134
|
+
suite file's, isolating JIT tier state and heap shape between tasks
|
|
135
|
+
the way suite files are already isolated from each other. Per-task
|
|
99
136
|
{ isolate } / per-group { isolate } override this default.
|
|
100
137
|
--jobs then pools across those per-task processes, so pair a
|
|
101
138
|
higher --jobs with --isolate deliberately: overhead now scales
|
|
102
139
|
with task count, not file count.
|
|
140
|
+
--timeout MS kill a suite file's subprocess (or, under --isolate, one task's
|
|
141
|
+
dedicated subprocess) with SIGKILL if it hasn't finished after this
|
|
142
|
+
many ms. No default: unset never times out.
|
|
103
143
|
--preload PATH script imported before each suite file loads, in the same
|
|
104
144
|
subprocess (repeatable; runs in the order given). Use it to
|
|
105
145
|
install globals (jsdom's document/window) or register a
|
|
@@ -113,9 +153,11 @@ Flags:
|
|
|
113
153
|
--no-noise-check skip the ~200ms machine noise floor reference measurement
|
|
114
154
|
--export-json PATH write the full ProfileDocument to PATH
|
|
115
155
|
--format FORMAT table | json | jsonl | markdown | minimal (default: table)
|
|
116
|
-
"minimal" is
|
|
117
|
-
|
|
118
|
-
|
|
156
|
+
"minimal" is protocol v1 (see README's "Using ostia from an AI
|
|
157
|
+
agent"): one JSON "run" event per task, {event, protocolVersion,
|
|
158
|
+
schemaVersion, workloadId, task, group, description, params,
|
|
159
|
+
samples, batch, mean, median, stddevPct, relative,
|
|
160
|
+
warnings[{code,data}]} in ns, no raw sample array - built to pipe
|
|
119
161
|
into an LLM agent's context.
|
|
120
162
|
--quiet suppress the rendered report (still writes --export-json)
|
|
121
163
|
--help show this message
|
|
@@ -169,7 +211,7 @@ Examples:
|
|
|
169
211
|
ostia bench --preload ./bench/jsdom-setup.ts benches/*.dom.bench.ts
|
|
170
212
|
ostia bench --bun-flags="--conditions=browser" bench/*.dom.bench.ts
|
|
171
213
|
ostia bench # picks up suites/preload/jobs from ostia.config.json
|
|
172
|
-
`,
|
|
214
|
+
`,Se=`ostia compare <base.json> <candidate.json>
|
|
173
215
|
ostia compare <candidate.json> --baseline <path.json>
|
|
174
216
|
|
|
175
217
|
Compare two ProfileDocuments (matched by workload id) and rank timing/frame/heap deltas.
|
|
@@ -177,14 +219,27 @@ Compare two ProfileDocuments (matched by workload id) and rank timing/frame/heap
|
|
|
177
219
|
Flags:
|
|
178
220
|
--export-json PATH write the resulting document (with comparisons) to PATH
|
|
179
221
|
--format FORMAT table | json | jsonl | markdown | minimal (default: table)
|
|
180
|
-
"minimal"
|
|
222
|
+
"minimal" is protocol v1 (see README's "Using ostia from an AI
|
|
223
|
+
agent"): a "run" event per task with delta: {medianPct, meanPct,
|
|
224
|
+
verdict, pass, ci95?, pValue?, effectiveTimingPct, matched}, an
|
|
225
|
+
"unmatched" event per workload absent from one side, and a
|
|
226
|
+
trailing "summary" event with the overall verdict and exitCode.
|
|
227
|
+
--timing-pct N override thresholds.timingPct (percent)
|
|
228
|
+
--alpha N override thresholds.alpha (Mann-Whitney significance level)
|
|
229
|
+
--no-config ignore ostia.config.ts/.json; use DEFAULT_THRESHOLDS
|
|
181
230
|
--quiet suppress the rendered report (still writes --export-json)
|
|
182
231
|
--help show this message
|
|
183
232
|
|
|
233
|
+
Reads ostia.config.ts/.json's "thresholds" when present (same discovery as "ostia ci"),
|
|
234
|
+
else DEFAULT_THRESHOLDS; --timing-pct/--alpha override individual fields on top.
|
|
235
|
+
|
|
236
|
+
Exit codes: 0 pass, 1 at least one workload regressed, 2 nothing was compared (zero
|
|
237
|
+
matched workloads) or a harness error (documents failed to load, or a bad flag).
|
|
238
|
+
|
|
184
239
|
Examples:
|
|
185
240
|
ostia compare before.json after.json
|
|
186
241
|
ostia compare after.json --baseline .ostia/baselines/main.json
|
|
187
|
-
`,
|
|
242
|
+
`,qe=`ostia report <document.json> [flags]
|
|
188
243
|
|
|
189
244
|
Render a saved ProfileDocument. Files, not a GUI for the visualization formats -
|
|
190
245
|
hand the output to speedscope.app, flamegraph.pl, or a Mermaid renderer.
|
|
@@ -212,23 +267,31 @@ Examples:
|
|
|
212
267
|
ostia report doc.json --format markdown
|
|
213
268
|
ostia report doc.json --format speedscope --out-dir node_modules/.cache/ostia/viz
|
|
214
269
|
ostia report doc.json --format collapsed | flamegraph.pl > flame.svg
|
|
215
|
-
`,
|
|
270
|
+
`,He=`ostia ci [--full] [--baseline NAME] [--save-baseline]
|
|
216
271
|
|
|
217
272
|
Load ostia.config.json, run configured workloads (reusing cached results when their
|
|
218
273
|
fingerprint is unchanged), compare against the named baseline, and gate on regressions.
|
|
219
274
|
|
|
220
275
|
Flags:
|
|
221
|
-
--full
|
|
222
|
-
--baseline NAME
|
|
223
|
-
--save-baseline
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
--
|
|
228
|
-
--
|
|
276
|
+
--full ignore the cache; rerun every configured workload
|
|
277
|
+
--baseline NAME baseline name (default: config's "baseline" field, or "main")
|
|
278
|
+
--save-baseline after a pass (no regressions, no harness failures), write the
|
|
279
|
+
just-measured document as the new baseline at the same path
|
|
280
|
+
just compared against - promotes today's numbers to
|
|
281
|
+
tomorrow's floor in one step.
|
|
282
|
+
--export-json PATH write the resulting document (with comparisons) to PATH
|
|
283
|
+
--format FORMAT table | json | jsonl | markdown | minimal (default: table)
|
|
284
|
+
--on-missing-baseline POLICY "warn" or "fail" when a configured workload has no matching
|
|
285
|
+
row in the baseline (default: "fail" when every configured
|
|
286
|
+
workload is missing, "warn" otherwise)
|
|
287
|
+
--no-noise-check skip the ~200ms noise-floor reference measurement (default:
|
|
288
|
+
on; same as ostia.config's noiseCheck: false)
|
|
289
|
+
--quiet suppress the rendered report entirely (still writes --export-json)
|
|
290
|
+
--help show this message
|
|
229
291
|
|
|
230
|
-
Exit codes: 0 pass, 1 regression, 2 harness error (missing config/baseline,
|
|
231
|
-
|
|
292
|
+
Exit codes: 0 pass, 1 regression, 2 harness error (missing config/baseline, every trial of
|
|
293
|
+
a workload exited non-zero, an "onMissingBaseline: fail" mismatch, or a spawn failure).
|
|
294
|
+
`,ce=`ostia baseline <save|list|show> [args]
|
|
232
295
|
|
|
233
296
|
Manage the baseline ProfileDocuments "ostia ci" gates against and "ostia compare --baseline"
|
|
234
297
|
reads.
|
|
@@ -247,24 +310,24 @@ Examples:
|
|
|
247
310
|
ostia baseline list
|
|
248
311
|
ostia baseline show main
|
|
249
312
|
ostia baseline show main --format markdown
|
|
250
|
-
`;function
|
|
251
|
-
`),
|
|
252
|
-
`)
|
|
253
|
-
`)
|
|
254
|
-
`)
|
|
255
|
-
`
|
|
256
|
-
`)
|
|
257
|
-
`),
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
`),
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
`),0}async function
|
|
265
|
-
`),0;for(let
|
|
266
|
-
`)}return 0}async function
|
|
267
|
-
|
|
313
|
+
`;function ae(p,l,k,y,v,M){let R=y;for(let A=0;A<p.length;A++){let T=p[A],K=M?.(T,A,y);if(K!==void 0){A=K;continue}let B=k[T];if(!B){if(T.startsWith("-"))throw new Q(`Unknown flag "${T}" for "ostia ${l}".`);v(T,y);continue}switch(B.spec.kind){case"string":R[B.dest]=p[++A];break;case"int":R[B.dest]=Be(T,p[++A],B.spec);break;case"float":R[B.dest]=Le(T,p[++A],B.spec);break;case"bool":R[B.dest]=B.spec.value;break;case"list":R[B.dest].push(p[++A]??"");break;case"enum":{let U=p[++A];if(!B.spec.values.includes(U))throw new Q(`Invalid ${T} "${U}": expected one of: ${B.spec.values.join(", ")}`);R[B.dest]=U;break}}}return y}var Je={"--samples":{dest:"samples",spec:{kind:"int",min:1}},"--budget":{dest:"budgetMs",spec:{kind:"int",min:1}},"--min-samples":{dest:"minSamples",spec:{kind:"int",min:1}},"--warmup":{dest:"warmup",spec:{kind:"int",min:0}},"--no-interleave":{dest:"interleave",spec:{kind:"bool",value:!1}},"--prepare":{dest:"prepare",spec:{kind:"list"}},"--time-source":{dest:"timeSource",spec:{kind:"string"}},"--time-unit":{dest:"timeUnit",spec:{kind:"string"}},"--cpu":{dest:"cpu",spec:{kind:"bool",value:!0}},"--heap":{dest:"heap",spec:{kind:"bool",value:!0}},"--cpu-interval":{dest:"cpuIntervalUs",spec:{kind:"int",min:1}},"--timeout":{dest:"timeoutMs",spec:{kind:"int",min:1}},"--fail-on-nonzero":{dest:"failOnNonzero",spec:{kind:"bool",value:!0}},"--out-dir":{dest:"outDir",spec:{kind:"string"}},"--no-noise-check":{dest:"noiseCheck",spec:{kind:"bool",value:!1}},"--export-json":{dest:"exportJson",spec:{kind:"string"}},"--format":{dest:"format",spec:{kind:"string"}},"--quiet":{dest:"quiet",spec:{kind:"bool",value:!0}},"--help":{dest:"help",spec:{kind:"bool",value:!0}},"-h":{dest:"help",spec:{kind:"bool",value:!0}}};function ze(p){return ae(p,"time",Je,{commands:[],prepare:[],interleave:!0,cpu:!1,heap:!1,ignoreExitCodes:[],failOnNonzero:!1,noiseCheck:!0,format:"table",quiet:!1,help:!1},(k,y)=>y.commands.push(k),(k,y,v)=>{if(k==="--")return v.argvCommand=p.slice(y+1),p.length;if(k==="--ignore-failure"||k.startsWith("--ignore-failure=")){let M=k.startsWith("--ignore-failure=")?k.slice(17):void 0;return v.ignoreExitCodes.push(...M===void 0?We:M.split(",").map(Number)),y}return})}async function Te(p){let l=new AbortController,k=()=>l.abort();process.on("SIGINT",k);try{return{result:await p(l.signal),aborted:l.signal.aborted}}finally{process.off("SIGINT",k)}}var Me=["ns","us","ms","s"];async function Ge(p){let l=ze(p),k=(l.argvCommand?.length??0)>0;if(l.help||l.commands.length===0&&!k)return Z(_e,l.help);oe(l.format,se);let y=l.commands.length+(k?1:0);if(l.prepare.length>1&&l.prepare.length!==y)return await F("invalid-flag",`--prepare given ${l.prepare.length} times for ${y} command(s): give it once (applies to all) or once per command.`),2;if(l.timeUnit!==void 0&&!Me.includes(l.timeUnit))return await F("invalid-flag",`Unknown --time-unit "${l.timeUnit}". Expected one of: ${Me.join(", ")}`),2;if(l.timeSource!==void 0)try{new RegExp(l.timeSource)}catch(O){return await F("invalid-flag",`Invalid --time-source regex: ${te(O)}`),2}let v=l.timeSource!==void 0?{pattern:l.timeSource,unit:l.timeUnit}:void 0,M=(O)=>l.prepare.length===1?l.prepare[0]:l.prepare[O],R=l.commands.map((O,D)=>({command:O,prepare:M(D)}));if(k)R.push({command:l.argvCommand,prepare:M(l.commands.length)});let A,T;try{({result:A,aborted:T}=await Te((O)=>V({commands:R,timeSource:v,samples:l.samples,budgetMs:l.budgetMs,minSamples:l.minSamples,warmup:l.warmup,interleave:l.interleave,cpu:l.cpu,heap:l.heap,cpuIntervalUs:l.cpuIntervalUs,timeoutMs:l.timeoutMs,ignoreExitCodes:l.ignoreExitCodes,failOnNonzero:l.failOnNonzero,outDir:l.outDir,noiseCheck:l.noiseCheck,signal:O})))}catch(O){return await F("spawn-failed",`Run failed: ${te(O)}`),2}let K=await fe(A,l);if(K!==0)return K;if(T)return 130;let B=new Set(l.ignoreExitCodes),U=A.workloads.some((O)=>!A.measurements.some((D)=>D.workloadId===O.id&&D.timing)),G=A.measurements.some((O)=>O.trials.some((D)=>D.exitCode!==void 0&&D.exitCode!==0&&!B.has(D.exitCode)));if(G||U){let O=A.measurements.some((Y)=>Y.warnings.some((X)=>X.code==="timeout")),D=A.measurements.some((Y)=>Y.warnings.some((X)=>X.code==="time-source-no-match"));return await F(G?"command-failed":O?"timeout":D?"time-source-no-match":"command-failed","One or more commands failed to produce a clean measurement; see the report above for details."),2}return 0}var Ve={"--budget":{dest:"budgetMs",spec:{kind:"int",min:1}},"--samples":{dest:"samples",spec:{kind:"int",min:1}},"--min-samples":{dest:"minSamples",spec:{kind:"int",min:1}},"--jobs":{dest:"jobs",spec:{kind:"int",min:1,allowAuto:!0}},"--gc":{dest:"gc",spec:{kind:"bool",value:!0}},"--no-gc":{dest:"gc",spec:{kind:"bool",value:!1}},"--cpu":{dest:"cpu",spec:{kind:"bool",value:!0}},"--no-cpu":{dest:"cpu",spec:{kind:"bool",value:!1}},"--alloc":{dest:"alloc",spec:{kind:"bool",value:!0}},"--no-alloc":{dest:"alloc",spec:{kind:"bool",value:!1}},"--filter":{dest:"filter",spec:{kind:"string"}},"--isolate":{dest:"isolate",spec:{kind:"bool",value:!0}},"--no-isolate":{dest:"isolate",spec:{kind:"bool",value:!1}},"--preload":{dest:"preload",spec:{kind:"list"}},"--timeout":{dest:"timeoutMs",spec:{kind:"int",min:1}},"--out-dir":{dest:"outDir",spec:{kind:"string"}},"--no-noise-check":{dest:"noiseCheck",spec:{kind:"bool",value:!1}},"--export-json":{dest:"exportJson",spec:{kind:"string"}},"--format":{dest:"format",spec:{kind:"string"}},"--quiet":{dest:"quiet",spec:{kind:"bool",value:!0}},"--help":{dest:"help",spec:{kind:"bool",value:!0}},"-h":{dest:"help",spec:{kind:"bool",value:!0}}};function Ke(p){return ae(p,"bench",Ve,{suites:[],preload:[],bunFlags:[],noiseCheck:!0,format:"table",quiet:!1,help:!1},(k,y)=>y.suites.push(k),(k,y,v)=>{if(k==="--bun-flags")return v.bunFlags.push(...m(p[y+1]??"")),y+1;if(k.startsWith("--bun-flags="))return v.bunFlags.push(...m(k.slice(12))),y;return})}async function Xe(p){let l=Ke(p);if(l.help)return Z(je,!0);oe(l.format,se);let k=await S(),y=await J(l,k?.bench);if(y.suites.length===0)return Z(je,!1);if(y.jobs!==void 0&&!(y.jobs>=1))return await F("invalid-flag",'--jobs expects a positive integer or "auto".'),2;let v,M;try{({result:v,aborted:M}=await Te((A)=>b({...y,signal:A})))}catch(A){return await F("spawn-failed",`Bench failed: ${te(A)}`),2}let R=await fe(v,l);if(R!==0)return R;return M?130:0}var Ze={"--baseline":{dest:"baseline",spec:{kind:"string"}},"--export-json":{dest:"exportJson",spec:{kind:"string"}},"--format":{dest:"format",spec:{kind:"string"}},"--timing-pct":{dest:"timingPct",spec:{kind:"float"}},"--alpha":{dest:"alpha",spec:{kind:"float"}},"--no-config":{dest:"noConfig",spec:{kind:"bool",value:!0}},"--quiet":{dest:"quiet",spec:{kind:"bool",value:!0}},"--help":{dest:"help",spec:{kind:"bool",value:!0}},"-h":{dest:"help",spec:{kind:"bool",value:!0}}};function Ye(p){return ae(p,"compare",Ze,{paths:[],format:"table",quiet:!1,help:!1,noConfig:!1},(k,y)=>y.paths.push(k))}async function Qe(p){let l=c,k="defaults";if(!p.noConfig){let y=await S();if(y)l=y.thresholds,k=await L()??"ostia.config.json"}if(p.timingPct!==void 0||p.alpha!==void 0)l={...l,...p.timingPct!==void 0&&{timingPct:p.timingPct},...p.alpha!==void 0&&{alpha:p.alpha}};return{thresholds:l,source:k}}async function et(p){let l=Ye(p);if(l.help)return Z(Se,!0);oe(l.format,se);let k,y;if(l.baseline)k=l.baseline,y=l.paths[0];else k=l.paths[0],y=l.paths[1];if(!k||!y)return Z(Se,!1);let v,M;try{[v,M]=await Promise.all([r(k),r(y)])}catch(O){return await F("document-load-failed",`Failed to load documents: ${te(O)}`),2}let{thresholds:R,source:A}=await Qe(l),T=C(v,M,R),K={...M,comparisons:T.comparisons,comparisonSummary:T.summary,unmatched:{baseOnly:T.unmatched.baseOnly.map((O)=>O.id),candOnly:T.unmatched.candOnly.map((O)=>O.id)}},B=l.format==="table"||l.format==="markdown";if(!l.quiet&&B){if(await q(`thresholds: ${A}
|
|
314
|
+
`),v.git&&M.git)await q(`base ${w(v.git)} \u2192 cand ${w(M.git)}
|
|
315
|
+
`);if(l.format==="table"&&T.summary.effectiveTimingPct>R.timingPct)await q(`threshold ${R.timingPct}% (widened to ${T.summary.effectiveTimingPct.toFixed(1)}% by noise floor)
|
|
316
|
+
`)}let U=T.summary.matched===0?2:T.summary.verdict==="fail"?1:0,G=await fe(K,l,{protocol:{command:"compare",exitCode:U,unmatched:T.unmatched,baseGit:v.git,candGit:M.git,...l.exportJson&&{exportedTo:l.exportJson}}});if(G!==0)return G;if(!l.quiet&&(l.format==="table"||l.format==="markdown")&&(T.unmatched.baseOnly.length>0||T.unmatched.candOnly.length>0))await q(tt(T.unmatched,l.format));if(T.summary.matched===0)await F("no-matches","No workload matched between base and candidate; nothing was compared.");return U}function tt(p,l){let k=(v)=>v.map((M)=>n(M)).join(", ");if(l==="markdown"){let v=["### Unmatched",""];if(p.baseOnly.length>0)v.push(`- baseline only: ${k(p.baseOnly)}`);if(p.candOnly.length>0)v.push(`- candidate only: ${k(p.candOnly)}`);return v.push(""),`${v.join(`
|
|
317
|
+
`)}
|
|
318
|
+
`}let y=["","Unmatched:"];if(p.baseOnly.length>0)y.push(` baseline only: ${k(p.baseOnly)}`);if(p.candOnly.length>0)y.push(` candidate only: ${k(p.candOnly)}`);return`${y.join(`
|
|
319
|
+
`)}
|
|
320
|
+
`}var nt={"--format":{dest:"format",spec:{kind:"string"}},"--measurement":{dest:"measurementId",spec:{kind:"string"}},"--out-dir":{dest:"outDir",spec:{kind:"string"}},"--help":{dest:"help",spec:{kind:"bool",value:!0}},"-h":{dest:"help",spec:{kind:"bool",value:!0}}};function st(p){return ae(p,"report",nt,{format:"table",help:!1},(k,y)=>{if(y.path!==void 0)throw new Q(`"ostia report" takes exactly one document path, got "${y.path}" and "${k}".`);y.path=k})}async function Re(p){let l=st(p);if(l.help||!l.path)return Z(qe,l.help);oe(l.format,Ue);let k;try{k=await r(l.path)}catch(M){return await F("document-load-failed",`Failed to load ${l.path}: ${te(M)}`),2}if(pe.includes(l.format)&&!l.measurementId&&!Ee(k))return await F("no-cpu-evidence",ue),2;let v=await i[l.format].render(k,{measurementId:l.measurementId});if(!v.text&&(!v.files||v.files.length===0))return await F("no-cpu-evidence",l.measurementId?`No CPU evidence found for measurement "${l.measurementId}".`:ue),2;return await ne(v,l.outDir),0}var ot={"--full":{dest:"full",spec:{kind:"bool",value:!0}},"--baseline":{dest:"baseline",spec:{kind:"string"}},"--save-baseline":{dest:"saveBaseline",spec:{kind:"bool",value:!0}},"--export-json":{dest:"exportJson",spec:{kind:"string"}},"--format":{dest:"format",spec:{kind:"string"}},"--on-missing-baseline":{dest:"onMissingBaseline",spec:{kind:"enum",values:["warn","fail"]}},"--no-noise-check":{dest:"noNoiseCheck",spec:{kind:"bool",value:!0}},"--quiet":{dest:"quiet",spec:{kind:"bool",value:!0}},"--help":{dest:"help",spec:{kind:"bool",value:!0}},"-h":{dest:"help",spec:{kind:"bool",value:!0}}};function at(p){return ae(p,"ci",ot,{full:!1,saveBaseline:!1,format:"table",quiet:!1,help:!1,noNoiseCheck:!1},(k)=>{throw new Q(`Unknown flag "${k}" for "ostia ci".`)})}async function it(p){let l=at(p);if(l.help)return Z(He,!0);oe(l.format,se);let k=await le("ostia ci");if(!k)return 2;let y={...k,...l.onMissingBaseline!==void 0&&{onMissingBaseline:l.onMissingBaseline},...l.noNoiseCheck&&{noiseCheck:!1}},v;try{v=await ye({config:y,full:l.full,baselineName:l.baseline})}catch(A){if(A instanceof ie||A instanceof re)return await F("baseline-missing",A.message),2;return await F("spawn-failed",`CI run failed: ${te(A)}`),2}let M=l.format==="json"&&!l.quiet?f(v.document):void 0;if(l.exportJson)if(M)await E(M,l.exportJson);else await a(v.document,l.exportJson);if(l.saveBaseline&&v.summary.regressed===0&&v.summary.failed===0)await a(v.document,s(y,l.baseline));let R=v.summary.failed>0?2:v.summary.regressed>0?1:0;if(v.summary.failed>0){let A=v.summary.results.filter((T)=>T.harnessFailed).map((T)=>n(T.workload));await F("command-failed",`${v.summary.failed} workload(s) failed (harness error, every trial exited non-zero): ${A.join(", ")}`)}if(!l.quiet){let A=l.baseline??y.baseline;if(l.format==="table"){if(await q(Ce(v.summary)),v.document.comparisons&&v.document.comparisons.length>0)await ne(await i.table.render(v.document,{}))}else if(M!==void 0)await q(M);else if(l.format==="markdown")await q(`## ostia ci
|
|
321
|
+
|
|
322
|
+
Baseline: \`${A}\` (\`${s(y,l.baseline)}\`) \xB7 ${v.summary.cached} cached, ${v.summary.executed} executed
|
|
323
|
+
|
|
324
|
+
`),await ne(await i.markdown.render(v.document,{}));else await ne(await i[l.format].render(v.document,{protocol:{command:"ci",exitCode:R,unmatched:v.summary.unmatched,baseGit:v.baseline.git,candGit:v.document.git,baseline:{name:A,path:s(y,l.baseline)},cached:v.summary.cached,executed:v.summary.executed,failed:v.summary.failed,missingBaseline:v.summary.missingBaseline,...l.exportJson&&{exportedTo:l.exportJson}}}))}return R}var Ae=/^[A-Za-z0-9._-]+$/;function Oe(p){if(p.startsWith("-"))return`Invalid baseline name "${p}": names can't start with "-".`;if(!Ae.test(p))return`Invalid baseline name "${p}": expected to match ${Ae}.`;return}async function rt(p){if(p.includes("--help")||p.includes("-h"))return Z(ce,!0);if(p.length>1)return await F("invalid-flag",`"ostia baseline save" takes at most one name argument, got ${p.length}.
|
|
325
|
+
Run 'ostia baseline --help'.`),2;let l=p[0];if(l!==void 0){let v=Oe(l);if(v)return await F("invalid-flag",`${v}
|
|
326
|
+
Run 'ostia baseline --help'.`),2}let k=await le("ostia baseline save");if(!k)return 2;let y=await xe(k,l);return await q(`Wrote ${y}
|
|
327
|
+
`),0}async function lt(p){if(p.includes("--help")||p.includes("-h"))return Z(ce,!0);let l=await le();if(!l)return 2;let k=await Pe(l);if(k.length===0)return await q(`No baselines found in ${l.baselineDir}.
|
|
328
|
+
`),0;for(let y of k){let v=y.git?` ${w(y.git)}`:"";await q(`${y.name} ${y.workloads} workloads created ${y.createdAt} toolVersion ${y.toolVersion}${v}
|
|
329
|
+
`)}return 0}async function ct(p){let[l,...k]=p;if(!l||l==="--help"||l==="-h")return Z(ce,!!l);let y=Oe(l);if(y)return await F("invalid-flag",`${y}
|
|
330
|
+
Run 'ostia baseline --help'.`),2;let v=await le();if(!v)return 2;return Re([s(v,l),...k])}async function Ne(p,l,k,y,v,M=""){if(p===void 0||p==="--help"||p==="-h")return Z(y,p!==void 0);let R=k[p];if(!R)return await F("invalid-flag",v(p)),2;try{return await R(l)}catch(A){return Fe(A,`${M}${p}`)}}async function dt(p){let[l,...k]=p;return Ne(l,k,{save:rt,list:lt,show:ct},ce,(y)=>`Unknown "ostia baseline ${y}". Run "ostia baseline --help".`,"baseline ")}var mt=`ostia - Bun-native profile IR engine
|
|
268
331
|
|
|
269
332
|
Commands:
|
|
270
333
|
time Time commands N times and report timing/CPU/heap
|
|
@@ -275,5 +338,4 @@ Commands:
|
|
|
275
338
|
baseline Manage baseline ProfileDocuments (save/list/show)
|
|
276
339
|
|
|
277
340
|
Run "ostia <command> --help" for details.
|
|
278
|
-
|
|
279
|
-
`),2}}if(import.meta.main)ve().then((l)=>process.exit(l));
|
|
341
|
+
`;async function ut(){let[p,...l]=process.argv.slice(2);return Ne(p,l,{time:Ge,bench:Xe,compare:et,report:Re,ci:it,baseline:dt},mt,(k)=>`Unknown subcommand "${k}". Run "ostia --help".`)}if(import.meta.main)ut().then((p)=>process.exit(p));export{Q as CliUsageError,Be as parseIntFlag};
|