nx_bench_companion_timed.nx source
↩ module page · 107 lines · 3781 B
1// nx_bench_companion_timed.nx -- wall-clock-wrapped substrate measurement.
2//
3// Sibling to [[nx_bench_companion]]. Adds REAL wall-clock timing
4// (via nx_clock_monotonic_ns) around bench capture, so substrate
5// counters AND elapsed microseconds land in one report.
6//
7// Per CARDINAL [[feedback-no-strawman-perf-comparisons]]: wall-clock
8// under qemu-riscv64 is NOT comparable to wall-clock on physical
9// hardware (qemu is single-threaded + interpreter-emulated). What it
10// IS: the substrate's first real time-measurement primitive, so
11// future physical-hardware bench runs use the same call. When the
12// Phase E + physical-board arcs land, this primitive doesn't change;
13// only the wall-clock number does.
14
15import "nx_syscalls.nx"
16import "nx_tier.nx"
17import "nx_clock.nx"
18import "nx_session.nx"
19import "nx_bench_companion.nx"
20
21// ===== Sealed verdict ===========================================
22
23const NX_BCTM_OK: nx_int = 0
24const NX_BCTM_NULL_SESSION: nx_int = 1
25const NX_BCTM_NULL_REPORT: nx_int = 2
26const NX_BCTM_NEGATIVE_ELAPSED: nx_int = 3
27const NX_BCTM_INVALID: nx_int = 4
28const NX_BCTM_N: nx_int = 5
29
30func nx_bctm_v_is_valid(v: nx_int) -> nx_int {
31 if v < 0 { return 0 }
32 if v >= NX_BCTM_N { return 0 }
33 return 1
34}
35
36// ===== Struct: NxBenchTimedReport ===============================
37//
38// Wraps an NxBenchReport with the wall-clock measurement.
39
40struct NxBenchTimedReport {
41 base: *NxBenchReport,
42 wallclock_start_ns: i64,
43 wallclock_end_ns: i64,
44 wallclock_elapsed_us: i64,
45 verdict: nx_int,
46}
47
48const NX_BCTM_BYTES: nx_int = 40
49
50func nx_bctm_new(base: *NxBenchReport) -> *NxBenchTimedReport {
51 if (base as i64) == 0 { return 0 as *NxBenchTimedReport }
52 let raw: *u8 = sys_mmap(NX_BCTM_BYTES)
53 let t: *NxBenchTimedReport = raw as *NxBenchTimedReport
54 t.base = base
55 t.wallclock_start_ns = 0
56 t.wallclock_end_ns = 0
57 t.wallclock_elapsed_us = 0
58 t.verdict = NX_BCTM_OK
59 return t
60}
61
62// ===== Timed capture ============================================
63//
64// Reads wall-clock NOW, captures session counters, computes elapsed
65// from caller-provided start. Calling pattern:
66//
67// let t: *NxBenchTimedReport = nx_bctm_new(report)
68// t.wallclock_start_ns = nx_clock_monotonic_ns()
69// ... drive workload ...
70// nx_bctm_capture_finish(t, session, n_kinds)
71//
72// After capture_finish: t.wallclock_elapsed_us holds delta in us.
73
74func nx_bctm_capture_finish(t: *NxBenchTimedReport,
75 s: *NxSession,
76 n_subscription_kinds_to_count: nx_int) -> nx_int {
77 if (t as i64) == 0 { return NX_BCTM_INVALID }
78 if (s as i64) == 0 { return NX_BCTM_NULL_SESSION }
79 if (t.base as i64) == 0 { return NX_BCTM_NULL_REPORT }
80 let end_ns: i64 = nx_clock_monotonic_ns()
81 t.wallclock_end_ns = end_ns
82 let elapsed_ns: i64 = end_ns - t.wallclock_start_ns
83 if elapsed_ns < 0 {
84 t.verdict = NX_BCTM_NEGATIVE_ELAPSED
85 return NX_BCTM_NEGATIVE_ELAPSED
86 }
87 t.wallclock_elapsed_us = elapsed_ns / 1000
88 let v_cap: nx_int = nx_bc_capture(s, t.base, n_subscription_kinds_to_count, end_ns as nx_size)
89 if v_cap != NX_BC_V_OK {
90 t.verdict = NX_BCTM_INVALID
91 return NX_BCTM_INVALID
92 }
93 t.verdict = NX_BCTM_OK
94 return NX_BCTM_OK
95}
96
97// ===== Accessors ================================================
98
99func nx_bctm_elapsed_us(t: *NxBenchTimedReport) -> i64 {
100 if (t as i64) == 0 { return 0 - 1 }
101 return t.wallclock_elapsed_us
102}
103
104func nx_bctm_verdict(t: *NxBenchTimedReport) -> nx_int {
105 if (t as i64) == 0 { return NX_BCTM_INVALID }
106 return t.verdict
107}