From 81b805b8c2a03f307533a2f861e7eb89826b60f9 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 1 Sep 2022 22:48:33 -0700 Subject: [PATCH] use an arena allocator for tty allocs libuv always called the alloc cb right before read, and read owns the buffer. By using an arena, we're probably just reusing the same buffer over and over again. This should be quite fast. In tracing, this indeed changes the MTPC on ttyReadAlloc from ~750ns to ~275ns. I'll take it! --- src/Window.zig | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Window.zig b/src/Window.zig index 076826e73..43a3919a8 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -33,6 +33,7 @@ const WRITE_REQ_PREALLOC = std.math.pow(usize, 2, 5); /// Allocator alloc: Allocator, +alloc_io_arena: std.heap.ArenaAllocator, /// The glfw window handle. window: glfw.Window, @@ -323,8 +324,15 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo errdefer cursor.destroy(); try window.setCursor(cursor); + // Create our IO allocator arena. Libuv appears to guarantee (in code, + // not in docs) that read_alloc is called directly before a read so + // we can use an arena to make allocation faster. + var io_arena = std.heap.ArenaAllocator.init(alloc); + errdefer io_arena.deinit(); + self.* = .{ .alloc = alloc, + .alloc_io_arena = io_arena, .window = window, .cursor = cursor, .focused = false, @@ -410,6 +418,8 @@ pub fn destroy(self: *Window) void { // We can destroy the cursor right away. glfw will just revert any // windows using it to the default. self.cursor.destroy(); + + self.alloc_io_arena.deinit(); } pub fn shouldClose(self: Window) bool { @@ -1235,7 +1245,8 @@ fn ttyReadAlloc(t: *libuv.Tty, size: usize) ?[]u8 { const tracy = trace(@src()); defer tracy.end(); - const alloc = t.loop().getData(Allocator).?.*; + const win = t.getData(Window) orelse return null; + const alloc = win.alloc_io_arena.allocator(); return alloc.alloc(u8, size) catch null; } @@ -1245,7 +1256,10 @@ fn ttyRead(t: *libuv.Tty, n: isize, buf: []const u8) void { defer tracy.end(); const win = t.getData(Window).?; - defer win.alloc.free(buf); + defer { + const alloc = win.alloc_io_arena.allocator(); + alloc.free(buf); + } // log.info("DATA: {d}", .{n}); // log.info("DATA: {any}", .{buf[0..@intCast(usize, n)]});