terminal: skip style map update when SGR leaves style unchanged

Profiling the csi benchmark showed ~20% of time in the style
ref-counted set (hash, probe, release/use churn) driven by
manualStyleUpdate, which runs after every SGR attribute even when
the attribute didn't actually change the cursor style. Real
programs re-assert the same style constantly (per span, per line,
or on every refresh of a mostly static screen), so a large share of
these updates are no-ops.

Screen.setAttribute already snapshots the old style to restore it
on failure, so this compares the style after applying the attribute
and returns early when it's unchanged: the current style ID is
already correct and no release/lookup/use is needed.

The tradeoff is one extra Style.eql on every style-changing
attribute. Measured with ghostty-bench terminal-stream (full
terminal handler, 100 MB deterministic corpora, 120x80, M4 Max,
ReleaseFast, hyperfine means of 10 runs) across corpora with
different repeated style rates (the csi/sgr corpora draw random
colors from a palette so nearly every SGR changes the style, which
is the worst case for this change; the redraw corpora model TUI
refreshes that re-assert the current style for 70% / 95% of SGRs):

| stream              | before | after  | change |
|---------------------|--------|--------|--------|
| redraw (95% same)   | 277 ms | 260 ms | +7%    |
| redraw (70% same)   | 302 ms | 291 ms | +4%    |
| csi (~0% same)      | 407 ms | 414 ms | -2%    |
| sgr (~0% same)      | 295 ms | 303 ms | -3%    |

Real-world SGR traffic is far closer to the redraw corpora than to
the adversarial random-color ones, so this trades a small worst
case regression for a solid win on the common pattern.
This commit is contained in:
Mitchell Hashimoto
2026-07-06 06:25:23 -07:00
parent 253e4f9c3c
commit cee35cabf6

View File

@@ -1992,6 +1992,12 @@ pub fn setAttribute(
.unknown => return,
}
// If the attribute didn't change our style then we can skip the
// style update entirely: our current style ID is already correct.
// This is a common case in the wild where programs re-assert the
// same style repeatedly (e.g. per span or per line).
if (self.cursor.style.eql(old_style)) return;
try self.manualStyleUpdate();
}