grid: re-interning the pen on every SGR costs 21% of the parse thread under DOOM-fire #416

Closed
opened 2026-09-25 05:31:27 +09:00 by natsukium · 0 comments
Owner

Split from #399.

Under DOOM-fire the parse thread spends about a fifth of its time re-interning the pen. Linux profile of the daemon (i5-12400F, felis main ef96bb46, release with line tables, perf record -e cycles:u --call-graph lbr, 15 s of DOOM-fire at 188x93, load 5.2), share of felis-pty-parser samples:

frame self inclusive
Grid::resync_pen_style (crates/felis-grid/src/lib.rs) 21%
StyleTable::intern (crates/felis-grid/src/style_table.rs) 8.2%
hash_one<Attributes> 4.0%
Attributes::equivalent 3.7%
Attributes::apply_sgr 4.2%

Every SGR ends in resync_pen_style, which looks the whole Attributes up in the dedup map (hash plus equality) even when the pen matches the previous one. DOOM-fire sends a 38;5 / 48;5 pair per cell.

Candidate levers, neither measured yet:

  1. Skip the lookup when the SGR left the pen unchanged (compare against the pen before apply_sgr).
  2. A small direct-mapped cache of recent (Attributes, StyleId) pairs in front of the dedup map, the lever .agents/skills/perf-trace/references/cost-maps.md "ascii cell-write path" already names for truecolor floods. A single last-hit entry does not help there: consecutive truecolor pens differ.

Either one has to stay correct across StyleTable::compact, which renumbers ids: a cached id from before a compaction points at the wrong pen afterwards.

Done when the parse thread's share in resync_pen_style under DOOM-fire drops by a measured amount, with the doom and truecolor floor benches (measure_parse_into_grid_floor) not slower, or the profile shows the lookup cannot get cheaper and the reason is recorded.

Split from #399. Under DOOM-fire the parse thread spends about a fifth of its time re-interning the pen. Linux profile of the daemon (i5-12400F, felis `main` ef96bb46, release with line tables, `perf record -e cycles:u --call-graph lbr`, 15 s of DOOM-fire at 188x93, load 5.2), share of `felis-pty-parser` samples: | frame | self | inclusive | |---|---|---| | `Grid::resync_pen_style` (`crates/felis-grid/src/lib.rs`) | | **21%** | | `StyleTable::intern` (`crates/felis-grid/src/style_table.rs`) | 8.2% | | | `hash_one<Attributes>` | 4.0% | | | `Attributes::equivalent` | 3.7% | | | `Attributes::apply_sgr` | 4.2% | | Every SGR ends in `resync_pen_style`, which looks the whole `Attributes` up in the dedup map (hash plus equality) even when the pen matches the previous one. DOOM-fire sends a `38;5` / `48;5` pair per cell. Candidate levers, neither measured yet: 1. Skip the lookup when the SGR left the pen unchanged (compare against the pen before `apply_sgr`). 2. A small direct-mapped cache of recent `(Attributes, StyleId)` pairs in front of the dedup map, the lever `.agents/skills/perf-trace/references/cost-maps.md` "ascii cell-write path" already names for truecolor floods. A single last-hit entry does not help there: consecutive truecolor pens differ. Either one has to stay correct across `StyleTable::compact`, which renumbers ids: a cached id from before a compaction points at the wrong pen afterwards. Done when the parse thread's share in `resync_pen_style` under DOOM-fire drops by a measured amount, with the doom and truecolor floor benches (`measure_parse_into_grid_floor`) not slower, or the profile shows the lookup cannot get cheaper and the reason is recorded.
Commenting is not possible because the repository is archived.
No description provided.