From 9006a3f43101df07ad511f8a283b68fbc114c364 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 1 Mar 2024 14:05:52 -0800 Subject: [PATCH] bench/resize --- build.zig | 2 +- src/bench/resize.sh | 12 ++++ src/bench/resize.zig | 110 ++++++++++++++++++++++++++++++++++ src/build_config.zig | 1 + src/main.zig | 1 + src/terminal/new/PageList.zig | 23 +++++++ 6 files changed, 148 insertions(+), 1 deletion(-) create mode 100755 src/bench/resize.sh create mode 100644 src/bench/resize.zig diff --git a/build.zig b/build.zig index 958e21a79..de008af35 100644 --- a/build.zig +++ b/build.zig @@ -1360,7 +1360,7 @@ fn benchSteps( .target = target, // We always want our benchmarks to be in release mode. - .optimize = .Debug, + .optimize = .ReleaseFast, }); c_exe.linkLibC(); if (install) b.installArtifact(c_exe); diff --git a/src/bench/resize.sh b/src/bench/resize.sh new file mode 100755 index 000000000..8f420bf01 --- /dev/null +++ b/src/bench/resize.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# +# Uncomment to test with an active terminal state. +# ARGS=" --terminal" + +hyperfine \ + --warmup 10 \ + -n new \ + "./zig-out/bin/bench-resize --mode=new${ARGS}" \ + -n old \ + "./zig-out/bin/bench-resize --mode=old${ARGS}" + diff --git a/src/bench/resize.zig b/src/bench/resize.zig new file mode 100644 index 000000000..53261486e --- /dev/null +++ b/src/bench/resize.zig @@ -0,0 +1,110 @@ +//! This benchmark tests the speed of resizing. + +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; +const cli = @import("../cli.zig"); +const terminal = @import("../terminal/main.zig"); + +const Args = struct { + mode: Mode = .old, + + /// The number of times to loop. + count: usize = 10_000, + + /// Rows and cols in the terminal. + rows: usize = 50, + cols: usize = 100, + + /// This is set by the CLI parser for deinit. + _arena: ?ArenaAllocator = null, + + pub fn deinit(self: *Args) void { + if (self._arena) |arena| arena.deinit(); + self.* = undefined; + } +}; + +const Mode = enum { + /// The default allocation strategy of the structure. + old, + + /// Use a memory pool to allocate pages from a backing buffer. + new, +}; + +pub const std_options: std.Options = .{ + .log_level = .debug, +}; + +pub fn main() !void { + // We want to use the c allocator because it is much faster than GPA. + const alloc = std.heap.c_allocator; + + // Parse our args + var args: Args = .{}; + defer args.deinit(); + { + var iter = try std.process.argsWithAllocator(alloc); + defer iter.deinit(); + try cli.args.parse(Args, alloc, &args, &iter); + } + + // Handle the modes that do not depend on terminal state first. + switch (args.mode) { + .old => { + var t = try terminal.Terminal.init(alloc, args.cols, args.rows); + defer t.deinit(alloc); + try benchOld(&t, args); + }, + + .new => { + var t = try terminal.new.Terminal.init( + alloc, + @intCast(args.cols), + @intCast(args.rows), + ); + defer t.deinit(alloc); + try benchNew(&t, args); + }, + } +} + +noinline fn benchOld(t: *terminal.Terminal, args: Args) !void { + // We fill the terminal with letters. + for (0..args.rows) |row| { + for (0..args.cols) |col| { + t.setCursorPos(row + 1, col + 1); + try t.print('A'); + } + } + + for (0..args.count) |i| { + const cols: usize, const rows: usize = if (i % 2 == 0) + .{ args.cols * 2, args.rows * 2 } + else + .{ args.cols, args.rows }; + + try t.screen.resizeWithoutReflow(@intCast(rows), @intCast(cols)); + } +} + +noinline fn benchNew(t: *terminal.new.Terminal, args: Args) !void { + // We fill the terminal with letters. + for (0..args.rows) |row| { + for (0..args.cols) |col| { + t.setCursorPos(row + 1, col + 1); + try t.print('A'); + } + } + + for (0..args.count) |i| { + const cols: usize, const rows: usize = if (i % 2 == 0) + .{ args.cols * 2, args.rows * 2 } + else + .{ args.cols, args.rows }; + + try t.screen.resizeWithoutReflow(@intCast(rows), @intCast(cols)); + } +} diff --git a/src/build_config.zig b/src/build_config.zig index 8992af8ad..c894917b9 100644 --- a/src/build_config.zig +++ b/src/build_config.zig @@ -144,6 +144,7 @@ pub const ExeEntrypoint = enum { bench_codepoint_width, bench_grapheme_break, bench_page_init, + bench_resize, bench_screen_copy, bench_vt_insert_lines, }; diff --git a/src/main.zig b/src/main.zig index 5d14e927b..1b83e24d0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -11,6 +11,7 @@ pub usingnamespace switch (build_config.exe_entrypoint) { .bench_codepoint_width => @import("bench/codepoint-width.zig"), .bench_grapheme_break => @import("bench/grapheme-break.zig"), .bench_page_init => @import("bench/page-init.zig"), + .bench_resize => @import("bench/resize.zig"), .bench_screen_copy => @import("bench/screen-copy.zig"), .bench_vt_insert_lines => @import("bench/vt-insert-lines.zig"), }; diff --git a/src/terminal/new/PageList.zig b/src/terminal/new/PageList.zig index 8ae1fe63f..6b3b08ed1 100644 --- a/src/terminal/new/PageList.zig +++ b/src/terminal/new/PageList.zig @@ -2179,3 +2179,26 @@ test "PageList resize (no reflow) empty screen" { try testing.expectEqual(@as(usize, 10), cells.len); } } + +// test "PageList bug" { +// const testing = std.testing; +// const alloc = testing.allocator; +// +// var s = try init(alloc, 300, 100, null); +// defer s.deinit(); +// try testing.expect(s.pages.first == s.pages.last); +// const page = &s.pages.first.?.data; +// for (0..s.rows) |y| { +// for (0..s.cols) |x| { +// const rac = page.getRowAndCell(x, y); +// rac.cell.* = .{ +// .content_tag = .codepoint, +// .content = .{ .codepoint = 'A' }, +// }; +// } +// } +// +// // Resize +// try s.resize(.{ .cols = s.cols * 2, .rows = s.rows * 2, .reflow = false }); +// try s.resize(.{ .cols = s.cols / 2, .rows = s.rows / 2, .reflow = false }); +// }