Record selected performance approaches

This commit is contained in:
2026-10-09 00:39:07 +00:00
parent f9b0454f34
commit 6612b54e2a

View File

@@ -1,6 +1,6 @@
# Computational efficiency roadmap # 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. 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-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-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-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-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 | | 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 Measure both cases separately, including the cost of app construction and
registration for consumers that execute only once. registration for consumers that execute only once.
Reusing mutable backend trees across different invocations is a later option, Under the selected OD-1 approach, construct fresh mutable backend parse state for
conditional on measured benefit and a clear account of state reset and value each invocation, reuse that state within the invocation, and cache immutable
ownership. The first target can retain fresh backend parse state for each metadata between invocations. Reusing mutable backend trees across invocations
invocation. No public freeze step, backend selector, or concurrent-dispatch 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. 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 In [configuration display](../../show.go), `hasYAMLDirective` and
`frameEffectiveYAML` split the complete document into lines before examining its `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 directive detection and scope-label placement do not independently scan the same
preamble. Avoid a document-wide line index and unnecessary string conversions. preamble. Avoid a document-wide line index and unnecessary string conversions.
Then evaluate delivering separators, labels, and native byte segments directly, Under the selected OD-2 approach, retain the native render buffer and assemble a
retaining one native render buffer without a second complete framed copy. Keep complete framed buffer for each document before delivery. This keeps delivery
the design simple enough to preserve failure handling for multiple writes. 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 Preserve native bytes, directive placement, inline document content and block
scalars, scope-label escaping, and boundary newlines according to the CLI 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, 1. Establish focused before-change measurements for PF-01, PF-02, and PF-04,
then implement conditional formatting, direct command lookup/ancestry, and then implement conditional formatting, direct command lookup/ancestry, and
YAML prefix scanning as independently reviewable changes. YAML prefix scanning as independently reviewable changes.
2. Measure complete dispatch paths and implement PF-03's reuse within an 2. Measure complete dispatch paths, then implement PF-03's reuse within an
invocation and immutable metadata preparation where the benefit justifies invocation and immutable metadata caching. Compare the resulting runtime
the coordination and retained memory. gains with the coordination cost and retained memory.
3. Evaluate PF-04's segmented delivery, PF-05, and PF-06 using the first-pass 3. Evaluate PF-05 and PF-06 using the first-pass evidence and expected consumer
evidence and expected consumer sizes. Record a deferral if a proposed change sizes. Record a deferral if a proposed change adds complexity without a
adds complexity without a worthwhile benefit. worthwhile benefit.
4. Consider backend reuse across invocations only if the remaining measured cost 4. Record remaining costs after the selected improvements. Mutable backend reuse
warrants it. 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 Use Go benchmarks with controlled, offline fixtures when implementation work is
authorized. Keep external loading and service latency out of isolated CommandKit 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 concrete motivation and review rather than following automatically from a
performance optimization. performance optimization.
## Open Decisions ## Resolved Decisions
The first-pass formatting, lookup, and prefix-scanning changes have a clear The following approaches were selected on 2026-10-09. Both are implementation
recommended direction. Two broader implementation choices remain dependent on choices within the existing public contracts. No significant open decisions
performance evidence. Resolve them when preparing the corresponding work; they remain for this roadmap's scope.
do not require a public API change.
### OD-1: How far should backend reuse extend? ### OD-1: How far should backend reuse extend?
**Recommendation:** Initially reuse the prepared backend within one invocation **Selected approach:** Adopt the recommended approach: reuse the prepared backend
and cache immutable metadata between invocations, while constructing fresh within one invocation and cache immutable metadata between invocations, while
mutable backend state for each `Execute`. This removes repeated help/usage work constructing fresh mutable backend state for each `Execute`.
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.
**Alternative:** Retain a mutable backend tree per `App` and reset it before each **Reasoning:** This removes repeated help/usage work and metadata translation
invocation. This can remove more command and flag-set construction work for while keeping invocation isolation straightforward. Measure the remaining
consumers that execute repeatedly. It also retains more memory and requires 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 careful reset of parsed values, presence, operands, contexts, streams, and other
backend state, plus refresh after registration. Choose it if measurements show backend state, plus refresh after registration. The added lifecycle complexity
that the remaining construction cost warrants the added lifecycle complexity is deferred until measurements justify reconsideration and behavioral evidence
and behavioral evidence establishes independent invocations. A CLI that executes establishes independent invocations. A CLI that executes only once receives
only once receives little benefit from this additional reuse. little benefit from this additional reuse.
### OD-2: How much buffering should aggregate YAML retain? ### OD-2: How much buffering should aggregate YAML retain?
**Recommendation:** After prefix scanning is improved, favor retaining the native **Selected approach:** Adopt the previously listed alternative: retain the
render buffer and delivering framing and native slices as separate segments if complete framed buffer after replacing the line splits with prefix scanning.
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.
**Alternative:** Retain a complete framed buffer after replacing the line splits **Reasoning:** This keeps delivery simple and avoids additional writes for each
with prefix scanning. This keeps delivery simple and avoids additional writes document. It accepts the second document allocation and copy while removing the
for each document. It still allocates and copies the document a second time, line index and unnecessary scanning. Measure the resulting allocation cost,
which matters for large reports. Prefer it if representative documents are small particularly for large reports, without making segmented delivery part of this
or segmented delivery provides insufficient benefit to justify its extra error implementation target.
handling. Either choice can deliver PF-04's initial prefix-scanning improvement;
record the selected buffering approach and its evidence. **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.