code wiki / (root) / nx_bwe.nx

nx_bwe.nx source

↩ module page · 73 lines · 3384 B

1// nx_bwe.nx -- SOVEREIGN bandwidth estimator (the "adapt to the pipe" rung). BENCHMARK: WebRTC's GCC 2// (Google Congestion Control) = a delay-based signal (queuing delay TREND: is one-way delay rising = 3// a queue building ahead of us?) + a loss-based signal, combined into an AIMD controller (additive 4// increase when the path is clear, multiplicative decrease the instant congestion appears). Rebuilt from 5// scratch, pure integer, no third party, transport-agnostic. Output = an available-bitrate estimate that 6// feeds nx_media_budget's uplink input, so the ladder rides the REAL pipe instead of a static guess. 7// bwe_on_arrival(send_ts, arr_ts) : per-packet inter-arrival delay variation -> EWMA trend 8// bwe_report_loss(lost, total) : windowed loss -> EWMA loss rate 9// bwe_update() : one AIMD step -> new estimate (call ~1x/RTT) 10// license_tier: ORIGINAL 11 12const BW_EST: i64 = 0 13const BW_LOSS: i64 = 1 // EWMA loss, permille 14const BW_TREND: i64 = 2 // EWMA inter-arrival delay variation (rising = queue building) 15const BW_PSEND: i64 = 3 16const BW_PARR: i64 = 4 17const BW_HAVE: i64 = 5 18const BW_MIN: i64 = 6 19const BW_MAX: i64 = 7 20const BW_INC: i64 = 8 21 22const BW_TREND_THRESH: i64 = 50 // delay-variation units above which a queue is deemed building 23const BW_LOSS_HI: i64 = 100 // 10% -> congested 24const BW_LOSS_LO: i64 = 20 // 2% -> safe to probe up 25const BW_DEC_NUM: i64 = 85 // multiplicative decrease = x0.85 (fast back-off, GCC-style) 26const BW_DEC_DEN: i64 = 100 27 28func bwe_init(bw: *i64, min_kbps: i64, max_kbps: i64, start_kbps: i64, inc_kbps: i64) -> i64 { 29 bw[BW_EST] = start_kbps 30 bw[BW_LOSS] = 0 31 bw[BW_TREND] = 0 32 bw[BW_HAVE] = 0 33 bw[BW_MIN] = min_kbps 34 bw[BW_MAX] = max_kbps 35 bw[BW_INC] = inc_kbps 36 return 0 37} 38// per-packet: d = (arr - prev_arr) - (send - prev_send) = how much EXTRA delay this packet took vs the 39// last = the queuing-delay gradient. Sustained positive => a queue is growing ahead of us (overuse). 40func bwe_on_arrival(bw: *i64, send_ts: i64, arr_ts: i64) -> i64 { 41 if bw[BW_HAVE] == 1 { 42 let d: i64 = (arr_ts - bw[BW_PARR]) - (send_ts - bw[BW_PSEND]) 43 bw[BW_TREND] = bw[BW_TREND] + (d - bw[BW_TREND]) / 8 // EWMA (1/8) 44 } 45 bw[BW_PSEND] = send_ts 46 bw[BW_PARR] = arr_ts 47 bw[BW_HAVE] = 1 48 return 0 49} 50func bwe_report_loss(bw: *i64, lost: i64, total: i64) -> i64 { 51 var lp: i64 = 0 52 if total > 0 { lp = lost * 1000 / total } 53 bw[BW_LOSS] = bw[BW_LOSS] + (lp - bw[BW_LOSS]) / 4 54 return 0 55} 56// one AIMD step. Congestion = (delay trend over threshold) OR (loss over 10%). React fast down, probe slow up. 57func bwe_update(bw: *i64) -> i64 { 58 var congested: i64 = 0 59 if bw[BW_TREND] > BW_TREND_THRESH { congested = 1 } 60 if bw[BW_LOSS] > BW_LOSS_HI { congested = 1 } 61 if congested == 1 { 62 bw[BW_EST] = bw[BW_EST] * BW_DEC_NUM / BW_DEC_DEN 63 bw[BW_TREND] = 0 // reacted; re-measure the gradient 64 } else { 65 if bw[BW_LOSS] < BW_LOSS_LO { bw[BW_EST] = bw[BW_EST] + bw[BW_INC] } // clear path -> probe up 66 } 67 if bw[BW_EST] < bw[BW_MIN] { bw[BW_EST] = bw[BW_MIN] } 68 if bw[BW_EST] > bw[BW_MAX] { bw[BW_EST] = bw[BW_MAX] } 69 return bw[BW_EST] 70} 71func bwe_estimate(bw: *i64) -> i64 { return bw[BW_EST] } 72 73func main() -> i64 { return 0 }