ostia 0.2.7 → 0.2.8
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 +68 -13
- package/chunk-17t12ta6.js +16 -0
- package/chunk-p3342c5c.js +25 -0
- package/cli.js +71 -34
- package/index.d.ts +200 -17
- package/index.js +1 -1
- package/package.json +1 -1
- package/runner.ts +16 -4
- package/chunk-5qtsmr3p.js +0 -21
- package/chunk-n02qf2mf.js +0 -16
package/cli.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import{e,
|
|
4
|
-
`)}var
|
|
3
|
+
import{e,w,t,y,N,r,B,x,i,P,Z,l,M,s,a,c}from"./chunk-17t12ta6.js";import{d,ne,te,L,T,E,u,re,R,j,H,ae,G,se,F,V,S,f,m,oe}from"./chunk-p3342c5c.js";import{resolve as Ue}from"path";function ve(o){return e("cache",o.workloadId,o.phase,o.configFingerprint,o.bunVersion,o.toolVersion,o.instrumented,o.inputsDigest??null)}async function ye(o,n=process.cwd()){if(o.length===0)return;let p=await H(o,n),h=await Promise.all(p.map(async(g)=>{let b=await Bun.file(Ue(n,g)).arrayBuffer();return{path:g,sha256:Bun.CryptoHasher.hash("sha256",b,"hex")}}));return e("inputs",h)}function Ce(o,n){return`${o}/cache/${n}.json`}async function xe(o,n){let p=Bun.file(Ce(o,n));if(!await p.exists())return;return await p.json()}async function Pe(o,n,p){await Bun.write(Ce(o,n),`${JSON.stringify(p,null,2)}
|
|
4
|
+
`)}var $e=600000;class me extends Error{path;constructor(o){super(`No baseline document at ${o}. Create one with: ostia baseline save ${o.split("/").pop().replace(/\.json$/,"")}`);this.path=o}}class de extends Error{path;missing;total;constructor(o,n,p){super(`${n} of ${p} configured workload(s) have no matching row in baseline ${o} (by workload id). Re-seed with: ostia baseline save`);this.path=o;this.missing=n;this.total=p}}function qe(o,n,p){if(o)return o;return n===p?"fail":"warn"}async function ge(o,n){let p=o.noiseCheck===!1?void 0:a(),h=p?c(p):void 0,g=[];for(let b of o.workloads){if(b.suites){let I=await F(b.suites,process.cwd()),K=await V({suites:I,preload:[],bunFlags:[],noiseCheck:!1},o.bench),Q=await S({...K,outDir:K.outDir??o.outDir,timeoutMs:K.timeoutMs??$e});for(let X of Q.workloads){let W=Q.measurements.find((ie)=>ie.workloadId===X.id&&ie.phase==="timing");if(!W)continue;if(h)W.warnings.push(h);g.push({workload:X,status:"executed",run:W,harnessFailed:!1})}continue}let A=B(b.command,b.label,{prepare:b.prepare,timeSource:b.timeSource}),k=await ye(b.inputs??[]),v=i({samples:o.samples??null,budgetMs:o.budgetMs??null,minSamples:o.minSamples??null,warmup:o.warmup}),J=b.inputs!==void 0&&typeof b.prepare!=="function",U=ve({workloadId:A.id,phase:"timing",configFingerprint:v,bunVersion:Bun.version,toolVersion:N,instrumented:!1,inputsDigest:k}),O=n||!J?void 0:await xe(o.outDir,U),D,C;if(O)D=O,C="cached";else{let I=await ae({argv:b.command,samples:o.samples,budgetMs:o.budgetMs,minSamples:o.minSamples,warmup:o.warmup,prepare:b.prepare,timeSource:b.timeSource,timeoutMs:b.timeoutMs??$e,ignoreExitCodes:b.ignoreExitCodes});if(D=x({workload:A,configFingerprint:v,trials:I.trials,timing:I.timing,warnings:h?[...I.warnings,h]:I.warnings}),J)await Pe(o.outDir,U,D);C="executed"}g.push({workload:A,status:C,run:D,harnessFailed:G(D,b.ignoreExitCodes)})}return{results:g,environment:p}}async function Ae(o){let{config:n}=o,p=u(n,o.baselineName);if(!await Bun.file(p).exists())throw new me(p);let g=await s(p),{results:b,environment:A}=await ge(n,o.full),k=b.map((W)=>({...W})),v=k.filter((W)=>W.status==="executed").length,J=k.length-v,U=k.filter((W)=>W.harnessFailed).length,O=r(k.map((W)=>W.workload),k.map((W)=>W.run),A),D=0,C=0,I=0,K=ne(g,O,n.thresholds);for(let W of k){let ie=K.compare(W.workload.id);if(!ie){I++;continue}if(W.comparison=ie,ie.verdict==="pass")D++;else C++}if(I>0){if(qe(n.onMissingBaseline,I,k.length)==="fail")throw new de(p,I,k.length)}let Q=k.map((W)=>W.comparison).filter((W)=>W!==void 0);O.comparisons=Q;let X=K.unmatched();return O.unmatched={baseOnly:X.baseOnly.map((W)=>W.id),candOnly:X.candOnly.map((W)=>W.id)},O.comparisonSummary=te(Q,K.effectiveTimingPct),{document:O,summary:{total:k.length,cached:J,executed:v,passed:D,regressed:C,missingBaseline:I,failed:U,results:k,unmatched:X},baseline:g}}function Me(o){let n=[];if(n.push(`${o.total} workloads`),n.push(`${o.cached} cached`),n.push(`${o.executed} executed`),o.missingBaseline>0)n.push(`${o.missingBaseline} skipped (no matching baseline workload)`);if(o.failed>0){let h=o.results.filter((g)=>g.harnessFailed).map((g)=>t(g.workload));n.push(`${o.failed} failed (harness error, a command exited non-zero or produced no samples: ${h.join(", ")})`)}let p=o.results.filter((h)=>h.comparison?.verdict==="fail").map((h)=>{let g=h.comparison.timing,b=t(h.workload);return g?`${g.medianDeltaPct>0?"+":""}${g.medianDeltaPct.toFixed(1)}% median on ${b}`:b});return n.push(`${o.passed} passed ${o.regressed} regressed${p.length>0?` (${p.join(", ")})`:""}`),n.push(""),n.push(`Profile CI: ${o.regressed>0||o.failed>0?"\u2717":"\u2713"}`),`${n.join(`
|
|
5
5
|
`)}
|
|
6
|
-
`}async function
|
|
6
|
+
`}async function Se(o,n){let{results:p,environment:h}=await ge(o,!1),g=r(p.map((A)=>A.workload),p.map((A)=>A.run),h),b=u(o,n);return await l(g,b),b}async function Fe(o){let n=[];try{let h=new Bun.Glob("*.json");for await(let g of h.scan({cwd:o.baselineDir,absolute:!1}))n.push(g.replace(/\.json$/,""))}catch{return[]}return n.sort(),(await Promise.all(n.map(async(h)=>{let g=u(o,h);try{let b=await s(g);return{name:h,path:g,createdAt:b.createdAt,toolVersion:b.toolVersion,bunVersion:b.bunVersion,workloads:b.workloads.length,...b.git!==void 0&&{git:b.git}}}catch{return}}))).filter((h)=>h!==void 0)}function ee(o){return o instanceof Error?o.message:String(o)}var q=(o)=>Bun.write(Bun.stdout,o),Te=(o)=>Bun.write(Bun.stderr,o);class Y extends Error{}var Ie=[],Ee=new Set(["minimal","json","jsonl"]);async function Le(o){let{isatty:n}=await import("tty");if(!n(2))return!0;return o.some((p,h)=>p==="--format"&&Ee.has(o[h+1]??"")||p.startsWith("--format=")&&Ee.has(p.slice(9)))}async function _(o,n,p){if(await Te(n.endsWith(`
|
|
7
7
|
`)?n:`${n}
|
|
8
|
-
`),!await
|
|
9
|
-
`)[0],...
|
|
10
|
-
`)}async function
|
|
11
|
-
Run 'ostia ${n} --help'.`),2}function
|
|
12
|
-
`;function
|
|
13
|
-
`)}else if(
|
|
14
|
-
${
|
|
15
|
-
`)}var
|
|
8
|
+
`),!await Le(Ie))return;await Te(`${JSON.stringify({event:"error",protocolVersion:f,code:o,message:n.split(`
|
|
9
|
+
`)[0],...p&&{data:p}})}
|
|
10
|
+
`)}async function z(o,n){return await q(o),n?0:2}async function Je(o,n){return await _("invalid-flag",`${o.message}
|
|
11
|
+
Run 'ostia ${n} --help'.`),2}function Ge(o,n,p={}){if(p.allowAuto&&n==="auto")return se();let h=p.min??1,g=Number(n);if(!Number.isInteger(g)||g<h)throw new Y(`Invalid ${o} "${n}": expected an integer \u2265 ${h}${p.allowAuto?' (or "auto")':""}`);return g}var Ve=["ns","us","ms","s"],le=["table","json","jsonl","markdown","minimal"],we=["collapsed","mermaid","speedscope","cpuprofile"],ze=[...le,...we],be=`No CPU evidence in this document; rerun with --cpu (ostia time) or --cpu (ostia bench)
|
|
12
|
+
`;function Ne(o){return o.measurements.some((n)=>n.phase==="cpu")}async function pe(o,n,p={}){if(n.format==="json"&&n.exportJson){let h=P(o);if(await Z(h,n.exportJson),!n.quiet)await q(h);return 0}if(n.exportJson)await l(o,n.exportJson);if(n.quiet)return 0;if(we.includes(n.format)&&!Ne(o))return await _("no-cpu-evidence",be),2;return await ue(await m[n.format].render(o,p)),0}async function fe(o){let n=await E();if(!n){await _("config-missing",o?`No ostia.config.json found. "${o}" needs configured workloads.`:"No ostia.config.json found.");return}if(o&&n.workloads.length===0){let p=await re()??"ostia.config.json";await _("config-missing",`${p} has no "workloads" configured.`);return}return n}async function ue(o,n){if(o.text)await q(o.text);if(!o.files||o.files.length===0)return;if(n)for(let p of o.files){let h=p.path?`${n}/${p.path}`:n;await Bun.write(h,p.content),await q(`wrote ${h}
|
|
13
|
+
`)}else if(o.files.length===1)await q(o.files[0].content);else for(let p of o.files)await q(`--- ${p.path??"(unnamed)"} ---
|
|
14
|
+
${p.content}
|
|
15
|
+
`)}var Ke=`ostia time [flags] <command...>
|
|
16
16
|
ostia time [flags] -- <argv...>
|
|
17
17
|
|
|
18
18
|
Time commands as subprocesses. Each <command> is whitespace-split into argv (no shell);
|
|
@@ -48,7 +48,7 @@ Examples:
|
|
|
48
48
|
ostia time --prepare "rm -rf dist" "bun build.ts"
|
|
49
49
|
ostia time --time-source "built in (\\d+)ms" "bun build.ts"
|
|
50
50
|
ostia time -- bun -e "console.log('a b')"
|
|
51
|
-
`,
|
|
51
|
+
`,Xe=Array.from({length:255},(o,n)=>n+1),De=`ostia bench [flags] <suite.ts...>
|
|
52
52
|
|
|
53
53
|
Run in-process group()/task() suites, each file in its own child process. With no files,
|
|
54
54
|
uses ostia.config's "bench" section; each flag overrides its config field.
|
|
@@ -60,8 +60,12 @@ Flags:
|
|
|
60
60
|
--jobs N|auto suite files at once (default: 1; >1 adds noise)
|
|
61
61
|
--isolate one process per task, not per file (--no-isolate to undo config)
|
|
62
62
|
--gc Bun.gc(true) between trials (--no-gc)
|
|
63
|
-
--cpu extra per-task CPU profile with JIT tiers (--no-cpu)
|
|
64
|
-
--
|
|
63
|
+
--cpu extra per-task CPU profile with JIT tiers, ~2,000 samples (--no-cpu)
|
|
64
|
+
--cpu-interval US CPU sampling interval (default: 100)
|
|
65
|
+
--alloc extra per-task retained-heap-per-call measurement: what calls keep
|
|
66
|
+
alive after a full GC, not what they allocate (--no-alloc)
|
|
67
|
+
--peak-mem extra per-task RSS rise during the task's first call, garbage
|
|
68
|
+
included; median of 3 fresh processes (--no-peak-mem)
|
|
65
69
|
--filter REGEX only tasks whose "group/name" matches
|
|
66
70
|
--preload PATH import before each suite file (repeatable, in order)
|
|
67
71
|
--bun-flags FLAGS extra flags for the bun process running each suite (repeatable)
|
|
@@ -73,14 +77,46 @@ Flags:
|
|
|
73
77
|
--quiet don't print the report
|
|
74
78
|
--help show this message
|
|
75
79
|
|
|
76
|
-
Per-task/per-group options ({ budgetMs, minSamples, gc, isolate, cpu, alloc }) override
|
|
80
|
+
Per-task/per-group options ({ budgetMs, minSamples, gc, isolate, cpu, alloc, peakMem }) override
|
|
77
81
|
the suite-wide defaults. Exit codes: 0 ok, 2 a suite failed (or a bad flag), 130 Ctrl-C.
|
|
78
82
|
|
|
79
83
|
Examples:
|
|
80
84
|
ostia bench bench/*.ts
|
|
81
85
|
ostia bench bench/*.ts --filter parse --cpu --alloc
|
|
82
86
|
ostia bench --preload ./bench/dom-setup.ts --bun-flags="--conditions=browser" bench/*.ts
|
|
83
|
-
`,Re=`ostia
|
|
87
|
+
`,Re=`ostia ab [flags] <suite.ts...>
|
|
88
|
+
|
|
89
|
+
Pair every task on a git ref's committed tree (base) against the working tree (candidate), in
|
|
90
|
+
one process, alternating ~10ms batches, and gate on the per-round time ratio. Drift between
|
|
91
|
+
the two sides cancels within a round. With no files, uses ostia.config's "bench" suites.
|
|
92
|
+
|
|
93
|
+
Flags:
|
|
94
|
+
--base REF git ref for the base side (default: HEAD)
|
|
95
|
+
--rounds N base/candidate rounds per task (default: 15)
|
|
96
|
+
--threshold PCT flag a task whose median ratio moves past PCT (default: 10)
|
|
97
|
+
--geomean-threshold PCT fail when the geometric mean of all ratios is slower than PCT
|
|
98
|
+
(default: 1.5)
|
|
99
|
+
--confirm N re-measure each flagged task in N fresh processes (default: 2; 0 skips)
|
|
100
|
+
--filter REGEX only tasks whose "group/name" matches
|
|
101
|
+
--preload PATH import before each suite file (repeatable, in order)
|
|
102
|
+
--bun-flags FLAGS extra flags for the bun process running each suite (repeatable)
|
|
103
|
+
--timeout MS kill a suite (or repeat) process after MS
|
|
104
|
+
--out-dir PATH scratch directory and base-tree cache (default: node_modules/.cache/ostia)
|
|
105
|
+
--no-noise-check skip the ~200ms noise-floor measurement
|
|
106
|
+
--export-json PATH write the ProfileDocument to PATH
|
|
107
|
+
--format FORMAT table | json | jsonl | markdown | minimal (default: table)
|
|
108
|
+
--quiet don't print the report
|
|
109
|
+
--help show this message
|
|
110
|
+
|
|
111
|
+
A flagged task counts only when every fresh-process repeat flags it the same way. Exit codes:
|
|
112
|
+
0 pass, 1 a confirmed regression or the geomean over its threshold, 2 nothing paired or a
|
|
113
|
+
harness error (not a git repo, unknown ref, a suite failed), 130 Ctrl-C.
|
|
114
|
+
|
|
115
|
+
Examples:
|
|
116
|
+
ostia ab bench/parse.bench.ts
|
|
117
|
+
ostia ab bench/*.ts --base origin/main --rounds 21
|
|
118
|
+
ostia ab bench/*.ts --filter parse --format minimal
|
|
119
|
+
`,Oe=`ostia compare <base.json> <candidate.json>
|
|
84
120
|
ostia compare <candidate.json> --baseline <base.json>
|
|
85
121
|
|
|
86
122
|
Compare two ProfileDocuments by workload id. Gates on ostia.config's "thresholds" when
|
|
@@ -94,7 +130,7 @@ Flags:
|
|
|
94
130
|
--help show this message
|
|
95
131
|
|
|
96
132
|
Exit codes: 0 pass, 1 a workload regressed, 2 nothing matched or a harness error.
|
|
97
|
-
`,
|
|
133
|
+
`,Ze=`ostia report <document.json> [flags]
|
|
98
134
|
|
|
99
135
|
Render a saved ProfileDocument. Files, not a GUI for the visualization formats -
|
|
100
136
|
hand the output to speedscope.app, flamegraph.pl, or a Mermaid renderer.
|
|
@@ -122,7 +158,7 @@ Examples:
|
|
|
122
158
|
ostia report doc.json --format markdown
|
|
123
159
|
ostia report doc.json --format speedscope --out-dir node_modules/.cache/ostia/viz
|
|
124
160
|
ostia report doc.json --format collapsed | flamegraph.pl > flame.svg
|
|
125
|
-
`,
|
|
161
|
+
`,Qe=`ostia ci [flags]
|
|
126
162
|
|
|
127
163
|
Run ostia.config's workloads (reusing cached runs whose declared inputs are unchanged),
|
|
128
164
|
compare against a saved baseline, and gate on regressions.
|
|
@@ -139,7 +175,7 @@ Flags:
|
|
|
139
175
|
|
|
140
176
|
Exit codes: 0 pass, 1 regression, 2 harness error (missing config/baseline, a workload
|
|
141
177
|
failed or produced no samples, or an onMissingBaseline "fail" mismatch).
|
|
142
|
-
`,
|
|
178
|
+
`,he=`ostia baseline <save|list|show> [args]
|
|
143
179
|
|
|
144
180
|
Manage the baseline ProfileDocuments "ostia ci" gates against and "ostia compare --baseline"
|
|
145
181
|
reads.
|
|
@@ -158,32 +194,33 @@ Examples:
|
|
|
158
194
|
ostia baseline list
|
|
159
195
|
ostia baseline show main
|
|
160
196
|
ostia baseline show main --format markdown
|
|
161
|
-
`;function
|
|
162
|
-
`),
|
|
163
|
-
`);if(n.format==="table"&&
|
|
164
|
-
`)}let
|
|
197
|
+
`;function ce(o,n,p,h,g,b){let A=h;for(let k=0;k<o.length;k++){let v=o[k],J=b?.(v,k,h);if(J!==void 0){k=J;continue}let U=v.startsWith("--")?v.indexOf("="):-1,O=U>0?v.slice(0,U):v,D=p[O];if(!D||U>0&&D.spec.kind==="bool"){if(v.startsWith("-"))throw new Y(`Unknown flag "${v}" for "ostia ${n}".`);g(v,h);continue}let C=()=>U>0?v.slice(U+1):o[++k];switch(D.spec.kind){case"string":A[D.dest]=C();break;case"int":A[D.dest]=Ge(O,C(),D.spec);break;case"number":{let I=C(),K=Number(I);if(I===void 0||I===""||!Number.isFinite(K)||K<D.spec.min)throw new Y(`Invalid ${O} "${I}": expected a number \u2265 ${D.spec.min}`);A[D.dest]=K;break}case"bool":A[D.dest]=D.spec.value;break;case"list":A[D.dest].push(C()??"");break;case"enum":{let I=C();if(!D.spec.values.includes(I))throw new Y(`Invalid ${O} "${I}": expected one of: ${D.spec.values.join(", ")}`);A[D.dest]=I;break}}}return h}var Ye={"--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:"enum",values:Ve}},"--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}},"--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:"enum",values:le}},"--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 et(o){return ce(o,"time",Ye,{commands:[],prepare:[],interleave:!0,cpu:!1,heap:!1,ignoreExitCodes:[],noiseCheck:!0,format:"table",quiet:!1,help:!1},(p,h)=>h.commands.push(p),(p,h,g)=>{if(p==="--")return g.argvCommand=o.slice(h+1),o.length;if(p==="--ignore-failure"||p.startsWith("--ignore-failure=")){let b=p.startsWith("--ignore-failure=")?p.slice(17):void 0;return g.ignoreExitCodes.push(...b===void 0?Xe:b.split(",").map(Number)),h}return})}async function ke(o){let n=new AbortController,p=()=>n.abort();process.on("SIGINT",p);try{return{result:await o(n.signal),aborted:n.signal.aborted}}finally{process.off("SIGINT",p)}}async function tt(o){let n=et(o),p=(n.argvCommand?.length??0)>0;if(n.help||n.commands.length===0&&!p)return z(Ke,n.help);let h=n.commands.length+(p?1:0);if(n.prepare.length>1&&n.prepare.length!==h)return await _("invalid-flag",`--prepare given ${n.prepare.length} times for ${h} command(s): give it once (applies to all) or once per command.`),2;if(n.timeSource!==void 0)try{new RegExp(n.timeSource)}catch(C){return await _("invalid-flag",`Invalid --time-source regex: ${ee(C)}`),2}let g=n.timeSource!==void 0?{pattern:n.timeSource,unit:n.timeUnit}:void 0,b=(C)=>n.prepare.length===1?n.prepare[0]:n.prepare[C],A=n.commands.map((C,I)=>({command:C,prepare:b(I)}));if(p)A.push({command:n.argvCommand,prepare:b(n.commands.length)});let k,v;try{({result:k,aborted:v}=await ke((C)=>oe({commands:A,timeSource:g,samples:n.samples,budgetMs:n.budgetMs,minSamples:n.minSamples,warmup:n.warmup,interleave:n.interleave,cpu:n.cpu,heap:n.heap,cpuIntervalUs:n.cpuIntervalUs,timeoutMs:n.timeoutMs,ignoreExitCodes:n.ignoreExitCodes,outDir:n.outDir,noiseCheck:n.noiseCheck,signal:C})))}catch(C){return await _("spawn-failed",`Run failed: ${ee(C)}`),2}let J=await pe(k,n);if(J!==0)return J;if(v)return 130;let U=k.workloads.map((C)=>k.measurements.find((I)=>I.workloadId===C.id&&I.phase==="timing")??{trials:[],timing:void 0}),O=U.some((C)=>!C.timing),D=U.some((C)=>C.timing&&G(C,n.ignoreExitCodes));if(D||O){let C=k.measurements.some((Q)=>Q.warnings.some((X)=>X.code==="timeout")),I=k.measurements.some((Q)=>Q.warnings.some((X)=>X.code==="time-source-no-match"));return await _(D?"command-failed":C?"timeout":I?"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 nt={"--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}},"--cpu-interval":{dest:"cpuIntervalUs",spec:{kind:"int",min:1}},"--alloc":{dest:"alloc",spec:{kind:"bool",value:!0}},"--no-alloc":{dest:"alloc",spec:{kind:"bool",value:!1}},"--peak-mem":{dest:"peakMem",spec:{kind:"bool",value:!0}},"--no-peak-mem":{dest:"peakMem",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:"enum",values:le}},"--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 st(o){return ce(o,"bench",nt,{suites:[],preload:[],bunFlags:[],noiseCheck:!0,format:"table",quiet:!1,help:!1},(p,h)=>h.suites.push(p),Be(o))}function Be(o){return(n,p,h)=>{if(n==="--bun-flags")return h.bunFlags.push(...y(o[p+1]??"")),p+1;if(n.startsWith("--bun-flags="))return h.bunFlags.push(...y(n.slice(12))),p;return}}async function ot(o){let n=st(o);if(n.help)return z(De,!0);let p=await E(),h=await V(n,p?.bench);if(h.suites.length===0)return z(De,!1);if(h.jobs!==void 0&&!(h.jobs>=1))return await _("invalid-flag",'--jobs expects a positive integer or "auto".'),2;let g,b;try{({result:g,aborted:b}=await ke((k)=>S({...h,signal:k})))}catch(k){return await _("spawn-failed",`Bench failed: ${ee(k)}`),2}let A=await pe(g,n);if(A!==0)return A;return b?130:0}var at={"--base":{dest:"base",spec:{kind:"string"}},"--rounds":{dest:"rounds",spec:{kind:"int",min:3}},"--threshold":{dest:"thresholdPct",spec:{kind:"number",min:0}},"--geomean-threshold":{dest:"geomeanThresholdPct",spec:{kind:"number",min:0}},"--confirm":{dest:"confirm",spec:{kind:"int",min:0}},"--filter":{dest:"filter",spec:{kind:"string"}},"--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:"enum",values:le}},"--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 it(o){return ce(o,"ab",at,{suites:[],preload:[],bunFlags:[],noiseCheck:!0,format:"table",quiet:!1,help:!1},(p,h)=>h.suites.push(p),Be(o))}async function rt(o){let n=it(o);if(n.help)return z(Re,!0);let p=(await E())?.bench,h=n.suites.length>0?n.suites:p?.suites?await F(p.suites,process.cwd()):[];if(h.length===0)return z(Re,!1);let g,b;try{({result:g,aborted:b}=await ke((O)=>j({suites:h,base:n.base,rounds:n.rounds,thresholdPct:n.thresholdPct,geomeanThresholdPct:n.geomeanThresholdPct,confirm:n.confirm,filter:n.filter??p?.filter,preload:n.preload.length>0?n.preload:p?.preload??[],bunFlags:n.bunFlags.length>0?n.bunFlags:p?.bunFlags??[],timeoutMs:n.timeoutMs??p?.timeoutMs,outDir:n.outDir??p?.outDir,noiseCheck:n.noiseCheck,signal:O})))}catch(O){if(O instanceof R)return await _("invalid-flag",`--base: ${O.message}`),2;return await _("spawn-failed",`A/B run failed: ${ee(O)}`),2}let A=g.ab,k=b?130:A.matched===0?2:A.verdict==="fail"?1:0,v=new Map(g.workloads.map((O)=>[O.id,O])),J=(O=[])=>O.flatMap((D)=>v.get(D)??[]),U=await pe(g,n,{protocol:{command:"ab",exitCode:k,unmatched:{baseOnly:J(g.unmatched?.baseOnly),candOnly:J(g.unmatched?.candOnly)},...n.exportJson&&{exportedTo:n.exportJson}}});if(U!==0)return U;if(k===2)await _("no-matches",`No task exists both at ${A.base.ref} and in the working tree; nothing was paired.`);return k}var lt={"--baseline":{dest:"baseline",spec:{kind:"string"}},"--export-json":{dest:"exportJson",spec:{kind:"string"}},"--format":{dest:"format",spec:{kind:"enum",values:le}},"--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 ct(o){return ce(o,"compare",lt,{paths:[],format:"table",quiet:!1,help:!1},(p,h)=>h.paths.push(p))}async function ut(){let o=await E();if(!o)return{thresholds:d,source:"defaults"};return{thresholds:o.thresholds,source:await re()??"ostia.config.json"}}async function mt(o){let n=ct(o);if(n.help)return z(Oe,!0);let p,h;if(n.baseline)p=n.baseline,h=n.paths[0];else p=n.paths[0],h=n.paths[1];if(!p||!h)return z(Oe,!1);let g,b;try{[g,b]=await Promise.all([s(p),s(h)])}catch(C){return await _("document-load-failed",`Failed to load documents: ${ee(C)}`),2}let{thresholds:A,source:k}=await ut(),v=L(g,b,A),J={...b,comparisons:v.comparisons,comparisonSummary:v.summary,unmatched:{baseOnly:v.unmatched.baseOnly.map((C)=>C.id),candOnly:v.unmatched.candOnly.map((C)=>C.id)}},U=n.format==="table"||n.format==="markdown";if(!n.quiet&&U){if(await q(`thresholds: ${k}
|
|
198
|
+
`),g.git&&b.git)await q(`base ${w(g.git)} \u2192 cand ${w(b.git)}
|
|
199
|
+
`);if(n.format==="table"&&v.summary.effectiveTimingPct>A.timingPct)await q(`threshold ${A.timingPct}% (widened to ${v.summary.effectiveTimingPct.toFixed(1)}% by noise floor)
|
|
200
|
+
`)}let O=v.summary.matched===0?2:v.summary.verdict==="fail"?1:0,D=await pe(J,n,{protocol:{command:"compare",exitCode:O,unmatched:v.unmatched,baseGit:g.git,candGit:b.git,...n.exportJson&&{exportedTo:n.exportJson}}});if(D!==0)return D;if(!n.quiet&&(n.format==="table"||n.format==="markdown")&&(v.unmatched.baseOnly.length>0||v.unmatched.candOnly.length>0))await q(dt(v.unmatched,n.format));if(v.summary.matched===0)await _("no-matches","No workload matched between base and candidate; nothing was compared.");return O}function dt(o,n){let p=(g)=>g.map((b)=>t(b)).join(", ");if(n==="markdown"){let g=["### Unmatched",""];if(o.baseOnly.length>0)g.push(`- baseline only: ${p(o.baseOnly)}`);if(o.candOnly.length>0)g.push(`- candidate only: ${p(o.candOnly)}`);return g.push(""),`${g.join(`
|
|
165
201
|
`)}
|
|
166
|
-
`}let h=["","Unmatched:"];if(
|
|
202
|
+
`}let h=["","Unmatched:"];if(o.baseOnly.length>0)h.push(` baseline only: ${p(o.baseOnly)}`);if(o.candOnly.length>0)h.push(` candidate only: ${p(o.candOnly)}`);return`${h.join(`
|
|
167
203
|
`)}
|
|
168
|
-
`}var
|
|
204
|
+
`}var pt={"--format":{dest:"format",spec:{kind:"enum",values:ze}},"--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 ft(o){return ce(o,"report",pt,{format:"table",help:!1},(p,h)=>{if(h.path!==void 0)throw new Y(`"ostia report" takes exactly one document path, got "${h.path}" and "${p}".`);h.path=p})}async function _e(o){let n=ft(o);if(n.help||!n.path)return z(Ze,n.help);let p;try{p=await s(n.path)}catch(b){return await _("document-load-failed",`Failed to load ${n.path}: ${ee(b)}`),2}if(we.includes(n.format)&&!n.measurementId&&!Ne(p))return await _("no-cpu-evidence",be),2;let g=await m[n.format].render(p,{measurementId:n.measurementId});if(!g.text&&(!g.files||g.files.length===0))return await _("no-cpu-evidence",n.measurementId?`No CPU evidence found for measurement "${n.measurementId}".`:be),2;return await ue(g,n.outDir),0}var ht={"--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:"enum",values:le}},"--no-noise-check":{dest:"noiseCheck",spec:{kind:"bool",value:!1}},"--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 gt(o){return ce(o,"ci",ht,{full:!1,saveBaseline:!1,format:"table",quiet:!1,help:!1,noiseCheck:!0},(p)=>{throw new Y(`Unknown flag "${p}" for "ostia ci".`)})}async function bt(o){let n=gt(o);if(n.help)return z(Qe,!0);let p=await fe("ostia ci");if(!p)return 2;let h={...p,...!n.noiseCheck&&{noiseCheck:!1}},g;try{g=await Ae({config:h,full:n.full,baselineName:n.baseline})}catch(k){if(k instanceof me||k instanceof de)return await _("baseline-missing",k.message),2;if(k instanceof M)return await _("document-load-failed",k.message),2;return await _("spawn-failed",`CI run failed: ${ee(k)}`),2}let b=n.format==="json"&&!n.quiet?P(g.document):void 0;if(n.exportJson)if(b)await Z(b,n.exportJson);else await l(g.document,n.exportJson);if(n.saveBaseline&&g.summary.regressed===0&&g.summary.failed===0)await l(g.document,u(h,n.baseline));let A=g.summary.failed>0?2:g.summary.regressed>0?1:0;if(g.summary.failed>0){let k=g.summary.results.filter((v)=>v.harnessFailed).map((v)=>t(v.workload));await _("command-failed",`${g.summary.failed} workload(s) failed (harness error, a command exited non-zero or produced no samples): ${k.join(", ")}`)}if(!n.quiet){let k=n.baseline??h.baseline;if(n.format==="table"){if(await q(Me(g.summary)),g.document.comparisons&&g.document.comparisons.length>0)await ue(await m.table.render(g.document,{}))}else if(b!==void 0)await q(b);else if(n.format==="markdown")await q(`## ostia ci
|
|
169
205
|
|
|
170
|
-
Baseline: \`${
|
|
206
|
+
Baseline: \`${k}\` (\`${u(h,n.baseline)}\`) \xB7 ${g.summary.cached} cached, ${g.summary.executed} executed
|
|
171
207
|
|
|
172
|
-
`),await
|
|
173
|
-
Run 'ostia baseline --help'.`),2;let n=
|
|
174
|
-
Run 'ostia baseline --help'.`),2}let
|
|
175
|
-
`),0}async function
|
|
176
|
-
`),0;for(let h of
|
|
177
|
-
`)}return 0}async function
|
|
178
|
-
Run 'ostia baseline --help'.`),2;let
|
|
208
|
+
`),await ue(await m.markdown.render(g.document,{}));else await ue(await m[n.format].render(g.document,{protocol:{command:"ci",exitCode:A,unmatched:g.summary.unmatched,baseGit:g.baseline.git,candGit:g.document.git,baseline:{name:k,path:u(h,n.baseline)},cached:g.summary.cached,executed:g.summary.executed,failed:g.summary.failed,missingBaseline:g.summary.missingBaseline,...n.exportJson&&{exportedTo:n.exportJson}}}))}return A}var je=/^[A-Za-z0-9._-]+$/;function He(o){if(o.startsWith("-"))return`Invalid baseline name "${o}": names can't start with "-".`;if(!je.test(o))return`Invalid baseline name "${o}": expected to match ${je}.`;return}async function wt(o){if(o.includes("--help")||o.includes("-h"))return z(he,!0);if(o.length>1)return await _("invalid-flag",`"ostia baseline save" takes at most one name argument, got ${o.length}.
|
|
209
|
+
Run 'ostia baseline --help'.`),2;let n=o[0];if(n!==void 0){let g=He(n);if(g)return await _("invalid-flag",`${g}
|
|
210
|
+
Run 'ostia baseline --help'.`),2}let p=await fe("ostia baseline save");if(!p)return 2;let h=await Se(p,n);return await q(`Wrote ${h}
|
|
211
|
+
`),0}async function kt(o){if(o.includes("--help")||o.includes("-h"))return z(he,!0);let n=await fe();if(!n)return 2;let p=await Fe(n);if(p.length===0)return await q(`No baselines found in ${n.baselineDir}.
|
|
212
|
+
`),0;for(let h of p){let g=h.git?` ${w(h.git)}`:"";await q(`${h.name} ${h.workloads} workloads created ${h.createdAt} toolVersion ${h.toolVersion}${g}
|
|
213
|
+
`)}return 0}async function vt(o){let[n,...p]=o;if(!n||n==="--help"||n==="-h")return z(he,!!n);let h=He(n);if(h)return await _("invalid-flag",`${h}
|
|
214
|
+
Run 'ostia baseline --help'.`),2;let g=await fe();if(!g)return 2;return _e([u(g,n),...p])}async function We(o,n,p,h,g,b=""){if(o===void 0||o==="--help"||o==="-h")return z(h,o!==void 0);let A=p[o];if(!A)return await _("invalid-flag",g(o)),2;try{return await A(n)}catch(k){if(k instanceof T)return await _("config-invalid",k.message),2;if(k instanceof Y)return Je(k,`${b}${o}`);return await _("internal",`Internal error: ${k instanceof Error?k.stack??k.message:String(k)}`),2}}async function yt(o){let[n,...p]=o;return We(n,p,{save:wt,list:kt,show:vt},he,(h)=>`Unknown "ostia baseline ${h}". Run "ostia baseline --help".`,"baseline ")}var Ct=`ostia - profiling and benchmarking for Bun
|
|
179
215
|
|
|
180
216
|
Commands:
|
|
181
217
|
time Time commands N times and report timing/CPU/heap
|
|
182
218
|
bench Run in-process benchmark suites (group()/task())
|
|
219
|
+
ab Pair suites against a git ref in one process, gate on regressions
|
|
183
220
|
compare Compare two ProfileDocuments
|
|
184
221
|
report Render a saved ProfileDocument (table/json/markdown/collapsed/mermaid/speedscope/...)
|
|
185
222
|
ci Run configured workloads against a baseline, gate on regressions
|
|
186
223
|
baseline Manage baseline ProfileDocuments (save/list/show)
|
|
187
224
|
|
|
188
225
|
Run "ostia <command> --help" for details.
|
|
189
|
-
`;async function
|
|
226
|
+
`;async function xt(){let[o,...n]=process.argv.slice(2);return Ie=n,We(o,n,{time:tt,bench:ot,ab:rt,compare:mt,report:_e,ci:bt,baseline:yt},Ct,(p)=>`Unknown subcommand "${p}". Run "ostia --help".`)}if(import.meta.main)xt().then((o)=>process.exit(o));export{Y as CliUsageError,Ge as parseIntFlag};
|