code wiki / _hdl_build / nx_room_diag.nx

nx_room_diag.nx source

↩ module page · 157 lines · 7567 B

1// nx_room_diag.nx -- X-ROOM: sovereign DETERMINISTIC multi-party room DIAGNOSTIC -- 2// the "WHERE DOES IT SUCK" analyzer. When you test a room with real people, raw "it's 3// choppy" is useless; this ingests per-PARTICIPANT per-tick metrics and pinpoints each 4// person's DOMINANT problem AND the subsystem that fixes it, then ranks worst-first. 5// 6// Per participant columns: [loss_pm, jitter_ms, rtt_ms, delivered_kbps, target_kbps, layer]. 7// Classifier (data-driven thresholds, rule 11) -> a PROBLEM CODE + a FIX subsystem: 8// STARVED (layer==0, no video) -> nx_room_sfu (fairness allocation) 9// LOSSY (loss_pm > LOSS thresh) -> nx_room_fec / nx_room_red 10// JITTERY (jitter_ms > JIT thresh) -> nx_room_jitterbuf 11// CONGESTED (delivered << target AND high rtt) -> nx_room_bwe 12// UNDERSERVED (delivered << target) -> nx_room_simulcast / abr 13// OK (none) -> - 14// Severity ranks dimensions so the ONE thing most worth fixing surfaces first. 15// 16// EXCEED axis (honest): turns a live test into an ACTIONABLE, audit-replayable bottleneck 17// report mapped to the exact sovereign fix -- not a vague "bad call". This is the SENSE 18// layer the self-improving room loop needs. HONEST SCOPE: the analyzer; the live daemon 19// + client must EMIT these per-participant samples (the instrumentation wiring) for a 20// real test -- that is the next deploy step. 21// 22// main() is the SELF-VALIDATING GATE. Evidence -> knowledge/status/room_diag.log. 23// license_tier: ORIGINAL 24import "nx_syscalls.nx" 25 26const DIAG_LOG: *u8 = "knowledge/status/room_diag.log" 27const D_LOSS: i64 = 50 // > 5% packet loss = LOSSY 28const D_JIT: i64 = 30 // > 30ms jitter = JITTERY 29const D_RTT: i64 = 350 // > 350ms one-way-ish = high latency (overseas) 30const D_UNDER: i64 = 70 // delivered < 70% of target = underserved 31 32// problem codes 33const P_OK: i64 = 0 34const P_STARVED: i64 = 1 35const P_LOSSY: i64 = 2 36const P_JITTERY: i64 = 3 37const P_CONGESTED: i64 = 4 38const P_UNDERSERVED: i64 = 5 39 40func dw(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 } 41func dwn(fd: i64, v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64=v; if m<0 {m=0-m; sys_write(fd,"-" as *u8,1)}; let t: *u8 = sys_mmap(28); var k: i64=0; if m==0 {t[0]=48;k=1}; while m>0 {t[k]=(48+(m%10)) as u8; m=m/10; k=k+1}; var i: i64=0; while i<k {bb[i]=t[k-1-i]; i=i+1}; sys_write(fd, bb, k); return 0 } 42 43func d_pname(code: i64) -> *u8 { 44 if code == P_OK { return "OK" as *u8 } 45 if code == P_STARVED { return "STARVED" as *u8 } 46 if code == P_LOSSY { return "LOSSY" as *u8 } 47 if code == P_JITTERY { return "JITTERY" as *u8 } 48 if code == P_CONGESTED { return "CONGESTED" as *u8 } 49 return "UNDERSERVED" as *u8 50} 51func d_fix(code: i64) -> *u8 { 52 if code == P_OK { return "-" as *u8 } 53 if code == P_STARVED { return "nx_room_sfu" as *u8 } 54 if code == P_LOSSY { return "nx_room_fec/red" as *u8 } 55 if code == P_JITTERY { return "nx_room_jitterbuf" as *u8 } 56 if code == P_CONGESTED { return "nx_room_bwe" as *u8 } 57 return "nx_room_simulcast/abr" as *u8 58} 59 60// classify one participant -> problem code (the DOMINANT problem). 61func d_classify(loss: i64, jit: i64, rtt: i64, deliv: i64, tgt: i64, layer: i64) -> i64 { 62 if layer == 0 { return P_STARVED } // no video at all = worst 63 let underserved: i64 = (deliv * 100) < (tgt * D_UNDER) 64 // severity per dimension (how far past threshold; comparable scales) 65 var sev_loss: i64 = 0 66 if loss > D_LOSS { sev_loss = (loss - D_LOSS) } 67 var sev_jit: i64 = 0 68 if jit > D_JIT { sev_jit = (jit - D_JIT) * 3 } 69 var sev_cong: i64 = 0 70 if underserved { if rtt > D_RTT { sev_cong = (tgt * D_UNDER / 100 - deliv) } } 71 var sev_under: i64 = 0 72 if underserved { if rtt <= D_RTT { sev_under = (tgt * D_UNDER / 100 - deliv) } } 73 // pick the worst dimension 74 var best: i64 = 0 75 var code: i64 = P_OK 76 if sev_loss > best { best = sev_loss; code = P_LOSSY } 77 if sev_jit > best { best = sev_jit; code = P_JITTERY } 78 if sev_cong > best { best = sev_cong; code = P_CONGESTED } 79 if sev_under> best { best = sev_under; code = P_UNDERSERVED } 80 return code 81} 82 83func main() -> i64 { 84 let P: i64 = 5 85 let C: i64 = 6 86 let m: *i64 = sys_mmap(8 * P * C) as *i64 87 // P0 healthy; P1 lossy; P2 jittery; P3 starved; P4 congested 88 // cols: loss_pm, jitter_ms, rtt_ms, delivered, target, layer 89 m[0*C+0]=5; m[0*C+1]=10; m[0*C+2]=250; m[0*C+3]=800; m[0*C+4]=800; m[0*C+5]=3 90 m[1*C+0]=120; m[1*C+1]=10; m[1*C+2]=250; m[1*C+3]=760; m[1*C+4]=800; m[1*C+5]=3 91 m[2*C+0]=5; m[2*C+1]=80; m[2*C+2]=250; m[2*C+3]=780; m[2*C+4]=800; m[2*C+5]=3 92 m[3*C+0]=8; m[3*C+1]=12; m[3*C+2]=260; m[3*C+3]=0; m[3*C+4]=800; m[3*C+5]=0 93 m[4*C+0]=10; m[4*C+1]=15; m[4*C+2]=400; m[4*C+3]=180; m[4*C+4]=800; m[4*C+5]=1 94 let code: *i64 = sys_mmap(8 * P) as *i64 95 var ok: i64 = 1 96 97 var i: i64 = 0 98 while i < P { 99 code[i] = d_classify(m[i*C+0], m[i*C+1], m[i*C+2], m[i*C+3], m[i*C+4], m[i*C+5]) 100 i = i + 1 101 } 102 if code[0] != P_OK { ok = 0 } 103 if code[1] != P_LOSSY { ok = 0 } 104 if code[2] != P_JITTERY { ok = 0 } 105 if code[3] != P_STARVED { ok = 0 } 106 if code[4] != P_CONGESTED { ok = 0 } 107 108 // rank: worst = the lowest-numbered severe code is not enough; STARVED is the worst 109 // problem to have. find first STARVED, else first non-OK. 110 var worst: i64 = 0 - 1 111 i = 0 112 while i < P { if code[i] == P_STARVED { if worst < 0 { worst = i } } i = i + 1 } 113 if worst < 0 { i = 0; while i < P { if code[i] != P_OK { if worst < 0 { worst = i } } i = i + 1 } } 114 var healthy: i64 = 0 115 i = 0 116 while i < P { if code[i] == P_OK { healthy = healthy + 1 } i = i + 1 } 117 if worst != 3 { ok = 0 } // P3 (starved) is the worst 118 if healthy != 1 { ok = 0 } // only P0 healthy 119 120 // neg-control: an all-healthy room -> every code OK, no false alarms 121 var allok: i64 = 1 122 i = 0 123 while i < P { 124 let c2: i64 = d_classify(5, 10, 250, 790, 800, 3) 125 if c2 != P_OK { allok = 0 } 126 i = i + 1 127 } 128 if allok != 1 { ok = 0 } 129 130 // tamper: a broken LOSS threshold would MISS the lossy participant -> classifier 131 // depends on real thresholds. emulate by reclassifying P1 with loss below thresh. 132 let c_tamper: i64 = d_classify(40, 10, 250, 760, 800, 3) // loss 40 < D_LOSS(50) 133 if c_tamper == P_LOSSY { ok = 0 } // below threshold must NOT flag lossy (no false positive) 134 135 dw(1, "ROOMDIAGGATE per-participant:" as *u8) 136 i = 0 137 while i < P { 138 dw(1, " P" as *u8); dwn(1, i); dw(1, "=" as *u8); dw(1, d_pname(code[i])) 139 dw(1, "(fix=" as *u8); dw(1, d_fix(code[i])); dw(1, ")" as *u8) 140 i = i + 1 141 } 142 dw(1, " WORST=P" as *u8); dwn(1, worst); dw(1, " healthy=" as *u8); dwn(1, healthy) 143 if ok == 1 { dw(1, " verdict=GREEN\n" as *u8) } else { dw(1, " verdict=RED\n" as *u8) } 144 145 let lf: i64 = sys_openat_append(DIAG_LOG, 420) 146 if lf >= 0 { 147 dw(lf, "ROOMDIAGGATE worst=P" as *u8); dwn(lf, worst); dw(lf, " healthy=" as *u8); dwn(lf, healthy) 148 dw(lf, " codes=[" as *u8) 149 i = 0 150 while i < P { dw(lf, d_pname(code[i])); dw(lf, " " as *u8); i = i + 1 } 151 dw(lf, "]" as *u8) 152 if ok == 1 { dw(lf, " verdict=GREEN\n" as *u8) } else { dw(lf, " verdict=RED\n" as *u8) } 153 sys_close(lf) 154 } 155 if ok == 1 { sys_exit(0) } else { sys_exit(1) } 156 return 0 157}