Skip to content

terminal: speed up formatting anywhere from ~1.5x to ~8x - #13587

Merged
mitchellh merged 6 commits into
mainfrom
push-ptyutxlmqymp
Aug 4, 2026
Merged

mitchellh merged 6 commits into
mainfrom
push-ptyutxlmqymp

Conversation

@mitchellh

Copy link
Copy Markdown
Contributor

This PR speeds up our formatting (plain text, html, and VT) by anywhere from ~1.5x to ~8x.

The formatter is the hot path behind multiple features in Ghostty GUI: clipboard copy (plain/VT/HTML), write_screen_file, selectionString, and terminal search sliding window. It's also the hot path for libghostty users, namely people like zmx which utilize the VT formatter to restore a terminal.

This PR also adds the benchmarking infrastructure for the formatter.

How

  • Fast cell-run optimization. For simple cells (single codepoint, no style/hyperlink) we encode them as a single run rather than one at a time.
  • Make some arguments comptime. Generates more code but benchmarks show it improves things, specifically for per-format switches that we do a LOT.
  • Interned style id fast path. Styles are interned per page, so id equality implies style equality. We track the id of the active style and skip the per-cell Style copy + eql when it matches.
  • Fast printing. Avoid std.fmt where possible and assemble integers, RGB colors, codepoints in fixed-width buffers with a single memcpy. This was extracted partially to fastprint.zig so we can reuse it.
  • Avoid double-formatting for tracked pins. Previously we formatted twice (once through a Discarding writer to count bytes) for pin maps. Now I'm smarter about it and do a single pass.

Performance

All on my machine, 80x24 terminal, 10K lines of scrollback.

workload main this PR speedup throughput
plain / plain 5.74 ms 1.67 ms 3.4x 364 MB/s
plain / vt 6.46 ms 1.04 ms 6.2x 596 MB/s
plain / html 7.39 ms 2.32 ms 3.2x 308 MB/s
unicode / plain 9.74 ms 5.42 ms 1.8x 276 MB/s
unicode / vt 10.42 ms 5.53 ms 1.9x 275 MB/s
unicode / html 12.53 ms 7.35 ms 1.7x 509 MB/s
styled / plain 5.65 ms 1.69 ms 3.4x 360 MB/s
styled / vt 9.07 ms 4.20 ms 2.2x 409 MB/s
styled / html 10.78 ms 6.64 ms 1.6x 740 MB/s
mixed / plain 8.59 ms 4.81 ms 1.8x 226 MB/s
mixed / vt 11.25 ms 6.65 ms 1.7x 250 MB/s
mixed / html 14.47 ms 10.52 ms 1.4x 414 MB/s
wrapped / plain 7.30 ms 1.11 ms 6.6x 733 MB/s
wrapped / vt 8.14 ms 1.04 ms 7.8x 789 MB/s
wrapped / html 9.00 ms 2.12 ms 4.2x 465 MB/s
pin-map / plain 12.51 ms 3.80 ms 3.3x
pin-map / vt 13.12 ms 2.99 ms 4.4x
active screen / plain 12.5 µs 2.7 µs 4.6x
active screen / vt 18.4 µs 6.8 µs 2.7x

Workloads:

  • plain is ASCII lines
  • unicode is 2/3/4-byte codepoints with 10% grapheme clusters
  • styled is heavy SGR churn
  • mixed is styles + Unicode + hyperlinks
  • wrapped is a continuous soft-wrapped stream
  • pin-map/active screen are the selectionString/search-style and visible-screen-only cases respectively.

@mitchellh mitchellh added this to the 1.4.0 milestone Aug 4, 2026
@mitchellh
mitchellh requested a review from a team as a code owner August 4, 2026 03:10
@ghostty-bot ghostty-bot Bot added the vt Control sequence related label Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

vt Control sequence related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant