Files
ghostty/src/terminal/point.zig
Mitchell Hashimoto e974d58615 Inline All The Things (#8946)
I used the new CPU counter mode in Instruments.app to track down
functions that had instruction delivery bottlenecks (indicating i-cache
misses) and picked a bunch of trivial functions to mark as inline (plus
a couple that are only used once or twice and which benefit from
inlining).

The size of `macos-arm64/libghostty-fat.a` built with `zig build
-Doptimize=ReleaseFast -Dxcframework-target=native` goes from
`145,538,856` bytes on `main` to `145,595,952` on this branch, a
negligible increase.

These changes resulted in some pretty sizable improvements in vtebench
results on my machine (Apple M3 Max):
<img width="983" height="696" alt="image"
src="https://github.com/user-attachments/assets/cac595ca-7616-48ed-983c-208c2ca2023f"
/>

With this, the only vtebench test we're slower than Alacritty in (on my
machine, at 130x51 window size) is `dense_cells` (which, IMO, is so
artificial that optimizing for it might actually negatively impact real
world performance).

I also did a pretty simple improvement to how we copy the screen in the
renderer, gave it its own page pool for less memory churn. Further
optimization in that area should be explored since in some scenarios it
seems like as much as 35% of the time on the `io-reader` thread is spent
waiting for the lock.

> [!NOTE]
> Before this is merged, someone really ought to test this on an x86
processor to see how the performance compares there, since this *is*
tuning for my processor specifically, and I know that M chips have
pretty big i-cache compared to some x86 processors which could impact
the performance characteristics of these changes.
2025-10-06 08:59:22 -07:00

84 lines
3.2 KiB
Zig

const std = @import("std");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const size = @import("size.zig");
/// The possible reference locations for a point. When someone says "(42, 80)"
/// in the context of a terminal, that could mean multiple things: it is in the
/// current visible viewport? the current active area of the screen where the
/// cursor is? the entire scrollback history? etc.
///
/// This tag is used to differentiate those cases.
pub const Tag = enum {
/// Top-left is part of the active area where a running program can
/// jump the cursor and make changes. The active area is the "editable"
/// part of the screen.
///
/// The bottom-right of the active tag differs from all other tags
/// because it includes the full height (rows) of the screen, including
/// rows that may not be written yet. This is required because the active
/// area is fully "addressable" by the running program (see below) whereas
/// the other tags are used primarily for reading/modifying past-written
/// data so they can't address unwritten rows.
///
/// Note for those less familiar with terminal functionality: there
/// are escape sequences to move the cursor to any position on
/// the screen, but it is limited to the size of the viewport and
/// the bottommost part of the screen. Terminal programs can't --
/// with sequences at the time of writing this comment -- modify
/// anything in the scrollback, visible viewport (if it differs
/// from the active area), etc.
active,
/// Top-left is the visible viewport. This means that if the user
/// has scrolled in any direction, top-left changes. The bottom-right
/// is the last written row from the top-left.
viewport,
/// Top-left is the furthest back in the scrollback history
/// supported by the screen and the bottom-right is the bottom-right
/// of the last written row. Note this last point is important: the
/// bottom right is NOT necessarily the same as "active" because
/// "active" always allows referencing the full rows tall of the
/// screen whereas "screen" only contains written rows.
screen,
/// The top-left is the same as "screen" but the bottom-right is
/// the line just before the top of "active". This contains only
/// the scrollback history.
history,
};
/// An x/y point in the terminal for some definition of location (tag).
pub const Point = union(Tag) {
active: Coordinate,
viewport: Coordinate,
screen: Coordinate,
history: Coordinate,
pub inline fn coord(self: Point) Coordinate {
return switch (self) {
.active,
.viewport,
.screen,
.history,
=> |v| v,
};
}
};
pub const Coordinate = struct {
/// x can use size.CellCountInt because the number of columns
/// can't ever be more than a valid number of columns in a Page.
x: size.CellCountInt = 0,
/// y does not use size.CellCountInt because certain coordinate
/// usage such as screen/history can have more rows than are possible
/// in a single page.
y: u32 = 0,
pub fn eql(self: Coordinate, other: Coordinate) bool {
return self.x == other.x and self.y == other.y;
}
};