delta: dumpVtRow allocates and frees per row, 50x per pty read
open by a73x
`DeltaTracker.update` allocates and frees one buffer per row per pty read — 50 alloc/free pairs per read at 50 rows, through Zig's GPA (`heap.debug_allocator.DebugAllocator`), which showed up at ~5% of daemon cycles in the 2026-08-21 profile plus an unmeasured share of `memset`. `dumpVtRow` returns an owned slice by contract, which is what forces the churn. Formatting into a caller-provided writer (one buffer reused across all rows, cleared per row) removes it. Unlike the detached-session fix, this one helps the attached case too, since the loop runs either way.
Comments
a73x
Re-ranked upward: this is the biggest of the three, not the cheap
cleanup the ~5% in the opening note suggested. That figure came from a
user-space perf profile, which structurally cannot see where the cost
actually lands.
Measured 2026-08-21 on 374MB of full-width repaint, 200x50, no client,
ReleaseSafe, while landing the detached-session fix:
utime 24.1s stime 106.5s <- 81% of CPU in the KERNEL
Fifty GPA allocations per pty read churn mmap/munmap and page faults.
In perf those frames come back as unresolved [unknown] addresses (~11%
of samples), so the profile attributed 57% to the formatter and ~5% to
the allocator — the formatter was only the visible half. Removing the
whole loop for detached sessions cut instructions 5.9x but wall time
27x; the missing 4.7x was system time.
The detached fix does nothing for a session with a client attached,
where this loop still runs on every read. This issue is what covers
that case, and it is a smaller change than the cell-hashing one.