cyfs_bdt/cc/
ledbat.rs

1use std::{
2    time::{Duration}, 
3    collections::LinkedList, 
4};
5use cyfs_base::*;
6use crate::types::*;
7use super::cc_impl::CcImpl;
8
9#[derive(Clone)]
10pub struct Config {
11    pub target_delay: Duration, 
12    pub min_cwnd: u64, 
13    pub max_cwnd_inc: u64, 
14    pub cwnd_gain: u64, 
15    pub history_count: u64, 
16    pub history_roll_interval: Duration
17}
18
19impl Default for Config {
20    fn default() -> Self {
21        Self {
22            target_delay: Duration::from_millis(100),
23            min_cwnd: 2,
24            max_cwnd_inc: 8,
25            cwnd_gain: 1,
26            history_count: 10,
27            history_roll_interval: Duration::from_secs(60),
28        }
29    }
30}
31
32struct EstimateDelay {
33    last_roll: Timestamp, 
34    base_delay: LinkedList<i64>, 
35    current_delay: LinkedList<i64>
36}
37
38impl EstimateDelay {
39    fn new(config: &Config) -> Self {
40        let mut base_delay = LinkedList::new();
41        for _ in 0..config.history_count {
42            base_delay.push_back(i64::MAX);
43        }
44        let mut current_delay = LinkedList::new();
45        for _ in 0..config.history_count {
46            current_delay.push_back(i64::MAX);
47        }
48
49        Self {
50            last_roll: bucky_time_now() - config.history_roll_interval.as_micros() as u64, 
51            base_delay, 
52            current_delay, 
53        }
54    }
55
56    fn current_delay(&self) -> i64 {
57        let mut delay = i64::MAX;
58        for d in &self.current_delay {
59            delay = std::cmp::min(*d, delay);
60        }
61        delay
62    }
63
64    fn base_delay(&self) -> i64 {
65        let mut delay = i64::MAX;
66            for d in &self.base_delay {
67                delay = std::cmp::min(*d, delay);
68            }
69            delay
70    }
71
72    fn update(&mut self, delay: i64) {
73        let tail = self.base_delay.back_mut().unwrap();
74        *tail = std::cmp::min(*tail, delay);  
75
76        self.current_delay.pop_front();
77        self.current_delay.push_back(delay);
78    }
79
80    fn check_roll(&mut self, config: &Config, now: Timestamp) {
81        if now > self.last_roll && Duration::from_micros(now - self.last_roll) > config.history_roll_interval {
82            self.last_roll = now;
83            self.base_delay.pop_front();
84            self.base_delay.push_back(i64::MAX);
85
86            let base_delay = {
87                let mut delay = i64::MAX;
88                for d in &self.base_delay {
89                    delay = std::cmp::min(*d, delay);
90                }
91                delay
92            };
93            if base_delay == i64::MAX {
94                for d in &mut self.current_delay {
95                    *d = i64::MAX;
96                }
97            }
98        }
99    }
100}
101
102
103pub(super) struct Ledbat {
104    mss: usize, 
105    est_delay: EstimateDelay,
106    config: Config, 
107    cwnd: u64
108}
109
110impl Ledbat {
111    pub fn new(mss: usize, config: &Config) -> Self {
112        let mut config = config.clone();
113        config.min_cwnd = config.min_cwnd * mss as u64;
114        config.cwnd_gain = config.cwnd_gain * mss as u64;
115        config.max_cwnd_inc = config.max_cwnd_inc * mss as u64;
116        Self {
117            cwnd: config.min_cwnd, 
118            mss, 
119            est_delay: EstimateDelay::new(&config), 
120            config
121        }
122    }
123}
124
125
126impl CcImpl for Ledbat {
127    fn on_sent(&mut self, _: Timestamp, _: u64, _: u64) {
128    }
129
130    fn cwnd(&self) -> u64 {
131        self.cwnd
132    }
133
134    fn on_estimate(&mut self, _rtt: Duration, _rto: Duration, delay: Duration, _app_limited: bool) {
135        self.est_delay.update(delay.as_micros() as i64);
136    }
137
138    fn on_ack(
139        &mut self, 
140        _flight: u64, 
141        ack: u64, 
142        _largest_packet_num_acked: Option<u64>, 
143        _sent_time: Timestamp,
144        _app_limited: bool
145    ) {
146        let cwnd = self.cwnd();
147        let cur_delay = self.est_delay.current_delay();
148        let base_delay = self.est_delay.base_delay();
149        let queuing_delay = cur_delay - base_delay;
150        let delay_factor = (self.config.target_delay.as_micros() as i64 - queuing_delay) as f64 / self.config.target_delay.as_micros() as f64;
151        let cwnd_factor = std::cmp::min(ack, cwnd) as f64 / std::cmp::max(ack, cwnd) as f64;
152        let scaled_gain = (self.config.max_cwnd_inc as f64 * cwnd_factor * delay_factor) as i64;
153        let new_cwnd = (cwnd as i64 + scaled_gain) as u64;
154        // trace!("ledbat cur_delay:{} base_delay:{} queuing_delay:{} delay_factor:{} cwnd_factor:{} scaled_gain:{}", cur_delay, base_delay, queuing_delay, delay_factor, cwnd_factor, scaled_gain);
155        // let allowed_max = (flight + newly_acked + config.wnd_gain as u64 * self.mss as u64) as i64;
156        // new_wnd = std::cmp::min(new_wnd, allowed_max);
157        self.cwnd = new_cwnd.max(self.config.min_cwnd);
158    }
159
160    
161    fn on_loss(&mut self, _lost: u64) {
162        self.cwnd = (self.cwnd / 2).max(self.config.min_cwnd)
163    }
164
165    fn on_no_resp(&mut self, rto: Duration, _lost: u64) -> Duration {
166        self.cwnd = self.config.min_cwnd;
167        rto * 2
168    }
169
170    fn on_time_escape(&mut self, now: Timestamp) {
171        self.est_delay.check_roll(&self.config, now);   
172    }
173
174    fn rate(&self) -> u64 {
175        0
176    }
177}
178