mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
terminal/new: using arena + pool is faster for page init
This commit is contained in:
@ -9,6 +9,7 @@ const assert = std.debug.assert;
|
||||
const point = @import("point.zig");
|
||||
const pagepkg = @import("page.zig");
|
||||
const size = @import("size.zig");
|
||||
const OffsetBuf = size.OffsetBuf;
|
||||
const Page = pagepkg.Page;
|
||||
|
||||
/// The number of PageList.Nodes we preheat the pool with. A node is
|
||||
@ -41,12 +42,17 @@ const List = std.DoublyLinkedList(Page);
|
||||
/// The memory pool we get page nodes from.
|
||||
const Pool = std.heap.MemoryPool(List.Node);
|
||||
|
||||
const std_layout = Page.layout(Page.std_capacity);
|
||||
const PagePool = std.heap.MemoryPoolAligned([std_layout.total_size]u8, std.mem.page_size);
|
||||
|
||||
/// The allocator to use for pages.
|
||||
alloc: Allocator,
|
||||
|
||||
/// The memory pool we get page nodes for the linked list from.
|
||||
pool: Pool,
|
||||
|
||||
page_pool: PagePool,
|
||||
|
||||
/// The list of pages in the screen.
|
||||
pages: List,
|
||||
|
||||
@ -88,15 +94,15 @@ pub fn init(
|
||||
var pool = try Pool.initPreheated(alloc, page_preheat);
|
||||
errdefer pool.deinit();
|
||||
|
||||
var page_pool = try PagePool.initPreheated(std.heap.page_allocator, page_preheat);
|
||||
errdefer page_pool.deinit();
|
||||
|
||||
var page = try pool.create();
|
||||
// no errdefer because the pool deinit will clean up the page
|
||||
const page_buf = OffsetBuf.init(try page_pool.create());
|
||||
|
||||
page.* = .{
|
||||
.data = try Page.init(.{
|
||||
.cols = cols,
|
||||
.rows = @max(rows, page_min_rows),
|
||||
.styles = page_default_styles,
|
||||
}),
|
||||
.data = Page.initBuf(page_buf, std_layout),
|
||||
};
|
||||
errdefer page.data.deinit(alloc);
|
||||
page.data.size.rows = rows;
|
||||
@ -122,6 +128,7 @@ pub fn init(
|
||||
.cols = cols,
|
||||
.rows = rows,
|
||||
.pool = pool,
|
||||
.page_pool = page_pool,
|
||||
.pages = page_list,
|
||||
.viewport = .{ .active = {} },
|
||||
.active = .{ .page = page },
|
||||
@ -131,7 +138,7 @@ pub fn init(
|
||||
pub fn deinit(self: *PageList) void {
|
||||
// Deallocate all the pages. We don't need to deallocate the list or
|
||||
// nodes because they all reside in the pool.
|
||||
while (self.pages.popFirst()) |node| node.data.deinit();
|
||||
self.page_pool.deinit();
|
||||
self.pool.deinit();
|
||||
}
|
||||
|
||||
@ -237,12 +244,10 @@ fn createPage(self: *PageList) !*List.Node {
|
||||
var page = try self.pool.create();
|
||||
errdefer page.data.deinit();
|
||||
|
||||
const page_buf = OffsetBuf.init(try self.page_pool.create());
|
||||
|
||||
page.* = .{
|
||||
.data = try Page.init(.{
|
||||
.cols = self.cols,
|
||||
.rows = @max(self.rows, page_min_rows),
|
||||
.styles = page_default_styles,
|
||||
}),
|
||||
.data = Page.initBuf(page_buf, std_layout),
|
||||
};
|
||||
page.data.size.rows = 0;
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
test {
|
||||
const testing = std.testing;
|
||||
try testing.expect(false);
|
||||
}
|
@ -2,7 +2,6 @@ const builtin = @import("builtin");
|
||||
|
||||
const page = @import("page.zig");
|
||||
pub const PageList = @import("PageList.zig");
|
||||
pub const PagePool = @import("PagePool.zig");
|
||||
pub const Terminal = @import("Terminal.zig");
|
||||
pub const Page = page.Page;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const color = @import("../color.zig");
|
||||
const sgr = @import("../sgr.zig");
|
||||
const style = @import("style.zig");
|
||||
@ -95,8 +96,8 @@ pub const Page = struct {
|
||||
/// requirements. This is enough to support a very large number of cells.
|
||||
/// The standard capacity is chosen as the fast-path for allocation.
|
||||
pub const std_capacity: Capacity = .{
|
||||
.cols = 120,
|
||||
.rows = 520,
|
||||
.cols = 250,
|
||||
.rows = 250,
|
||||
.styles = 128,
|
||||
.grapheme_bytes = 1024,
|
||||
};
|
||||
@ -145,6 +146,13 @@ pub const Page = struct {
|
||||
errdefer std.os.munmap(backing);
|
||||
|
||||
const buf = OffsetBuf.init(backing);
|
||||
return initBuf(buf, l);
|
||||
}
|
||||
|
||||
/// Initialize a new page using the given backing memory.
|
||||
/// It is up to the caller to not call deinit on these pages.
|
||||
pub fn initBuf(buf: OffsetBuf, l: Layout) Page {
|
||||
const cap = l.capacity;
|
||||
const rows = buf.member(Row, l.rows_start);
|
||||
const cells = buf.member(Cell, l.cells_start);
|
||||
|
||||
@ -160,7 +168,7 @@ pub const Page = struct {
|
||||
}
|
||||
|
||||
return .{
|
||||
.memory = backing,
|
||||
.memory = @alignCast(buf.start()[0..l.total_size]),
|
||||
.rows = rows,
|
||||
.cells = cells,
|
||||
.styles = style.Set.init(
|
||||
@ -219,7 +227,7 @@ pub const Page = struct {
|
||||
return .{ .row = row, .cell = cell };
|
||||
}
|
||||
|
||||
const Layout = struct {
|
||||
pub const Layout = struct {
|
||||
total_size: usize,
|
||||
rows_start: usize,
|
||||
cells_start: usize,
|
||||
@ -229,11 +237,12 @@ pub const Page = struct {
|
||||
grapheme_alloc_layout: GraphemeAlloc.Layout,
|
||||
grapheme_map_start: usize,
|
||||
grapheme_map_layout: GraphemeMap.Layout,
|
||||
capacity: Capacity,
|
||||
};
|
||||
|
||||
/// The memory layout for a page given a desired minimum cols
|
||||
/// and rows size.
|
||||
fn layout(cap: Capacity) Layout {
|
||||
pub fn layout(cap: Capacity) Layout {
|
||||
const rows_start = 0;
|
||||
const rows_end = rows_start + (cap.rows * @sizeOf(Row));
|
||||
|
||||
@ -266,6 +275,7 @@ pub const Page = struct {
|
||||
.grapheme_alloc_layout = grapheme_alloc_layout,
|
||||
.grapheme_map_start = grapheme_map_start,
|
||||
.grapheme_map_layout = grapheme_map_layout,
|
||||
.capacity = cap,
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -343,6 +353,15 @@ pub const Cell = packed struct(u64) {
|
||||
// });
|
||||
// }
|
||||
|
||||
test "Page std size" {
|
||||
// We want to ensure that the standard capacity is what we
|
||||
// expect it to be. Changing this is fine but should be done with care
|
||||
// so we fail a test if it changes.
|
||||
const total_size = Page.layout(Page.std_capacity).total_size;
|
||||
try testing.expectEqual(@as(usize, 524_288), total_size); // 512 KiB
|
||||
//const pages = total_size / std.mem.page_size;
|
||||
}
|
||||
|
||||
test "Page init" {
|
||||
var page = try Page.init(.{
|
||||
.cols = 120,
|
||||
@ -353,7 +372,6 @@ test "Page init" {
|
||||
}
|
||||
|
||||
test "Page read and write cells" {
|
||||
const testing = std.testing;
|
||||
var page = try Page.init(.{
|
||||
.cols = 10,
|
||||
.rows = 10,
|
||||
|
Reference in New Issue
Block a user