mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-08-24 16:11:43 +00:00
terminal/snapshot: skip remap tables for pages without styles
Decoding a page allocated and zeroed two full remap tables (a 128 KB
entries array plus an 8 KB seen bitmap each for styles and hyperlinks)
even when the page declared no table entries at all, which is every page
of plain scrollback. Empty tables now use a shared `.empty` remap that
allocates nothing; `get` reads it as all-unmapped through a length check.
Pages that do declare entries are unchanged.
(Leaving the entries array unzeroed behind a seen-bitmap-gated `get` was
also tried and measured no better than the plain memset, so the table
keeps its simple zero-means-unmapped representation.)
Benchmarks ("prev" is the parent commit):
| wasm | encode prev | encode | decode prev | decode |
|-----------|------------:|---------:|------------:|---------:|
| ascii | 2.06 ms | 2.13 ms | 2.70 ms | 2.54 ms |
| styled | 2.41 ms | 2.29 ms | 6.56 ms | 6.75 ms |
| truecolor | 5.02 ms | 4.95 ms | 11.86 ms | 12.05 ms |
| cjk | 6.03 ms | 6.23 ms | 11.60 ms | 11.39 ms |
| grapheme | 8.36 ms | 8.72 ms | 11.39 ms | 11.27 ms |
| native | mode | prev | this |
|--------|--------|--------:|--------:|
| ascii | encode | 25.6 ms | 24.4 ms |
| ascii | decode | 48.1 ms | 45.1 ms |
| utf8 | encode | 41.7 ms | 41.9 ms |
| utf8 | decode | 58.5 ms | 58.6 ms |
This commit is contained in:
@@ -1515,6 +1515,11 @@ fn Remap(comptime Id: type) type {
|
||||
/// semantics.
|
||||
seen: std.DynamicBitSetUnmanaged,
|
||||
|
||||
/// A remap with no entries at all: every lookup is unmapped. Use
|
||||
/// this instead of `init` when the encoded table is empty so pages
|
||||
/// without styles or hyperlinks allocate nothing.
|
||||
pub const empty: Self = .{ .entries = &.{}, .seen = .{} };
|
||||
|
||||
pub fn init(alloc: Allocator) Allocator.Error!Self {
|
||||
const entries = try alloc.alloc(Id, capacity);
|
||||
errdefer alloc.free(entries);
|
||||
@@ -1527,25 +1532,29 @@ fn Remap(comptime Id: type) type {
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self, alloc: Allocator) void {
|
||||
alloc.free(self.entries);
|
||||
self.seen.deinit(alloc);
|
||||
if (self.entries.len != 0) {
|
||||
alloc.free(self.entries);
|
||||
self.seen.deinit(alloc);
|
||||
}
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
/// Record one encoded-to-native mapping.
|
||||
/// Record one encoded-to-native mapping. Illegal on `empty`.
|
||||
pub fn put(self: *Self, encoded: Id, native: Id) void {
|
||||
assert(!self.seen.isSet(encoded));
|
||||
self.entries[encoded] = native;
|
||||
self.seen.set(encoded);
|
||||
}
|
||||
|
||||
/// Whether the encoded ID already has an entry, even a default one.
|
||||
/// Whether the encoded ID already has an entry, even a default
|
||||
/// one. Illegal on `empty`.
|
||||
pub fn contains(self: *const Self, encoded: Id) bool {
|
||||
return self.seen.isSet(encoded);
|
||||
}
|
||||
|
||||
/// The native ID for an encoded ID, or zero when unmapped.
|
||||
pub inline fn get(self: *const Self, encoded: Id) Id {
|
||||
if (self.entries.len == 0) return 0;
|
||||
return self.entries[encoded];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -367,12 +367,19 @@ fn decodePayloadBody(
|
||||
page.pauseIntegrityChecks(true);
|
||||
defer page.pauseIntegrityChecks(false);
|
||||
|
||||
var style_remap = grid.StyleRemap.init(alloc) catch
|
||||
return error.OutOfMemory;
|
||||
// Pages without styles or hyperlinks, the common case for plain
|
||||
// scrollback, skip the remap tables entirely: every encoded cell ID
|
||||
// resolves to the default through the empty remap.
|
||||
var style_remap: grid.StyleRemap = if (header.style_count > 0)
|
||||
grid.StyleRemap.init(alloc) catch return error.OutOfMemory
|
||||
else
|
||||
.empty;
|
||||
defer style_remap.deinit(alloc);
|
||||
|
||||
var hyperlink_remap = grid.HyperlinkRemap.init(alloc) catch
|
||||
return error.OutOfMemory;
|
||||
var hyperlink_remap: grid.HyperlinkRemap = if (header.hyperlink_count > 0)
|
||||
grid.HyperlinkRemap.init(alloc) catch return error.OutOfMemory
|
||||
else
|
||||
.empty;
|
||||
defer hyperlink_remap.deinit(alloc);
|
||||
|
||||
// Styles
|
||||
|
||||
Reference in New Issue
Block a user