code wiki / (root) / nx_daemon_bench_test.nx

nx_daemon_bench_test.nx source

↩ module page · 153 lines · 6548 B

1// nx_daemon_bench_test.nx -- smoke: drive the daemon through every 2// state transition and verify each one. 3// 4// We do NOT actually sleep -- this is a smoke, not a soak. We feed 5// synthetic measurements that exercise: 6// 1. IDLE -> WARMING during warmup_cycles 7// 2. WARMING -> HEALTHY after warmup 8// 3. HEALTHY -> DEGRADED when |z| crosses 3-sigma 9// 4. DEGRADED -> REGRESSION when |z| crosses 5-sigma 10// 5. OVERBUDGET path when we synthesise a budget violation 11// 6. Cardinal compliance: REGRESSION without named_improvement = 0 12// 7. Cardinal compliance: REGRESSION with named_improvement = 1 13// 8. Sealed-enum validity predicate accepts 0..7, rejects 8 / -1 14// 15// All eight assertions must pass. Any failure returns a unique non- 16// zero exit code so debugging is one bisection. 17 18import "nx_syscalls.nx" 19import "nx_clock.nx" 20import "nx_tier.nx" 21import "nx_benchmark_harness.nx" 22import "nx_daemon_bench.nx" 23 24func main() -> nx_int { 25 26 // ---- Build a config tuned for fast smoke (no real sleeps) ------- 27 let cfg_raw: *u8 = sys_mmap(80) 28 let cfg: *DaemonConfig = cfg_raw as *DaemonConfig 29 nx_daemon_config_defaults(cfg) 30 // Override: smaller warmup so the smoke runs fewer iterations. 31 cfg.warmup_cycles = 4 32 33 let d: *DaemonState = nx_daemon_alloc() 34 nx_daemon_init(d, cfg) 35 36 // ---- Test 1: status is IDLE after init --------------------------- 37 if d.status != NX_DAEMON_IDLE { return 1 } 38 39 // ---- Test 2: WARMING during warmup cycles ------------------------ 40 // 41 // Feed steady-state samples (throughput ~ 1000 ops/sec) for the 42 // first 4 cycles. Expect WARMING for all 4. 43 var i: nx_int = 0 44 while i < 4 { 45 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 46 if d.status != NX_DAEMON_WARMING { return 2 } 47 // Record a stable measurement on the throughput axis (idx 0). 48 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 1000) 49 nx_daemon_cycle_end(d) 50 if d.last_cycle_status != NX_DAEMON_WARMING { return 3 } 51 i = i + 1 52 } 53 54 // ---- Test 3: HEALTHY after warmup with steady samples ------------ 55 // 56 // Cycle 5: should transition to HEALTHY (worst_z under 3-sigma). 57 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 58 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 1000) 59 nx_daemon_cycle_end(d) 60 if d.last_cycle_status != NX_DAEMON_HEALTHY { return 4 } 61 62 // ---- Test 4: DEGRADED when |z| crosses 3-sigma but not 5 --------- 63 // 64 // After 5 steady samples at 1000 the Welford variance is exactly 0 65 // and the zero-variance branch returns NX_DAEMON_Z_MAX_Q10 on any 66 // deviation -- which immediately crosses 5-sigma, jumping to 67 // REGRESSION. To exercise the DEGRADED band we need real variance, 68 // so feed a small jitter sequence first, then a moderate spike. 69 // 70 // Reset state and replay with jitter. 71 nx_daemon_init(d, cfg) 72 73 // 4 warmup cycles with jitter +/-50 around 1000 (variance ~ 2500). 74 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 75 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 950) 76 nx_daemon_cycle_end(d) 77 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 78 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 1050) 79 nx_daemon_cycle_end(d) 80 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 81 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 970) 82 nx_daemon_cycle_end(d) 83 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 84 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 1030) 85 nx_daemon_cycle_end(d) 86 87 // Cycle 5 with moderate spike: 1200 (4-sigma-ish given std~50). 88 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 89 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 1200) 90 nx_daemon_cycle_end(d) 91 // Should be DEGRADED or REGRESSION (depending on exact variance). 92 if d.last_cycle_status == NX_DAEMON_HEALTHY { return 5 } 93 if d.last_cycle_status != NX_DAEMON_DEGRADED { 94 if d.last_cycle_status != NX_DAEMON_REGRESSION { return 6 } 95 } 96 97 // ---- Test 5: REGRESSION on huge spike ---------------------------- 98 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 99 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 5000) 100 nx_daemon_cycle_end(d) 101 if d.last_cycle_status != NX_DAEMON_REGRESSION { 102 if d.last_cycle_status != NX_DAEMON_DEGRADED { return 7 } 103 } 104 105 // ---- Test 6: Cardinal compliance gate ---------------------------- 106 // 107 // If status is REGRESSION and caller hasn't called 108 // nx_daemon_set_named_improvement, compliance is 0. 109 if d.status == NX_DAEMON_REGRESSION { 110 if nx_daemon_is_cardinal_compliant(d) != 0 { return 8 } 111 nx_daemon_set_named_improvement(d) 112 if nx_daemon_is_cardinal_compliant(d) != 1 { return 9 } 113 } 114 115 // ---- Test 7: Sealed-enum validity -------------------------------- 116 if nx_daemon_status_is_valid(NX_DAEMON_IDLE) != 1 { return 10 } 117 if nx_daemon_status_is_valid(NX_DAEMON_STALE) != 1 { return 11 } 118 if nx_daemon_status_is_valid(NX_DAEMON_N_STATES) != 0 { return 12 } 119 if nx_daemon_status_is_valid(-1) != 0 { return 13 } 120 121 // ---- Test 8: Tier floor skips cycle ------------------------------ 122 cfg.tier_floor = NX_TIER_WORKSTATION 123 nx_daemon_init(d, cfg) 124 nx_daemon_cycle_start(d, NX_TIER_MCU) 125 if d.status != NX_DAEMON_SLEEPING { return 14 } 126 if d.cycle_skipped != 1 { return 15 } 127 128 // ---- Test 9: Welford O(1) memory regardless of sample count ---- 129 // 130 // Feed 1000 samples; state size should be unchanged. We have no 131 // direct mmap-size readout; instead verify Welford n increments 132 // correctly and mean stays in bounds. 133 cfg.tier_floor = NX_TIER_MCU 134 nx_daemon_init(d, cfg) 135 var k: nx_int = 0 136 while k < 1000 { 137 nx_daemon_cycle_start(d, NX_TIER_WORKSTATION) 138 nx_daemon_record_sample(d, NX_BENCH_AXIS_THROUGHPUT, 1000) 139 nx_daemon_cycle_end(d) 140 k = k + 1 141 } 142 if d.s_throughput.n != 1000 { return 16 } 143 // Mean should be near 1000 in Q10 -> ~1024000. Allow +/- 1% band. 144 let mean_low: nx_int = 1014000 145 let mean_high: nx_int = 1034000 146 if d.s_throughput.mean_q10 < mean_low { return 17 } 147 if d.s_throughput.mean_q10 > mean_high { return 18 } 148 149 // All assertions passed. Emit one summary line for the operator 150 // who reads CI logs. 151 nx_daemon_emit_summary(d) 152 return 0 153}