summaryrefslogtreecommitdiff
path: root/src/pardes/app.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes/app.zig')
-rw-r--r--src/pardes/app.zig26
1 files changed, 25 insertions, 1 deletions
diff --git a/src/pardes/app.zig b/src/pardes/app.zig
index a83485a..23da203 100644
--- a/src/pardes/app.zig
+++ b/src/pardes/app.zig
@@ -37,6 +37,10 @@
const std = @import("std");
const soc = @import("soc");
const config = @import("config");
+
+/// `-Dprof`: time the two phases of a keystroke on the board and print the cycle counts. A
+/// diagnostic, not a feature - see the loop.
+const prof = config.prof;
const hal = @import("hal");
const heapmod = @import("heap");
const uart = @import("uart.zig");
@@ -203,16 +207,36 @@ export fn zig_main() noreturn {
var in: [256]u8 = undefined;
while (!pardes_p4_quit()) {
+ // ATTRIBUTION. The host can time a keystroke's round trip but cannot see what the firmware
+ // spent it on, and the two candidates - parsing and editing, versus rendering - want
+ // opposite fixes. `soc.cycles()` is the unprivileged cycle counter, so this costs two CSR
+ // reads per phase and quantises at one cycle, which is four orders of magnitude below the
+ // milliseconds being attributed. Gated on `prof` so the shipping build carries none of it.
const n = uart.read(&in);
- if (n > 0) pardes_p4_input(&in, n);
+ var input_cy: u64 = 0;
+ if (n > 0) {
+ const t0 = if (prof) soc.cycles() else 0;
+ pardes_p4_input(&in, n);
+ if (prof) input_cy = soc.cycles() - t0;
+ }
pardes_p4_tick(nowMs());
// Only when there is something to show. On a link this slow an unconditional repaint per
// iteration would saturate the wire and starve input.
if (pardes_p4_wants_frame()) {
+ const t0 = if (prof) soc.cycles() else 0;
const err = pardes_p4_render();
if (err != 0) soc.rom.print("MARK PARDES_RENDER_FAIL rc=%u\r\n", .{err});
+ if (prof) {
+ const render_cy = soc.cycles() - t0;
+ // 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)),
+ });
+ }
}
}