mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-07-31 20:59:02 +00:00
APC payloads such as Kitty graphics images can be megabytes of base64 data, but every byte was dispatched individually: through the VT state machine table, an apc_put action, the stream handler, the APC protocol handler, and finally a per-byte ArrayList append in the Kitty command parser. Five layers of dispatch per byte made large image transfers far slower than they needed to be. Add a bulk fast path alongside the existing CSI fast paths in consumeUntilGround: scan the longest run of apc_put bytes (stopping at any byte the parse table doesn't treat as APC payload: CAN, SUB, ESC, and most C1 bytes exit or abort the string state, and 0xA0-0xFF are ignored by it) and dispatch the run as a single new apc_put_slice action. The APC handler identifies the protocol from the first few bytes as before, then passes the remainder of each slice to the protocol parser in bulk; the Kitty parser appends payload data with a single appendSlice. Ignored/unknown APC sequences now drop each slice in O(1) instead of per-byte dispatch. The fast path is guarded the same way as the CSI fast paths: handlers with a vtRaw hook (the inspector) keep receiving per-byte apc_put actions, and the scalar next() path is unchanged. Also add benchmark support: a `ghostty-gen +kitty` synthetic generator emitting well-formed Kitty graphics transmit commands with 4 KiB random base64 payloads (not valid image data; the corpus exercises the parsing paths, not image decoding), and a `ghostty-bench +apc-parser` benchmark that measures the stream -> APC -> Kitty parse path without image decode/storage. Benchmarks on a 64 MiB corpus (hyperfine, ReleaseFast, x86_64 Linux, baseline is identical source with only the fast path disabled): apc-parser: 1.061 s -> 43 ms (~25x) terminal-stream (kitty): 1.163 s -> 72 ms (~16x) terminal-stream (ascii): no change The ascii case was verified with retired instruction counts (perf stat, pinned to one core) since wall time on the test machine has 4-7 ms of noise: 988,030,458 vs 988,045,833 instructions (+0.0016%), a fixed startup-size delta; the ground-state hot loop never reaches the new branch.