1use crate::{Duration, Instant};
4
5use tracing::warn;
6
7#[derive(Debug)]
16pub(super) struct Pacer {
17 capacity: u64,
18 last_window: u64,
19 last_mtu: u16,
20 tokens: u64,
21 max_bytes_per_second: Option<u64>,
22 prev: Instant,
23}
24
25impl Pacer {
26 pub(super) fn new(
28 smoothed_rtt: Duration,
29 window: u64,
30 mtu: u16,
31 max_bytes_per_second: Option<u64>,
32 now: Instant,
33 ) -> Self {
34 let window = rate_limited_window(smoothed_rtt, window, max_bytes_per_second);
35 let capacity = optimal_capacity(smoothed_rtt, window, mtu);
36 Self {
37 capacity,
38 last_window: window,
39 last_mtu: mtu,
40 tokens: capacity,
41 max_bytes_per_second,
42 prev: now,
43 }
44 }
45
46 pub(crate) fn max_bytes_per_second(&self) -> Option<u64> {
48 self.max_bytes_per_second
49 }
50
51 pub(super) fn on_transmit(&mut self, packet_length: u16) {
53 self.tokens = self.tokens.saturating_sub(packet_length.into())
54 }
55
56 pub(super) fn delay(
70 &mut self,
71 smoothed_rtt: Duration,
72 bytes_to_send: u64,
73 mtu: u16,
74 window: u64,
75 now: Instant,
76 capacity: Option<u64>,
77 pacing_rate: Option<u64>,
78 ) -> Option<Duration> {
79 debug_assert_ne!(
80 window, 0,
81 "zero-sized congestion control window is nonsense"
82 );
83
84 let window = rate_limited_window(smoothed_rtt, window, self.max_bytes_per_second);
85 if window != self.last_window || mtu != self.last_mtu {
86 self.capacity = optimal_capacity(smoothed_rtt, window, mtu);
87
88 self.tokens = self.capacity.min(self.tokens);
90 self.last_window = window;
91 self.last_mtu = mtu;
92 }
93
94 if let Some(capacity) = capacity {
95 self.capacity = capacity;
96 self.tokens = self.capacity.min(self.tokens);
97 }
98
99 if let Some(pacing_rate) = pacing_rate
100 && bytes_to_send > self.capacity
101 {
102 let capped_bytes_to_send = bytes_to_send.max(self.capacity);
105 let delay = Duration::from_secs_f64(capped_bytes_to_send as f64 / pacing_rate as f64);
106 return Some(delay);
107 }
108
109 if self.tokens >= bytes_to_send {
111 return None;
112 }
113
114 if window > u64::from(u32::MAX) {
116 return None;
117 }
118
119 let window = window as u32;
120
121 let time_elapsed = now.checked_duration_since(self.prev).unwrap_or_else(|| {
122 warn!("received a timestamp early than a previous recorded time, ignoring");
123 Default::default()
124 });
125
126 if smoothed_rtt.as_nanos() == 0 {
127 return None;
128 }
129
130 let elapsed_rtts = time_elapsed.as_secs_f64() / smoothed_rtt.as_secs_f64();
131 let new_tokens = (window as f64 * 1.25 * elapsed_rtts).round() as u64;
132 self.tokens = self.tokens.saturating_add(new_tokens).min(self.capacity);
133
134 if new_tokens > 0 {
137 self.prev = now;
138 }
139
140 if self.tokens >= bytes_to_send {
142 return None;
143 }
144
145 let unscaled_delay = smoothed_rtt
146 .checked_mul((bytes_to_send.max(self.capacity) - self.tokens) as _)
147 .unwrap_or(Duration::MAX)
148 / window;
149
150 Some((unscaled_delay / 5) * 4)
153 }
154}
155
156fn optimal_capacity(smoothed_rtt: Duration, window: u64, mtu: u16) -> u64 {
170 let rtt = smoothed_rtt.as_nanos().max(1);
171 let mtu = u64::from(mtu);
172
173 let target_capacity = ((window as u128 * TARGET_BURST_INTERVAL.as_nanos()) / rtt) as u64;
174 let max_capacity = Ord::max(
176 ((window as u128 * MAX_BURST_INTERVAL.as_nanos()) / rtt) as u64,
177 mtu,
178 );
179
180 Ord::min(
184 max_capacity,
185 target_capacity.clamp(MIN_BURST_SIZE * mtu, MAX_BURST_SIZE * mtu),
186 )
187}
188
189fn rate_limited_window(
193 smoothed_rtt: Duration,
194 window: u64,
195 max_bytes_per_second: Option<u64>,
196) -> u64 {
197 let Some(max_bytes_per_second) = max_bytes_per_second else {
198 return window;
199 };
200
201 let rate_window = max_bytes_per_second as f64 * smoothed_rtt.as_secs_f64();
202
203 let adjusted_rate_window = (rate_window / 1.25).round();
206
207 Ord::min(window, Ord::max(adjusted_rate_window as u64, 1))
208}
209
210const TARGET_BURST_INTERVAL: Duration = Duration::from_millis(2);
212
213const MAX_BURST_INTERVAL: Duration = Duration::from_millis(10);
217
218const MIN_BURST_SIZE: u64 = 10;
221
222const MAX_BURST_SIZE: u64 = 256;
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn does_not_panic_on_bad_instant() {
231 let old_instant = Instant::now();
232 let new_instant = old_instant + Duration::from_micros(15);
233 let rtt = Duration::from_micros(400);
234
235 assert!(
236 Pacer::new(rtt, 30000, 1500, None, new_instant)
237 .delay(
238 Duration::from_micros(0),
239 0,
240 1500,
241 1,
242 old_instant,
243 None,
244 None
245 )
246 .is_none()
247 );
248 assert!(
249 Pacer::new(rtt, 30000, 1500, None, new_instant)
250 .delay(
251 Duration::from_micros(0),
252 1600,
253 1500,
254 1,
255 old_instant,
256 None,
257 None
258 )
259 .is_none()
260 );
261 assert!(
262 Pacer::new(rtt, 30000, 1500, None, new_instant)
263 .delay(
264 Duration::from_micros(0),
265 1500,
266 1500,
267 3000,
268 old_instant,
269 None,
270 None
271 )
272 .is_none()
273 );
274 }
275
276 #[test]
277 fn derives_initial_capacity() {
278 let window = 2_000_000;
279 let mtu = 1500;
280 let rtt = Duration::from_millis(50);
281 let now = Instant::now();
282
283 let pacer = Pacer::new(rtt, window, mtu, None, now);
284 assert_eq!(
285 pacer.capacity,
286 (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
287 );
288 assert_eq!(pacer.tokens, pacer.capacity);
289
290 let pacer = Pacer::new(Duration::from_millis(0), window, mtu, None, now);
291 assert_eq!(pacer.capacity, MAX_BURST_SIZE * mtu as u64);
292 assert_eq!(pacer.tokens, pacer.capacity);
293
294 let pacer = Pacer::new(rtt, 1, mtu, None, now);
295 assert_eq!(pacer.capacity, mtu as u64);
296 assert_eq!(pacer.tokens, pacer.capacity);
297 }
298
299 #[test]
300 fn adjusts_capacity() {
301 let window = 2_000_000;
302 let mtu = 1500;
303 let rtt = Duration::from_millis(50);
304 let now = Instant::now();
305
306 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
307 assert_eq!(
308 pacer.capacity,
309 (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
310 );
311 assert_eq!(pacer.tokens, pacer.capacity);
312 let initial_tokens = pacer.tokens;
313
314 pacer.delay(rtt, mtu as u64, mtu, window * 2, now, None, None);
315 assert_eq!(
316 pacer.capacity,
317 (2 * window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
318 );
319 assert_eq!(pacer.tokens, initial_tokens);
320
321 pacer.delay(rtt, mtu as u64, mtu, window / 2, now, None, None);
322 assert_eq!(
323 pacer.capacity,
324 (window as u128 / 2 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
325 );
326 assert_eq!(pacer.tokens, initial_tokens / 2);
327
328 pacer.delay(rtt, mtu as u64, mtu * 2, window, now, None, None);
329 assert_eq!(
330 pacer.capacity,
331 (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
332 );
333
334 pacer.delay(rtt, mtu as u64, 20_000, window, now, None, None);
335 assert_eq!(pacer.capacity, 20_000_u64 * MIN_BURST_SIZE);
336 }
337
338 #[test]
339 fn computes_pause_correctly() {
340 let window = 2_000_000u64;
341 let mtu = 1000;
342 let rtt = Duration::from_millis(50);
343 let old_instant = Instant::now();
344
345 let mut pacer = Pacer::new(rtt, window, mtu, None, old_instant);
346 let packet_capacity = pacer.capacity / mtu as u64;
347
348 for _ in 0..packet_capacity {
349 assert_eq!(
350 pacer.delay(rtt, mtu as u64, mtu, window, old_instant, None, None),
351 None,
352 "When capacity is available packets should be sent immediately"
353 );
354
355 pacer.on_transmit(mtu);
356 }
357
358 let pace_duration = Duration::from_nanos((TARGET_BURST_INTERVAL.as_nanos() * 4 / 5) as u64);
359
360 let actual_delay = pacer
361 .delay(rtt, mtu as u64, mtu, window, old_instant, None, None)
362 .expect("Send must be delayed");
363
364 let diff = actual_delay.abs_diff(pace_duration);
365
366 assert!(
368 diff < Duration::from_nanos(2),
369 "expected ≈ {pace_duration:?}, got {actual_delay:?} (diff {diff:?})"
370 );
371 assert_eq!(
373 pacer.delay(
374 rtt,
375 mtu as u64,
376 mtu,
377 window,
378 old_instant + pace_duration / 2,
379 None,
380 None,
381 ),
382 None
383 );
384 assert_eq!(pacer.tokens, pacer.capacity / 2);
385
386 for _ in 0..packet_capacity / 2 {
387 assert_eq!(
388 pacer.delay(rtt, mtu as u64, mtu, window, old_instant, None, None),
389 None,
390 "When capacity is available packets should be sent immediately"
391 );
392
393 pacer.on_transmit(mtu);
394 }
395
396 assert_eq!(
398 pacer.delay(
399 rtt,
400 mtu as u64,
401 mtu,
402 window,
403 old_instant + pace_duration * 3 / 2,
404 None,
405 None,
406 ),
407 None
408 );
409 assert_eq!(pacer.tokens, pacer.capacity);
410 }
411
412 #[test]
413 fn computes_pause_correctly_for_rate_limited() {
414 let window = 2_000_000u64;
415 let mtu = 1000;
416 let rtt = Duration::from_millis(50);
417 let old_instant = Instant::now();
418
419 let mut pacer = Pacer::new(rtt, window, mtu, Some(2_000), old_instant);
420 assert_eq!(
421 pacer.delay(rtt, 1_000, mtu, window, old_instant, None, None),
422 None,
423 "When capacity is available packets should be sent immediately"
424 );
425 pacer.on_transmit(mtu);
426
427 let actual_delay = pacer
428 .delay(rtt, 1_000, mtu, window, old_instant, None, None)
429 .expect("Send must be delayed");
430
431 let expected_delay = Duration::from_millis(500);
432 let diff = actual_delay.abs_diff(expected_delay);
433
434 assert!(
436 diff < Duration::from_nanos(2),
437 "expected ≈ {expected_delay:?}, got {actual_delay:?} (diff {diff:?})"
438 );
439
440 let now = old_instant + expected_delay / 2;
442 assert_eq!(pacer.delay(rtt, 500, mtu, window, now, None, None), None);
443 }
444}