Files
l0ng-ai 2e6f9cab4f perf(protocol): put a frame's header and payload on the wire in one write (#713)
`write_frame` sent the length, the kind byte and the payload as three
separate `write_all` calls. The pane socket is a loopback `TcpStream` with
`TCP_NODELAY` set, so each of those was its own segment and its own wakeup
on the far side: the client woke from `read()` about twice per frame just
to reassemble a header it had already been told the shape of. The daemon
frames every ConPTY read, so under output that is tens of thousands of
extra syscalls a second on each end.

Write the 5-byte header and the payload as one `write_vectored` instead.
The bytes on the wire are identical, and a writer with no native vectored
write still terminates on the loop's fallback — it just costs what it
used to.

Measured on a Ryzen 9 9950X (32 threads, integrated Radeon), release
build, one pane in a 2182x1361 window, a generator emitting 20000
80-column lines/s (1.64 MB/s), three 25-second samples each. CPU is % of
one core; "reads/frame" is `TTY7_TRACE`'s client socket reads divided by
its frame count.

| | tty7-app (GUI) | daemon | conpty host | total | reads/frame |
|---|---|---|---|---|---|
| before | 22.0 | 3.8 | 2.3 | 28.1 | 1.90 |
| after | 17.7 | 3.1 | 2.5 | 23.3 | 0.93 |

Socket reads per frame halve, and CPU at a fixed output rate falls 17%.
Under an unbounded flood the pipeline instead gets faster — 35.7 MB/s
before, 47.0 MB/s after — so that case is not rate-matched and is not
claimed as a CPU win.

This does not on its own explain #713: at the rate that issue describes
(a held Return, ~30 lines/s) tty7 costs about 11% of one core here either
way. It is a real cost on the output path regardless.
2026-09-07 19:31:09 +08:00
..