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}