From f2d4b64032d5908a63108f6f91c1c6f27ac711d9 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 23 Feb 2024 08:05:37 -0800 Subject: [PATCH] terminal/new: using arena + pool is faster for page init --- src/terminal/new/PageList.zig | 27 ++++++++++++++++----------- src/terminal/new/PagePool.zig | 8 -------- src/terminal/new/main.zig | 1 - src/terminal/new/page.zig | 30 ++++++++++++++++++++++++------ 4 files changed, 40 insertions(+), 26 deletions(-) delete mode 100644 src/terminal/new/PagePool.zig diff --git a/src/terminal/new/PageList.zig b/src/terminal/new/PageList.zig index 313847d96..1bafdc147 100644 --- a/src/terminal/new/PageList.zig +++ b/src/terminal/new/PageList.zig @@ -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; diff --git a/src/terminal/new/PagePool.zig b/src/terminal/new/PagePool.zig deleted file mode 100644 index 52790a7d0..000000000 --- a/src/terminal/new/PagePool.zig +++ /dev/null @@ -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); -} diff --git a/src/terminal/new/main.zig b/src/terminal/new/main.zig index 40b88e013..cac9fa6ab 100644 --- a/src/terminal/new/main.zig +++ b/src/terminal/new/main.zig @@ -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; diff --git a/src/terminal/new/page.zig b/src/terminal/new/page.zig index 99f6d1b5f..848cf5ced 100644 --- a/src/terminal/new/page.zig +++ b/src/terminal/new/page.zig @@ -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,