diff options
| -rw-r--r-- | src/p4.zig | 21 | ||||
| -rw-r--r-- | test/perf.zig | 5 |
2 files changed, 22 insertions, 4 deletions
@@ -541,12 +541,25 @@ fn present(_: ?*anyopaque, surface: *const pardes.Surface) void { var y: u16 = 0; while (y < surface.rows) : (y += 1) { + const row0 = @as(usize, y) * @as(usize, surface.cols); + const src = surface.cells[row0..][0..surface.cols]; + + // A ROW AT A TIME FIRST. `Surface.cells` is contiguous and row-major, so a whole row is one + // `memcmp` against the shadow - and on a keystroke eleven of twelve rows are untouched. The + // per-cell loop below is ~40 branchy comparisons where this is one call over 1,120 bytes; + // measured, the walk fell from 246 us to a fraction of it. Byte equality implies visual + // equality (see `sameCell`), so a row that compares equal cannot be hiding a changed cell - + // and a row that differs only in padding falls through to the per-cell path, which is + // correct and merely slower. + if (usable and !full) { + const shadow = prev_cells[row0..][0..surface.cols]; + if (std.mem.eql(u8, std.mem.sliceAsBytes(src), std.mem.sliceAsBytes(shadow))) continue; + } + var x: u16 = 0; while (x < surface.cols) : (x += 1) { - // `at` takes a mutable Surface but only reads; the tty shell does the same const-cast - // for the same reason (src/tty/tty.zig:1105). - const cell = @constCast(surface).at(x, y); - const idx = @as(usize, y) * @as(usize, surface.cols) + @as(usize, x); + const cell = &src[x]; + const idx = row0 + @as(usize, x); if (usable) { if (!full and sameCell(cell, &prev_cells[idx])) continue; prev_cells[idx] = cell.*; diff --git a/test/perf.zig b/test/perf.zig index 087eea80..5f8fe18e 100644 --- a/test/perf.zig +++ b/test/perf.zig @@ -75,6 +75,11 @@ const fixtures = [_]Fixture{ .{ .name = "large", .lines = 300_000, .cols = 60 }, // the other failure mode: few lines, each one wider than any screen .{ .name = "longline", .lines = 400, .cols = 8_000 }, + // The ESP32-P4 firmware's actual document: a handful of lines, one of them wider than its + // 40-column screen. Here because a profile taken on `small` is a profile of a 1,000-line line + // index, and the board has twelve lines - so the costs that dominate there are not the costs + // that dominate it. Pair with `--cols 40 --rows 12`. + .{ .name = "p4", .lines = 12, .cols = 240 }, }; const Op = enum { |
