code wiki / (root) / nx_time_quality.nx

nx_time_quality.nx source

↩ module page · 276 lines · 9987 B

1// nx_time_quality.nx -- four-dimensional time classification primitive. 2// 3// Cardinal: feedback-time-quality-fourth-dimension-triangulation. 4// 5// Time in the substrate is 4-D by construction: 6// (1) t (quantitative) -- wall-ns measured 7// (2) phase (qualitative) -- which racing-crew bucket 8// (3) budget (declared) -- caller's intent at start 9// (4) norm (population) -- avg across history for this phase 10// 11// Three of those (measured + declared + norm) triangulate. When 12// they agree -> confidence. When one disagrees -> signal worth 13// surfacing to the kernel / racing crew / coach. 14// 15// API: 16// nx_tq_record(work_tag, phase, declared_ns, measured_ns) -> 0 17// nx_tq_classify(work_tag) -> phase | -1 18// nx_tq_budget(work_tag) -> declared_ns | -1 19// nx_tq_history_norm(phase) -> avg_ns 20// nx_tq_triangle(work_tag) -> OK | SLOW | FAST | DRIFT | UNKNOWN 21// nx_tq_n_records() -> i64 22// 23// Substrate-native: import syscalls.nx, mmap-backed ledger, sealed 24// enum verdicts, --strip clean. 25 26import "syscalls.nx" 27const NX_MAGIC_4096: i64 = 4096 28const NX_MAGIC_1024: i64 = 1024 29 30// 8 phases (qualitative time-quality). 31const NX_TQ_HOT_PATH: i64 = 1 32const NX_TQ_WARM_PATH: i64 = 2 33const NX_TQ_COLD_PATH: i64 = 3 34const NX_TQ_LEISURE: i64 = 4 35const NX_TQ_SETUP: i64 = 5 36const NX_TQ_TEARDOWN: i64 = 6 37const NX_TQ_DEADLINE: i64 = 7 38const NX_TQ_OPPORTUNISTIC: i64 = 8 39const NX_TQ_PHASE_N: i64 = 9 40 41// Triangle verdicts. 42const NX_TQ_TRIANGLE_OK: i64 = 0 43const NX_TQ_TRIANGLE_SLOW: i64 = 1 44const NX_TQ_TRIANGLE_FAST: i64 = 2 45const NX_TQ_TRIANGLE_DRIFT: i64 = 3 46const NX_TQ_TRIANGLE_UNKNOWN: i64 = 4 47 48// Triangle thresholds (Q10 fraction of declared / norm). 49const NX_TQ_DELTA_OK_BOUND: i64 = 256 // |delta| < 25% = OK 50const NX_TQ_DELTA_BIG_BOUND: i64 = 512 // |delta| > 50% = SLOW/FAST 51 52static NX_TQ_ACTIVE: i64 53static NX_TQ_LEDGER_PTR: i64 54static NX_TQ_N_RECORDS: i64 55static NX_TQ_CAPACITY: i64 56 57// Per-phase rolling stats: total_ns, count. Index by phase tag (1-based). 58static NX_TQ_PHASE_TOTAL_PTR: i64 59static NX_TQ_PHASE_COUNT_PTR: i64 60 61const NX_TQ_REC_SIZE: i64 = 40 // 5 i64: work_tag/phase/decl/meas/seq 62const NX_TQ_CHUNK_BYTES: i64 = 40960 // 1024 records 63 64func nx_tq_init() -> i64 { 65 if NX_TQ_LEDGER_PTR != 0 { return 0 } 66 let raw: *u8 = sys_mmap(NX_TQ_CHUNK_BYTES) 67 if (raw as i64) == 0 { return 1 } 68 if (raw as i64) == 0 - 1 { return 2 } 69 NX_TQ_LEDGER_PTR = raw as i64 70 NX_TQ_N_RECORDS = 0 71 NX_TQ_CAPACITY = NX_TQ_CHUNK_BYTES / NX_TQ_REC_SIZE 72 73 // Per-phase stats: NX_TQ_PHASE_N slots, 16 bytes each = 144 bytes. 74 let st: *u8 = sys_mmap(NX_MAGIC_4096) 75 if (st as i64) == 0 { return 3 } 76 if (st as i64) == 0 - 1 { return 4 } 77 NX_TQ_PHASE_TOTAL_PTR = st as i64 78 NX_TQ_PHASE_COUNT_PTR = (st as i64) + (NX_TQ_PHASE_N * 8) 79 var i: i64 = 0 80 while i < NX_TQ_PHASE_N { 81 let t: *i64 = (NX_TQ_PHASE_TOTAL_PTR + i * 8) as *i64 82 let c: *i64 = (NX_TQ_PHASE_COUNT_PTR + i * 8) as *i64 83 t[0] = 0 84 c[0] = 0 85 i = i + 1 86 } 87 88 NX_TQ_ACTIVE = 1 89 return 0 90} 91 92func nx_tq_enable() -> i64 { NX_TQ_ACTIVE = 1; return 0 } 93func nx_tq_disable() -> i64 { NX_TQ_ACTIVE = 0; return 0 } 94func nx_tq_is_active() -> i64 { return NX_TQ_ACTIVE } 95 96// Record one time-event. Returns 0 OK. 97func nx_tq_record(work_tag: i64, phase: i64, 98 declared_ns: i64, measured_ns: i64) -> i64 { 99 if NX_TQ_ACTIVE == 0 { return 0 } 100 nx_tq_init() 101 if NX_TQ_LEDGER_PTR == 0 { return 0 } 102 if phase < 1 { return 1 } 103 if phase > 8 { return 1 } 104 if declared_ns < 0 { return 2 } 105 if measured_ns < 0 { return 3 } 106 if NX_TQ_N_RECORDS >= NX_TQ_CAPACITY { return 4 } 107 108 let base: i64 = NX_TQ_LEDGER_PTR + (NX_TQ_N_RECORDS * NX_TQ_REC_SIZE) 109 let rec: *i64 = base as *i64 110 rec[0] = work_tag 111 rec[1] = phase 112 rec[2] = declared_ns 113 rec[3] = measured_ns 114 rec[4] = NX_TQ_N_RECORDS 115 NX_TQ_N_RECORDS = NX_TQ_N_RECORDS + 1 116 117 // Update per-phase rolling stats. 118 let t: *i64 = (NX_TQ_PHASE_TOTAL_PTR + phase * 8) as *i64 119 let c: *i64 = (NX_TQ_PHASE_COUNT_PTR + phase * 8) as *i64 120 t[0] = t[0] + measured_ns 121 c[0] = c[0] + 1 122 return 0 123} 124 125// Find the most-recent slot for a work_tag. 126func _nx_tq_latest_slot(work_tag: i64) -> i64 { 127 nx_tq_init() 128 var i: i64 = NX_TQ_N_RECORDS - 1 129 while i >= 0 { 130 let base: i64 = NX_TQ_LEDGER_PTR + (i * NX_TQ_REC_SIZE) 131 let rec: *i64 = base as *i64 132 if rec[0] == work_tag { return i } 133 i = i - 1 134 } 135 return 0 - 1 136} 137 138func nx_tq_classify(work_tag: i64) -> i64 { 139 let slot: i64 = _nx_tq_latest_slot(work_tag) 140 if slot < 0 { return 0 - 1 } 141 let base: i64 = NX_TQ_LEDGER_PTR + (slot * NX_TQ_REC_SIZE) 142 let rec: *i64 = base as *i64 143 return rec[1] 144} 145 146func nx_tq_budget(work_tag: i64) -> i64 { 147 let slot: i64 = _nx_tq_latest_slot(work_tag) 148 if slot < 0 { return 0 - 1 } 149 let base: i64 = NX_TQ_LEDGER_PTR + (slot * NX_TQ_REC_SIZE) 150 let rec: *i64 = base as *i64 151 return rec[2] 152} 153 154// Population-level average measured-ns for a phase. 155func nx_tq_history_norm(phase: i64) -> i64 { 156 if phase < 1 { return 0 } 157 if phase > 8 { return 0 } 158 nx_tq_init() 159 let t: *i64 = (NX_TQ_PHASE_TOTAL_PTR + phase * 8) as *i64 160 let c: *i64 = (NX_TQ_PHASE_COUNT_PTR + phase * 8) as *i64 161 if c[0] == 0 { return 0 } 162 return t[0] / c[0] 163} 164 165// Triangulation verdict for the latest event of a work_tag. 166// abs(measured - declared) / declared <= 25% AND 167// abs(measured - norm) / norm <= 25% -> OK 168// (measured - declared) / declared >= 50% -> SLOW 169// (measured - declared) / declared <= -50% -> FAST 170// (measured - norm) / norm >= 50% -> DRIFT 171// 172// Computed via integer math; thresholds in Q10 of declared/norm. 173func nx_tq_triangle(work_tag: i64) -> i64 { 174 let slot: i64 = _nx_tq_latest_slot(work_tag) 175 if slot < 0 { return NX_TQ_TRIANGLE_UNKNOWN } 176 let base: i64 = NX_TQ_LEDGER_PTR + (slot * NX_TQ_REC_SIZE) 177 let rec: *i64 = base as *i64 178 let phase: i64 = rec[1] 179 let declared: i64 = rec[2] 180 let measured: i64 = rec[3] 181 182 // Compute delta_declared_q10 = (measured - declared) * 1024 / declared. 183 // Guard against zero declared. 184 var delta_d: i64 = 0 185 if declared > 0 { 186 delta_d = (measured - declared) * NX_MAGIC_1024 / declared 187 } 188 if delta_d >= NX_TQ_DELTA_BIG_BOUND { return NX_TQ_TRIANGLE_SLOW } 189 if delta_d <= 0 - NX_TQ_DELTA_BIG_BOUND { return NX_TQ_TRIANGLE_FAST } 190 191 // Compute delta_norm_q10. 192 let norm: i64 = nx_tq_history_norm(phase) 193 var delta_n: i64 = 0 194 if norm > 0 { 195 delta_n = (measured - norm) * NX_MAGIC_1024 / norm 196 } 197 // Absolute value of delta_n for DRIFT check. 198 var abs_n: i64 = delta_n 199 if abs_n < 0 { abs_n = 0 - abs_n } 200 if abs_n >= NX_TQ_DELTA_BIG_BOUND { return NX_TQ_TRIANGLE_DRIFT } 201 202 // Within OK band. 203 var abs_d: i64 = delta_d 204 if abs_d < 0 { abs_d = 0 - abs_d } 205 if abs_d <= NX_TQ_DELTA_OK_BOUND { 206 if abs_n <= NX_TQ_DELTA_OK_BOUND { return NX_TQ_TRIANGLE_OK } 207 } 208 // Mid-band: slight off but not big. Default OK for V0. 209 return NX_TQ_TRIANGLE_OK 210} 211 212func nx_tq_n_records() -> i64 { 213 nx_tq_init() 214 return NX_TQ_N_RECORDS 215} 216 217// ---- self-test --------------------------------------------------- 218// expect_exit: 0 219 220func main() -> i64 { 221 if nx_tq_init() != 0 { return 1 } 222 223 // Disabled-mode short-circuit. 224 nx_tq_disable() 225 nx_tq_record(0xAAAA, NX_TQ_HOT_PATH, 100, 95) 226 if nx_tq_n_records() != 0 { return 10 } 227 228 // Enable + record several hot-path events near declared (OK). 229 nx_tq_enable() 230 if nx_tq_record(0x100, NX_TQ_HOT_PATH, 200, 210) != 0 { return 20 } 231 if nx_tq_record(0x100, NX_TQ_HOT_PATH, 200, 195) != 0 { return 21 } 232 if nx_tq_record(0x100, NX_TQ_HOT_PATH, 200, 205) != 0 { return 22 } 233 234 // Population norm for HOT_PATH should be (210+195+205)/3 = 203. 235 let norm: i64 = nx_tq_history_norm(NX_TQ_HOT_PATH) 236 if norm != 203 { return 30 } 237 238 // Latest event 0x100 was measured=205 vs declared=200 vs norm=203 239 // -> all within 25% bands -> OK triangle. 240 if nx_tq_triangle(0x100) != NX_TQ_TRIANGLE_OK { return 40 } 241 242 // Record a SLOW event for 0x200 -- measured 2x declared. 243 if nx_tq_record(0x200, NX_TQ_WARM_PATH, 100, 250) != 0 { return 50 } 244 if nx_tq_triangle(0x200) != NX_TQ_TRIANGLE_SLOW { return 51 } 245 246 // Record a FAST event for 0x300 -- measured 30% of declared. 247 if nx_tq_record(0x300, NX_TQ_COLD_PATH, 1000, 200) != 0 { return 60 } 248 if nx_tq_triangle(0x300) != NX_TQ_TRIANGLE_FAST { return 61 } 249 250 // Build a LEISURE norm of ~100ns from 3 events, then record one 251 // at 5x norm -> DRIFT. 252 if nx_tq_record(0x400, NX_TQ_LEISURE, 100, 100) != 0 { return 70 } 253 if nx_tq_record(0x400, NX_TQ_LEISURE, 100, 100) != 0 { return 71 } 254 if nx_tq_record(0x400, NX_TQ_LEISURE, 100, 100) != 0 { return 72 } 255 // Last record measured=600 declared=600 (within decl band) but 256 // norm is around (100+100+100+600)/4 = 225; 600 vs 225 = +166% >> 50%. 257 // Skip declared-comparison by recording with declared=measured. 258 if nx_tq_record(0x400, NX_TQ_LEISURE, 600, 600) != 0 { return 73 } 259 if nx_tq_triangle(0x400) != NX_TQ_TRIANGLE_DRIFT { return 74 } 260 261 // Lookups. 262 if nx_tq_classify(0x100) != NX_TQ_HOT_PATH { return 80 } 263 if nx_tq_classify(0x200) != NX_TQ_WARM_PATH { return 81 } 264 if nx_tq_classify(0xDEAD) != 0 - 1 { return 82 } 265 if nx_tq_budget(0x300) != 1000 { return 83 } 266 267 // Invalid phase rejected. 268 if nx_tq_record(0xCAFE, 99, 100, 100) == 0 { return 90 } 269 if nx_tq_record(0xCAFE, NX_TQ_HOT_PATH, 0 - 1, 100) == 0 { return 91 } 270 if nx_tq_record(0xCAFE, NX_TQ_HOT_PATH, 100, 0 - 1) == 0 { return 92 } 271 272 // Triangle for unknown work_tag -> UNKNOWN. 273 if nx_tq_triangle(0xFEED) != NX_TQ_TRIANGLE_UNKNOWN { return 95 } 274 275 return 0 276}