mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 17:26:09 +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 point = @import("point.zig");
|
||||||
const pagepkg = @import("page.zig");
|
const pagepkg = @import("page.zig");
|
||||||
const size = @import("size.zig");
|
const size = @import("size.zig");
|
||||||
|
const OffsetBuf = size.OffsetBuf;
|
||||||
const Page = pagepkg.Page;
|
const Page = pagepkg.Page;
|
||||||
|
|
||||||
/// The number of PageList.Nodes we preheat the pool with. A node is
|
/// 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.
|
/// The memory pool we get page nodes from.
|
||||||
const Pool = std.heap.MemoryPool(List.Node);
|
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.
|
/// The allocator to use for pages.
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
|
|
||||||
/// The memory pool we get page nodes for the linked list from.
|
/// The memory pool we get page nodes for the linked list from.
|
||||||
pool: Pool,
|
pool: Pool,
|
||||||
|
|
||||||
|
page_pool: PagePool,
|
||||||
|
|
||||||
/// The list of pages in the screen.
|
/// The list of pages in the screen.
|
||||||
pages: List,
|
pages: List,
|
||||||
|
|
||||||
@ -88,15 +94,15 @@ pub fn init(
|
|||||||
var pool = try Pool.initPreheated(alloc, page_preheat);
|
var pool = try Pool.initPreheated(alloc, page_preheat);
|
||||||
errdefer pool.deinit();
|
errdefer pool.deinit();
|
||||||
|
|
||||||
|
var page_pool = try PagePool.initPreheated(std.heap.page_allocator, page_preheat);
|
||||||
|
errdefer page_pool.deinit();
|
||||||
|
|
||||||
var page = try pool.create();
|
var page = try pool.create();
|
||||||
// no errdefer because the pool deinit will clean up the page
|
// no errdefer because the pool deinit will clean up the page
|
||||||
|
const page_buf = OffsetBuf.init(try page_pool.create());
|
||||||
|
|
||||||
page.* = .{
|
page.* = .{
|
||||||
.data = try Page.init(.{
|
.data = Page.initBuf(page_buf, std_layout),
|
||||||
.cols = cols,
|
|
||||||
.rows = @max(rows, page_min_rows),
|
|
||||||
.styles = page_default_styles,
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
errdefer page.data.deinit(alloc);
|
errdefer page.data.deinit(alloc);
|
||||||
page.data.size.rows = rows;
|
page.data.size.rows = rows;
|
||||||
@ -122,6 +128,7 @@ pub fn init(
|
|||||||
.cols = cols,
|
.cols = cols,
|
||||||
.rows = rows,
|
.rows = rows,
|
||||||
.pool = pool,
|
.pool = pool,
|
||||||
|
.page_pool = page_pool,
|
||||||
.pages = page_list,
|
.pages = page_list,
|
||||||
.viewport = .{ .active = {} },
|
.viewport = .{ .active = {} },
|
||||||
.active = .{ .page = page },
|
.active = .{ .page = page },
|
||||||
@ -131,7 +138,7 @@ pub fn init(
|
|||||||
pub fn deinit(self: *PageList) void {
|
pub fn deinit(self: *PageList) void {
|
||||||
// Deallocate all the pages. We don't need to deallocate the list or
|
// Deallocate all the pages. We don't need to deallocate the list or
|
||||||
// nodes because they all reside in the pool.
|
// nodes because they all reside in the pool.
|
||||||
while (self.pages.popFirst()) |node| node.data.deinit();
|
self.page_pool.deinit();
|
||||||
self.pool.deinit();
|
self.pool.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,12 +244,10 @@ fn createPage(self: *PageList) !*List.Node {
|
|||||||
var page = try self.pool.create();
|
var page = try self.pool.create();
|
||||||
errdefer page.data.deinit();
|
errdefer page.data.deinit();
|
||||||
|
|
||||||
|
const page_buf = OffsetBuf.init(try self.page_pool.create());
|
||||||
|
|
||||||
page.* = .{
|
page.* = .{
|
||||||
.data = try Page.init(.{
|
.data = Page.initBuf(page_buf, std_layout),
|
||||||
.cols = self.cols,
|
|
||||||
.rows = @max(self.rows, page_min_rows),
|
|
||||||
.styles = page_default_styles,
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
page.data.size.rows = 0;
|
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");
|
const page = @import("page.zig");
|
||||||
pub const PageList = @import("PageList.zig");
|
pub const PageList = @import("PageList.zig");
|
||||||
pub const PagePool = @import("PagePool.zig");
|
|
||||||
pub const Terminal = @import("Terminal.zig");
|
pub const Terminal = @import("Terminal.zig");
|
||||||
pub const Page = page.Page;
|
pub const Page = page.Page;
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const testing = std.testing;
|
||||||
const color = @import("../color.zig");
|
const color = @import("../color.zig");
|
||||||
const sgr = @import("../sgr.zig");
|
const sgr = @import("../sgr.zig");
|
||||||
const style = @import("style.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.
|
/// requirements. This is enough to support a very large number of cells.
|
||||||
/// The standard capacity is chosen as the fast-path for allocation.
|
/// The standard capacity is chosen as the fast-path for allocation.
|
||||||
pub const std_capacity: Capacity = .{
|
pub const std_capacity: Capacity = .{
|
||||||
.cols = 120,
|
.cols = 250,
|
||||||
.rows = 520,
|
.rows = 250,
|
||||||
.styles = 128,
|
.styles = 128,
|
||||||
.grapheme_bytes = 1024,
|
.grapheme_bytes = 1024,
|
||||||
};
|
};
|
||||||
@ -145,6 +146,13 @@ pub const Page = struct {
|
|||||||
errdefer std.os.munmap(backing);
|
errdefer std.os.munmap(backing);
|
||||||
|
|
||||||
const buf = OffsetBuf.init(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 rows = buf.member(Row, l.rows_start);
|
||||||
const cells = buf.member(Cell, l.cells_start);
|
const cells = buf.member(Cell, l.cells_start);
|
||||||
|
|
||||||
@ -160,7 +168,7 @@ pub const Page = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.memory = backing,
|
.memory = @alignCast(buf.start()[0..l.total_size]),
|
||||||
.rows = rows,
|
.rows = rows,
|
||||||
.cells = cells,
|
.cells = cells,
|
||||||
.styles = style.Set.init(
|
.styles = style.Set.init(
|
||||||
@ -219,7 +227,7 @@ pub const Page = struct {
|
|||||||
return .{ .row = row, .cell = cell };
|
return .{ .row = row, .cell = cell };
|
||||||
}
|
}
|
||||||
|
|
||||||
const Layout = struct {
|
pub const Layout = struct {
|
||||||
total_size: usize,
|
total_size: usize,
|
||||||
rows_start: usize,
|
rows_start: usize,
|
||||||
cells_start: usize,
|
cells_start: usize,
|
||||||
@ -229,11 +237,12 @@ pub const Page = struct {
|
|||||||
grapheme_alloc_layout: GraphemeAlloc.Layout,
|
grapheme_alloc_layout: GraphemeAlloc.Layout,
|
||||||
grapheme_map_start: usize,
|
grapheme_map_start: usize,
|
||||||
grapheme_map_layout: GraphemeMap.Layout,
|
grapheme_map_layout: GraphemeMap.Layout,
|
||||||
|
capacity: Capacity,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The memory layout for a page given a desired minimum cols
|
/// The memory layout for a page given a desired minimum cols
|
||||||
/// and rows size.
|
/// and rows size.
|
||||||
fn layout(cap: Capacity) Layout {
|
pub fn layout(cap: Capacity) Layout {
|
||||||
const rows_start = 0;
|
const rows_start = 0;
|
||||||
const rows_end = rows_start + (cap.rows * @sizeOf(Row));
|
const rows_end = rows_start + (cap.rows * @sizeOf(Row));
|
||||||
|
|
||||||
@ -266,6 +275,7 @@ pub const Page = struct {
|
|||||||
.grapheme_alloc_layout = grapheme_alloc_layout,
|
.grapheme_alloc_layout = grapheme_alloc_layout,
|
||||||
.grapheme_map_start = grapheme_map_start,
|
.grapheme_map_start = grapheme_map_start,
|
||||||
.grapheme_map_layout = grapheme_map_layout,
|
.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" {
|
test "Page init" {
|
||||||
var page = try Page.init(.{
|
var page = try Page.init(.{
|
||||||
.cols = 120,
|
.cols = 120,
|
||||||
@ -353,7 +372,6 @@ test "Page init" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "Page read and write cells" {
|
test "Page read and write cells" {
|
||||||
const testing = std.testing;
|
|
||||||
var page = try Page.init(.{
|
var page = try Page.init(.{
|
||||||
.cols = 10,
|
.cols = 10,
|
||||||
.rows = 10,
|
.rows = 10,
|
||||||
|
Reference in New Issue
Block a user