From 6612b54e2ae7bb02c38a2124b03afd5e4b71da9e Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Fri, 9 Oct 2026 00:39:07 +0000 Subject: [PATCH] Record selected performance approaches --- docs/roadmap/performance.md | 106 +++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 50 deletions(-) diff --git a/docs/roadmap/performance.md b/docs/roadmap/performance.md index 581dad7..7b72315 100644 --- a/docs/roadmap/performance.md +++ b/docs/roadmap/performance.md @@ -1,6 +1,6 @@ # Computational efficiency roadmap -Status: proposed; implementation has not begun. +Status: proposed improvements; OD-1 and OD-2 resolved; implementation has not begun. Date: 2026-10-09. @@ -31,7 +31,7 @@ or promised speedups. Recheck the affected implementation before starting work. | PF-01 | PromptKit text reports are built even for YAML requests. | Render only the requested format and avoid redundant report buffers. | First pass | | PF-02 | Selected-command lookup scans a map; each ancestor is rediscovered from the root. | Direct declaration lookup and ancestry traversal proportional to path depth. | First pass | | PF-03 | Every invocation translates and sorts metadata; help and usage construct another backend tree. | Reuse immutable metadata and the invocation's prepared tree. | Measure and improve after the first pass | -| PF-04 | Aggregate YAML framing splits every line and copies the complete native document. | Inspect only the opening lines; assess eliminating the complete framed copy. | Prefix scanning in the first pass; copying afterward | +| PF-04 | Aggregate YAML framing splits every line and copies the complete native document. | Inspect only the opening lines and retain a complete framed buffer for delivery. | First pass | | PF-05 | Each registration copies the existing top-level registry. | Prepare new entries separately and install a validated batch atomically. | Lower priority | | PF-06 | Scope ordering, lookup, and selection repeat; selector duplicate checks scan previous entries. | Prepare stable scope metadata once and use direct duplicate checks. | Lower priority | @@ -130,13 +130,14 @@ second backend construction also benefits a single CLI help or usage request. Measure both cases separately, including the cost of app construction and registration for consumers that execute only once. -Reusing mutable backend trees across different invocations is a later option, -conditional on measured benefit and a clear account of state reset and value -ownership. The first target can retain fresh backend parse state for each -invocation. No public freeze step, backend selector, or concurrent-dispatch +Under the selected OD-1 approach, construct fresh mutable backend parse state for +each invocation, reuse that state within the invocation, and cache immutable +metadata between invocations. Reusing mutable backend trees across invocations +is deferred beyond this target. Measurements may motivate reconsidering it in +future work. No public freeze step, backend selector, or concurrent-dispatch guarantee is needed for these improvements. -### PF-04: Reduce aggregate YAML scanning and copying +### PF-04: Reduce aggregate YAML preamble scanning In [configuration display](../../show.go), `hasYAMLDirective` and `frameEffectiveYAML` split the complete document into lines before examining its @@ -149,9 +150,11 @@ decision is complete. Share the resulting framing analysis where useful so directive detection and scope-label placement do not independently scan the same preamble. Avoid a document-wide line index and unnecessary string conversions. -Then evaluate delivering separators, labels, and native byte segments directly, -retaining one native render buffer without a second complete framed copy. Keep -the design simple enough to preserve failure handling for multiple writes. +Under the selected OD-2 approach, retain the native render buffer and assemble a +complete framed buffer for each document before delivery. This keeps delivery +and write-failure handling straightforward. The full document copy remains an +accepted cost of this target; the optimization removes the document-wide line +index and redundant preamble scanning. Preserve native bytes, directive placement, inline document content and block scalars, scope-label escaping, and boundary newlines according to the CLI @@ -207,14 +210,16 @@ preparing this metadata. 1. Establish focused before-change measurements for PF-01, PF-02, and PF-04, then implement conditional formatting, direct command lookup/ancestry, and YAML prefix scanning as independently reviewable changes. -2. Measure complete dispatch paths and implement PF-03's reuse within an - invocation and immutable metadata preparation where the benefit justifies - the coordination and retained memory. -3. Evaluate PF-04's segmented delivery, PF-05, and PF-06 using the first-pass - evidence and expected consumer sizes. Record a deferral if a proposed change - adds complexity without a worthwhile benefit. -4. Consider backend reuse across invocations only if the remaining measured cost - warrants it. +2. Measure complete dispatch paths, then implement PF-03's reuse within an + invocation and immutable metadata caching. Compare the resulting runtime + gains with the coordination cost and retained memory. +3. Evaluate PF-05 and PF-06 using the first-pass evidence and expected consumer + sizes. Record a deferral if a proposed change adds complexity without a + worthwhile benefit. +4. Record remaining costs after the selected improvements. Mutable backend reuse + across invocations and segmented YAML delivery remain future possibilities + beyond this target; any reconsideration should use the measurements and a + deliberate change to the selected approach. Use Go benchmarks with controlled, offline fixtures when implementation work is authorized. Keep external loading and service latency out of isolated CommandKit @@ -264,45 +269,46 @@ ownership, and replacing Cobra are outside this target. They require their own concrete motivation and review rather than following automatically from a performance optimization. -## Open Decisions +## Resolved Decisions -The first-pass formatting, lookup, and prefix-scanning changes have a clear -recommended direction. Two broader implementation choices remain dependent on -performance evidence. Resolve them when preparing the corresponding work; they -do not require a public API change. +The following approaches were selected on 2026-10-09. Both are implementation +choices within the existing public contracts. No significant open decisions +remain for this roadmap's scope. ### OD-1: How far should backend reuse extend? -**Recommendation:** Initially reuse the prepared backend within one invocation -and cache immutable metadata between invocations, while constructing fresh -mutable backend state for each `Execute`. This removes repeated help/usage work -and metadata translation while keeping invocation isolation straightforward. -Measure the remaining backend construction cost before expanding reuse. This is -the recommended PF-03 target, not a permanent restriction on implementation. +**Selected approach:** Adopt the recommended approach: reuse the prepared backend +within one invocation and cache immutable metadata between invocations, while +constructing fresh mutable backend state for each `Execute`. -**Alternative:** Retain a mutable backend tree per `App` and reset it before each -invocation. This can remove more command and flag-set construction work for -consumers that execute repeatedly. It also retains more memory and requires +**Reasoning:** This removes repeated help/usage work and metadata translation +while keeping invocation isolation straightforward. Measure the remaining +backend construction cost to inform future work. The selection defines the +PF-03 target without establishing a permanent architectural restriction. + +**Alternative considered:** Retain a mutable backend tree per `App` and reset it +before each invocation. This can remove more command and flag-set construction +work for consumers that execute repeatedly. It also retains more memory and requires careful reset of parsed values, presence, operands, contexts, streams, and other -backend state, plus refresh after registration. Choose it if measurements show -that the remaining construction cost warrants the added lifecycle complexity -and behavioral evidence establishes independent invocations. A CLI that executes -only once receives little benefit from this additional reuse. +backend state, plus refresh after registration. The added lifecycle complexity +is deferred until measurements justify reconsideration and behavioral evidence +establishes independent invocations. A CLI that executes only once receives +little benefit from this additional reuse. ### OD-2: How much buffering should aggregate YAML retain? -**Recommendation:** After prefix scanning is improved, favor retaining the native -render buffer and delivering framing and native slices as separate segments if -measurements confirm a useful memory reduction. This removes the second complete -document copy while keeping native rendering complete before that document's -delivery begins. The work includes correct accounting for cancellation and -partial output across segment writes, without changing aggregate acquisition -timing. Compare allocation savings with any additional writer-call overhead. +**Selected approach:** Adopt the previously listed alternative: retain the +complete framed buffer after replacing the line splits with prefix scanning. -**Alternative:** Retain a complete framed buffer after replacing the line splits -with prefix scanning. This keeps delivery simple and avoids additional writes -for each document. It still allocates and copies the document a second time, -which matters for large reports. Prefer it if representative documents are small -or segmented delivery provides insufficient benefit to justify its extra error -handling. Either choice can deliver PF-04's initial prefix-scanning improvement; -record the selected buffering approach and its evidence. +**Reasoning:** This keeps delivery simple and avoids additional writes for each +document. It accepts the second document allocation and copy while removing the +line index and unnecessary scanning. Measure the resulting allocation cost, +particularly for large reports, without making segmented delivery part of this +implementation target. + +**Alternative considered:** Retain only the native render buffer and deliver +framing and native slices as separate segments. This can reduce peak allocation +and copying while keeping native rendering complete before delivery. It requires +accounting for cancellation and partial output across segment writes and may +increase writer-call overhead. It remains a viable future optimization if the +selected approach's measured memory cost warrants the additional delivery logic.