Cache immutable command bridge metadata

This commit is contained in:
2026-10-09 01:34:24 +00:00
parent 5816dd3eb9
commit 3ad355927c
5 changed files with 125 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
# Performance implementation plan
Status: implementation in progress; Stages 1–6 are complete, Stages 7–11 have not started.
Status: implementation in progress; Stages 1–7 are complete, Stages 8–11 have not started.
Date: 2026-10-09.
@@ -549,7 +549,7 @@ issues remain open.
## Stage 7: cache immutable bridge metadata per app
**Status:** not started. **Prerequisite:** Stage 6.
**Status:** complete. **Prerequisite:** Stage 6.
**Files:** [app.go](../../app.go), [parser.go](../../parser.go), registry invalidation,
root parser/registry tests, dispatch benchmarks, and evidence.
@@ -581,7 +581,37 @@ invocation still creates fresh backend values at this stage. Use
**Completion:** unchanged registrations reuse translated metadata; successful
registration is visible to later parsing and help.
**Evidence:** pending.
**Evidence:** `GOWORK=off GOTOOLCHAIN=local GOPROXY=off GONOPROXY=none
GOSUMDB=off go test -mod=readonly -count=1 .` passed. The new behavioral test
builds help metadata, registers a command and both standard command families,
then confirms later help and parsing see them without invoking provider
callbacks. It also checks visibility after failed and empty registration.
Source review confirms the tree is built lazily, contains only neutral
declarations/flag/operand metadata, and is cleared only after successful
nonempty registration. Root and child ordering is performed by the uncached
builder once per metadata generation.
Measurements used Go 1.26.8, linux/amd64, Linux 6.17.0-41-generic, Intel Core
i5-7260U CPU @ 2.20 GHz, based on source revision `5816dd3` with this stage's
changes in the working tree. The five-sample command passed:
`GOWORK=off GOTOOLCHAIN=local GOPROXY=off GONOPROXY=none GOSUMDB=off go test -mod=readonly -run '^$' -bench '^BenchmarkPerformanceDispatch$' -benchmem -benchtime=200ms -count=5 .`.
Raw output is in `/tmp/commandkit-performance-dispatch-after-stage7.txt`.
Repeated small success changed from 31,066–41,041 ns/op, 33,209–33,210 B/op,
and 287 allocations to 26,008–31,223 ns/op, 29,408–29,409 B/op, and 267
allocations. Wide success changed from 218,073–253,010 ns/op, 269,063–269,070
B/op, and 1,898 allocations to 182,431–194,243 ns/op, 247,626–247,635 B/op,
and 1,756 allocations. Deep success changed from 119,958–139,625 ns/op,
139,787–139,791 B/op, and 1,074 allocations to 103,208–124,879 ns/op,
124,240–124,242 B/op, and 879 allocations. Help and usage paths also reduced
allocations and bytes. Cold construction plus first execution remained similar
for the small app (38,152–50,235 ns/op, 38,275–38,276 B/op, 339 allocations
baseline; 39,158–47,365 ns/op, 38,243 B/op, 338 allocations now). The wide
cold case changed from 251,945–315,276 ns/op, 291,822–291,827 B/op, and 2,184
allocations to 271,403–321,746 ns/op, 305,046–305,051 B/op, and 2,194
allocations. Its timing range overlaps baseline; the extra cold storage is the
retained neutral tree. The measured tradeoff is lower repeated-execution cost
with one tree allocation retained per app metadata generation.
## Stage 8: introduce an invocation-owned adapter session