summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pardes/app.zig26
1 files changed, 24 insertions, 2 deletions
diff --git a/src/pardes/app.zig b/src/pardes/app.zig
index 23da203..2f13865 100644
--- a/src/pardes/app.zig
+++ b/src/pardes/app.zig
@@ -101,6 +101,11 @@ extern fn pardes_p4_wants_frame() callconv(.c) bool;
/// Has the user asked to leave? There is nowhere to go, so this only stops the loop.
extern fn pardes_p4_quit() callconv(.c) bool;
+/// The last frame's three stages in CPU cycles: the copy of pardes's Surface into vaxis's grid,
+/// vaxis's own diff-and-emit, and the push into the UART. Only meaningful under `-Dprof`; the
+/// editor object always exports it, and it costs two CSR reads per stage.
+extern fn pardes_p4_frame_prof(copy: *u64, render: *u64, flush: *u64) callconv(.c) void;
+
// ------------------------------------------------------------------------------------ the sink
/// The write callback handed to `pardes_p4_init`. No context is needed - there is one UART.
@@ -230,11 +235,28 @@ export fn zig_main() noreturn {
if (err != 0) soc.rom.print("MARK PARDES_RENDER_FAIL rc=%u\r\n", .{err});
if (prof) {
const render_cy = soc.cycles() - t0;
+ // A SECOND render with nothing changed since the first. It splits the cost in two:
+ // whatever this still costs is the price of walking and diffing the whole editor
+ // state, paid regardless of output, while the difference between the two is the
+ // price of the change itself. `wants_frame` is false now, so this only happens
+ // under -Dprof and never on a shipping build.
+ const t1 = soc.cycles();
+ _ = pardes_p4_render();
+ const idle_cy = soc.cycles() - t1;
// Reported in cycles, not microseconds: the divisor is the CPU clock, which this
// firmware does not set and has only ever measured, so converting here would bake a
// guess into the data. `experiments/` divides by the clock it measured.
- soc.rom.print("PROF in=%u render=%u\r\n", .{
- @as(u32, @intCast(input_cy)), @as(u32, @intCast(render_cy)),
+ var copy_cy: u64 = 0;
+ var vx_cy: u64 = 0;
+ var flush_cy: u64 = 0;
+ pardes_p4_frame_prof(&copy_cy, &vx_cy, &flush_cy);
+ soc.rom.print("PROF in=%u render=%u idle=%u copy=%u vaxis=%u flush=%u\r\n", .{
+ @as(u32, @intCast(input_cy)),
+ @as(u32, @intCast(render_cy)),
+ @as(u32, @intCast(idle_cy)),
+ @as(u32, @intCast(copy_cy)),
+ @as(u32, @intCast(vx_cy)),
+ @as(u32, @intCast(flush_cy)),
});
}
}