summaryrefslogtreecommitdiff
path: root/test/perf.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-30 18:40:41 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:17 -0300
commit9a256d34ebca317e3007adf71c2b94016059d4a3 (patch)
treede19eed72424da8b2e43e8cd8f673e6ae71de3d5 /test/perf.zig
parent14dc0b452cf646fe5c9f060fbe66afb01f153ac0 (diff)
downloadpardes-9a256d34ebca317e3007adf71c2b94016059d4a3.tar.gz
pardes-9a256d34ebca317e3007adf71c2b94016059d4a3.zip
A selection deep in a long line costs a render what one at its start does: 5 MB in, /screen goes from 14.7 s to 5 ms
Every render measured a selection's and the cursor's columns from the start of their line (lineDisplayOffset walked the whole prefix twice), so a selection near the end of a 5 MB line stalled each frame, 3 s at 1 MB in and 14.7 s at 5 MB. The cost grew with the offset, with Wrap on or off. Three changes make it independent of where the selection is: - display width adds (a tab is tab_width wherever it stands), so the offset between two columns is the width of the text between them, never the prefix; - the selection's rows are clamped to what is shown: a row wholly before the selection is skipped, a start before the row's first column starts there, and an end past its last column ends there; - a head or cursor whose column lies past its visible row (the last visible row of a line owns every column after its start) is not measured, since it is not drawn. Measured on a Debug build, 5 MB line: offset 10, 1 MB and 5 MB now take 11, 6 and 5 ms per /screen. A new perf gate case, deep-sel, renders with the selection 2 MB into a line: 83 us on Debug. The baselines were re-recorded for the new harness. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'test/perf.zig')
-rw-r--r--test/perf.zig28
1 files changed, 25 insertions, 3 deletions
diff --git a/test/perf.zig b/test/perf.zig
index 95b55748..94076a25 100644
--- a/test/perf.zig
+++ b/test/perf.zig
@@ -53,6 +53,10 @@ const Op = enum {
/// close, as a shell's `>>` loop makes: each costs its own bytes, not a
/// pass over the whole body for its cursor, line index and saved hash.
body_appends,
+ /// A render with the selection 2 MB into one line: only the columns
+ /// shown are measured, so it costs what a selection at the line's
+ /// start does (4.5 s a frame at 5 MB before).
+ deep_selection,
fn label(o: Op) []const u8 {
return switch (o) {
@@ -65,6 +69,7 @@ const Op = enum {
.edit_char => "edit-char",
.body_write => "body-2m",
.body_appends => "body-appends",
+ .deep_selection => "deep-sel",
};
}
};
@@ -83,6 +88,16 @@ fn bodyWrite(core: *pardes.Pardes, serial: u32) void {
_ = core.serveFs(.{ .tag = 4, .op = .release, .node = body, .handle = h, .opened = true });
}
+/// One line of 2 MB appended to the file, no newline in it.
+fn longLine(core: *pardes.Pardes, serial: u32) void {
+ const Node = pardes.ctlfs.Node;
+ const body = Node.of(serial, .body);
+ @memset(&body_chunk, 'z');
+ const h = core.serveFs(.{ .tag = 1, .op = .open, .node = body, .omode = 1 }).handle;
+ for (0..8) |_| _ = core.serveFs(.{ .tag = 2, .op = .write, .node = body, .handle = h, .data = &body_chunk });
+ _ = core.serveFs(.{ .tag = 4, .op = .release, .node = body, .handle = h, .opened = true });
+}
+
const append_chunk_len = 8 * 1024;
const append_count = 64;
@@ -534,9 +549,16 @@ fn measure(op: Op, fx: Fixture, path: []const u8, expected_bytes: usize, reps: u
core.update(.{ .key = .{ .cp = 'i', .text = "i" } });
pump(core);
}
+ if (op == .deep_selection) {
+ longLine(core, pane.serial);
+ pump(core);
+ const len: u32 = @intCast(pane.file.?.content.len);
+ pardes.ctlfs.pane.setDot(pane, .{ .q0 = len - 10, .q1 = len - 5 });
+ pump(core);
+ }
for (0..warmup + reps) |n| {
- seek(pane, fx, n);
+ if (op != .deep_selection) seek(pane, fx, n);
_ = try frame(core); // settle the view at the new spot, untimed
const before = .{ .row = pane.body.cur_row, .col = pane.body.cur_col, .scroll = pane.scroll(), .len = pane.file.?.content.len };
const rect = core.rects[id];
@@ -545,7 +567,7 @@ fn measure(op: Op, fx: Fixture, path: []const u8, expected_bytes: usize, reps: u
const t0 = nowNs();
switch (op) {
.open => unreachable,
- .render => {},
+ .render, .deep_selection => {},
.key_down => core.update(.{ .key = .{ .cp = 'j', .text = "j" } }),
.key_right => core.update(.{ .key = .{ .cp = 'l', .text = "l" } }),
.page_down => core.update(.{ .key = .{ .cp = pardes.Key.page_down } }),
@@ -561,7 +583,7 @@ fn measure(op: Op, fx: Fixture, path: []const u8, expected_bytes: usize, reps: u
.open => unreachable,
.body_write => if (pane.file.?.content.len != before.len + 8 * body_chunk.len) return error.BodyWriteWasNotAppended,
.body_appends => if (pane.file.?.content.len != before.len + append_count * append_chunk_len) return error.BodyAppendsWereNotAppended,
- .render => if (pane.body.cur_row != before.row or pane.body.cur_col != before.col or pane.file.?.content.len != before.len)
+ .render, .deep_selection => if (pane.body.cur_row != before.row or pane.body.cur_col != before.col or pane.file.?.content.len != before.len)
return error.RenderChangedDocument,
.key_down => if (pane.body.cur_row != before.row + 1) return error.DownDidNotMove,
.key_right => if (pane.body.cur_row != before.row or pane.body.cur_col != before.col + 1) return error.RightDidNotMove,