Commit Graph

15 Commits

Author SHA1 Message Date
Chris Marchesi
048619a6bf global: take minimal instead of juicy main
The early-stage main Zig wrapper recognizes if main only needs the
minimal state (args and lower-level environment) and skips a bunch of
unneeded initialization (allocator, arena, threaded I/O, and the
higher-level environment map). Particularly, the fact that it does not
set up an I/O instance means that we won't have any unneeded signal
handlers set up for the unused threaded I/O implementation, which is
similar in spirit to the fixes we applied for the C VT implementation,
with the notable difference that we do actually set a threaded I/O up in
global state - hence, again, we don't want the duplicate unused one.
2026-07-21 22:05:33 -07:00
Mitchell Hashimoto
f2a7652aba mitchell's touchups
- benchmark: avoid buffers to avoid a memcpy
- build: keep frame pointers on macOS. There was some debug changes from
  Zig 0.15 and this helps. Also, Apple actually requires/expects x29 to
  always be a frame pointer.
- build/macos: force libSystem symbols instead of compiler-rt
- global: add InitOpts.tool so that ghostty-gen/bench can parse their
  own actions in `+action`
- quirks: provide our own vectorized memset. see the comment for more
  details why.
- synthetic: fix UB by accessing global.io before it was initialized
- terminal/hash_map: force inline for unique repr types. Zig 0.15
  inlined and 0.16 doesn't, measured a huge slowdown in hyperlink
  benchmarks.
- terminal: add explicit `@Vector` usage for storing a run of identical cells
  as well as for scanning printable cells. This auto-vectorized in Zig
  0.15 but not in Zig 0.16. This produces the same assembly.
- unicode: properties and LUT need power-of-two backing integer to avoid
  bad LLVM codegen
2026-07-21 17:19:16 -07:00
Chris Marchesi
e8525c0fd9 Update to Zig 0.16.0
This commit represents the majority of the work necessary to upgrade
Ghostty to use Zig 0.16.0.

Key parts:

* In addition to its previous responsibilities, the global state now
  houses state for global I/O implementations and the process
  environment. It is now also utilized in the main application along
  with the C library. Where necessary, global state is isolated from key
  parts of the implementation (e.g., in libghostty subsystems), and it's
  expected that this list will grow.

* We currently manage our own C translation layer where necessary. In
  these cases, cImport has been removed in favor of the new external
  translate-c package. Due to fixes that have needed be made to properly
  translate the dependencies that were swapped out, as mentioned, we
  have had to backport fixes from the current translate-c package (and
  the upstream Arocc dependency). We will host this ourselves until Zig
  0.17.0 is released with these fixes.

* Where necessary (only a small number of cases), some stdlib code from
  0.15.2 (and even from 0.17.0) has been taken, adopted, and vendored in
  lib/compat.

Co-authored-by: Leah Amelia Chen <hi@pluie.me>
2026-07-21 12:35:05 -07:00
Mitchell Hashimoto
7e14347c13 terminal: bound page map probe lengths
#13292

Page maps previously allowed a 100% load factor. Once live entries
and tombstones filled every slot, a missing-key lookup or insertion
could scan the entire map.

Reserve 20% of each offset hash map as insertion headroom and track
that budget separately from the live count. Port the allocation-free
in-place rehash from Zig HashMapUnmanaged so canonical insertion can
rebuild fragmented probes and restore tombstone-exhausted headroom
without growing the page. Assumed-capacity insertion now applies the
same guard, preventing the headroom counter from wrapping.

Pass the exact requested hyperlink count into map layout before
load-factor scaling, avoiding a redundant power-of-two rounding step.
Screen-level recovery now grows only when live hyperlinks actually fill
usable capacity.

ReleaseFast terminal benchmarks compare main with the combined map
changes:

| workload | before | after | speedup |
|---|---:|---:|---:|
| map churn | 1.253 s | 12.5 ms | 100x |
| full OSC 8 stream | 3.576 s | 75.6 ms | 47x |
| clear and redraw | 299.1 ms | 118.3 ms | 2.5x |

Co-authored-by: Tim Culverhouse <tim@timculverhouse.com>
2026-07-11 09:21:27 -07:00
Tim Culverhouse
f6f79acce6 terminal: dispatch APC string bytes in bulk slices
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.
2026-07-09 17:07:55 -05:00
Mitchell Hashimoto
9156ada169 terminal: add cold-history compression pass
PageList could compress individual nodes but had no policy-level
operation for selecting pages that are safe to reclaim. The compressed
state therefore remained reachable only from tests.

Add a stateless pass that considers only complete history pages while
the viewport follows the active area. It gates work on supported
retained-mapping reclamation, reports attempts and retained bytes, and
leaves restoration lazy when a resize pulls compressed history back into
the active area.

Add a live scrollback-compression benchmark for measuring complete
PageList compression and restoration against saved VT corpora. The pass
still has no production callers, and ReleaseFast terminal-stream
comparisons remain within the existing throughput guardrail.
2026-07-09 09:47:12 -07:00
Mitchell Hashimoto
c62c159841 terminal: add standalone LZ4 block codec
Scrollback compression needs a codec that can be used from libghostty-vt
without pulling in libc, and we need to measure it before integrating it
with terminal page ownership.

This adds an allocation-free raw LZ4 block codec in scalar Zig.  Callers
provide the input, output, and fixed-size scratch table. The decoder
uses an exact-size output contract so page metadata mismatches fail
cleanly. Compatibility vectors, boundary cases, random round trips, and
fuzz coverage exercise the block format.

Also adds a page-compression benchmark that operates on reusable raw
page corpora. Compression and decompression have separate modes with
setup outside the timed region, plus a ratio report and no-op baseline.
Nothing uses compression in the terminal yet; this is the isolated codec
and measurement groundwork.
2026-07-09 09:47:11 -07:00
Jeffrey C. Ollie
01a75ceec4 benchmark: add option to microbenchmark OSC parser 2025-12-10 22:31:27 -06:00
Mitchell Hashimoto
9a46397b59 benchmark: screen clone 2025-11-17 05:08:19 -10:00
Jeffrey C. Ollie
a7da96faee add two LUT-based implementations of isSymbol 2025-09-05 07:58:01 -05:00
Mitchell Hashimoto
a28b7e9205 synthetic cli (ghostty-gen) 2025-07-09 15:06:24 -07:00
Mitchell Hashimoto
99ed984af2 benchmark: add GraphemeBreak and TerminalParser benchmarks 2025-07-09 15:06:24 -07:00
Mitchell Hashimoto
5890826356 benchmark: add codepoint width benchmark 2025-07-09 15:06:24 -07:00
Mitchell Hashimoto
20bb71c627 libghostty: export benchmark CLI API 2025-07-09 15:06:24 -07:00
Mitchell Hashimoto
b8f5cf9d52 initial ghostty-bench program 2025-07-09 15:06:24 -07:00