nx_rate_ema_test.nx source
↩ module page · 50 lines · 2634 B
1// nx_rate_ema_test.nx -- KAT for rolling rate EMA + its integration with the choker.
2// Native sovereign lane; exit 0 = pass, N = assertion N failed. Expecteds hand-computed.
3
4import "nx_str.nx"
5import "nx_rate_ema.nx"
6import "nx_choker.nx"
7
8func main() -> i64 {
9 // ---- rate sample ----
10 if nx_re_rate_sample(16384, 1000) != 16384 { return 1 } // 16 KiB in 1s = 16384 B/s
11 if nx_re_rate_sample(8000, 500) != 16000 { return 2 } // 8000 B in 0.5s = 16000 B/s
12 if nx_re_rate_sample(100, 0) != 0 { return 3 } // no interval -> 0
13
14 // ---- EMA step ----
15 if nx_re_ema_update(0, 1000, 500, 1000) != 500 { return 4 } // 0.5*1000 + 0.5*0
16 if nx_re_ema_update(500, 1000, 500, 1000) != 750 { return 5 } // 0.5*1000 + 0.5*500
17 if nx_re_ema_update(123, 999, 1000, 1000) != 999 { return 6 } // alpha=1 -> all sample
18 if nx_re_ema_update(777, 999, 0, 1000) != 777 { return 7 } // alpha=0 -> hold old
19 if nx_re_ema_update(50, 888, 2000, 1000) != 888 { return 8 } // alpha clamps to scale
20 if nx_re_ema_update(5, 42, 500, 0) != 42 { return 9 } // scale<=0 -> raw sample
21
22 // ---- vector update over peers ----
23 let rates: *i64 = sys_mmap(8 * 8) as *i64
24 let dbs: *i64 = sys_mmap(8 * 8) as *i64
25 rates[0]=0; rates[1]=0; rates[2]=0
26 dbs[0]=1000; dbs[1]=2000; dbs[2]=500 // bytes since last tick
27 // interval 1000ms, alpha 500/1000: sample = delta; ema from 0 = 0.5*delta
28 nx_re_update_all(rates, dbs, 3, 1000, 500, 1000)
29 if rates[0] != 500 { return 10 } // 0.5*1000
30 if rates[1] != 1000 { return 11 } // 0.5*2000
31 if rates[2] != 250 { return 12 } // 0.5*500
32 // second tick: peer1 keeps feeding, peer0 stalls -> EMA tracks the shift
33 dbs[0]=0; dbs[1]=2000; dbs[2]=500
34 nx_re_update_all(rates, dbs, 3, 1000, 500, 1000)
35 if rates[0] != 250 { return 13 } // 0.5*0 + 0.5*500
36 if rates[1] != 1500 { return 14 } // 0.5*2000 + 0.5*1000
37 if rates[2] != 375 { return 15 } // 0.5*500 + 0.5*250
38
39 // ---- INTEGRATION: the smoothed rates feed the choker, fastest peer wins the slot ----
40 // peer1 has the highest EMA (1500) -> with k=1 it must be the unchoked one.
41 let intr: *i64 = sys_mmap(8 * 8) as *i64
42 let out: *i64 = sys_mmap(8 * 8) as *i64
43 intr[0]=1; intr[1]=1; intr[2]=1
44 if nx_ch_select_top_k(rates, intr, 3, 1, out) != 1 { return 16 }
45 if out[1] != 1 { return 17 } // peer1 = fastest feeder -> reciprocated
46 if out[0] != 0 { return 18 }
47 if out[2] != 0 { return 19 }
48
49 return 0
50}