quiche/recovery/congestion/
pacer.rs1use std::time::Duration;
42use std::time::Instant;
43
44#[derive(Debug)]
45pub struct Pacer {
46 enabled: bool,
48
49 capacity: usize,
51
52 used: usize,
54
55 rate: u64,
57
58 last_update: Instant,
60
61 next_time: Instant,
63
64 max_datagram_size: usize,
66
67 last_packet_size: Option<usize>,
69
70 iv: Duration,
72
73 max_pacing_rate: Option<u64>,
75}
76
77impl Pacer {
78 pub fn new(
79 enabled: bool, capacity: usize, rate: u64, max_datagram_size: usize,
80 max_pacing_rate: Option<u64>,
81 ) -> Self {
82 let capacity = capacity / max_datagram_size * max_datagram_size;
84 let pacing_rate = if let Some(max_rate) = max_pacing_rate {
85 max_rate.min(rate)
86 } else {
87 rate
88 };
89
90 Pacer {
91 enabled,
92
93 capacity,
94
95 used: 0,
96
97 rate: pacing_rate,
98
99 last_update: Instant::now(),
100
101 next_time: Instant::now(),
102
103 max_datagram_size,
104
105 last_packet_size: None,
106
107 iv: Duration::ZERO,
108
109 max_pacing_rate,
110 }
111 }
112
113 pub fn enabled(&self) -> bool {
115 self.enabled
116 }
117
118 pub fn rate(&self) -> u64 {
120 self.rate
121 }
122
123 pub fn max_pacing_rate(&self) -> Option<u64> {
125 self.max_pacing_rate
126 }
127
128 pub fn update(&mut self, capacity: usize, rate: u64, now: Instant) {
130 let capacity = capacity / self.max_datagram_size * self.max_datagram_size;
131
132 if self.capacity != capacity {
133 self.reset(now);
134 }
135
136 self.capacity = capacity;
137
138 self.rate = if let Some(max_rate) = self.max_pacing_rate {
139 max_rate.min(rate)
140 } else {
141 rate
142 };
143 }
144
145 fn reset(&mut self, now: Instant) {
147 self.used = 0;
148
149 self.last_update = now;
150
151 self.next_time = self.next_time.max(now);
152
153 self.last_packet_size = None;
154
155 self.iv = Duration::ZERO;
156 }
157
158 pub fn send(&mut self, packet_size: usize, now: Instant) {
160 if self.rate() == 0 {
161 self.reset(now);
162
163 return;
164 }
165
166 if !self.iv.is_zero() {
167 self.next_time = self.next_time.max(now) + self.iv;
168
169 self.iv = Duration::ZERO;
170 }
171
172 let interval =
173 Duration::from_secs_f64(self.capacity as f64 / self.rate() as f64);
174
175 let elapsed = now.saturating_duration_since(self.last_update);
176
177 if elapsed > interval {
179 self.reset(now);
180 }
181
182 self.used += packet_size;
183
184 let same_size = if let Some(last_packet_size) = self.last_packet_size {
185 last_packet_size == packet_size
186 } else {
187 true
188 };
189
190 self.last_packet_size = Some(packet_size);
191
192 if self.used >= self.capacity || !same_size {
193 self.iv =
194 Duration::from_secs_f64(self.used as f64 / self.rate() as f64);
195
196 self.used = 0;
197
198 self.last_update = now;
199
200 self.last_packet_size = None;
201 };
202 }
203
204 pub fn next_time(&self) -> Instant {
206 self.next_time
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
215 fn pacer_update() {
216 let datagram_size = 1200;
217 let max_burst = datagram_size * 10;
218 let pacing_rate = 100_000;
219
220 let mut p = Pacer::new(true, max_burst, pacing_rate, datagram_size, None);
221
222 let now = Instant::now();
223
224 p.send(6000, now);
226
227 assert!(now.duration_since(p.next_time()) < Duration::from_millis(1));
228
229 p.send(6000, now);
231
232 assert!(now.duration_since(p.next_time()) < Duration::from_millis(1));
233
234 let now = now + Duration::from_millis(5);
236
237 p.send(1000, now);
239
240 let interval = max_burst as f64 / pacing_rate as f64;
241
242 assert_eq!(p.next_time() - now, Duration::from_secs_f64(interval));
243 }
244
245 #[test]
246 fn pacer_idle() {
249 let datagram_size = 1200;
250 let max_burst = datagram_size * 10;
251 let pacing_rate = 100_000;
252
253 let mut p = Pacer::new(true, max_burst, pacing_rate, datagram_size, None);
254
255 let now = Instant::now();
256
257 p.send(6000, now);
259
260 assert!(now.duration_since(p.next_time()) < Duration::from_millis(1));
261
262 let now = now + Duration::from_millis(200);
264
265 p.send(6000, now);
267
268 assert_eq!(p.next_time(), now);
269 }
270
271 #[test]
272 fn pacer_set_max_pacing_rate() {
273 let datagram_size = 1200;
274 let max_burst = datagram_size * 10;
275 let pacing_rate = 100_000;
276 let max_pacing_rate = 50_000;
277
278 let mut p = Pacer::new(
280 true,
281 max_burst,
282 pacing_rate,
283 datagram_size,
284 Some(max_pacing_rate),
285 );
286
287 let now = Instant::now();
288
289 p.send(6000, now);
291
292 assert!(now.duration_since(p.next_time()) < Duration::from_millis(1));
293
294 p.send(6000, now);
296
297 assert!(now.duration_since(p.next_time()) < Duration::from_millis(1));
298
299 let now = now + Duration::from_millis(5);
301 p.send(12000, now);
302
303 let second_burst_send_time = p.next_time();
304
305 let interval = max_burst as f64 / max_pacing_rate as f64;
306
307 assert_eq!(
308 second_burst_send_time - now,
309 Duration::from_secs_f64(interval)
310 );
311
312 let now = now + Duration::from_millis(5);
314
315 p.update(max_burst, 75_000, now);
317
318 p.send(12000, now);
319
320 let third_burst_send_time = p.next_time();
321
322 assert_eq!(
323 third_burst_send_time - second_burst_send_time,
324 Duration::from_secs_f64(interval)
325 );
326 }
327}