1use crate::congestion::ControllerMetrics;
4use crate::{Duration, Instant};
5
6use tracing::warn;
7
8#[derive(Debug)]
17pub(super) struct Pacer {
18 capacity: u64,
19 last_window_inputs: Option<WindowInputs>,
21 tokens: u64,
22 max_bytes_per_second: Option<u64>,
23 prev: Instant,
24}
25
26#[derive(Copy, Clone, Eq, PartialEq, Debug)]
28struct WindowInputs {
29 window: u64,
31 mtu: u16,
33}
34
35impl Pacer {
36 pub(super) fn new(
38 smoothed_rtt: Duration,
39 window: u64,
40 mtu: u16,
41 max_bytes_per_second: Option<u64>,
42 now: Instant,
43 ) -> Self {
44 let window = rate_limited_window(smoothed_rtt, window, max_bytes_per_second);
45 let capacity = optimal_capacity(smoothed_rtt, window, mtu);
46 Self {
47 capacity,
48 last_window_inputs: Some(WindowInputs { window, mtu }),
49 tokens: capacity,
50 max_bytes_per_second,
51 prev: now,
52 }
53 }
54
55 pub(crate) fn max_bytes_per_second(&self) -> Option<u64> {
57 self.max_bytes_per_second
58 }
59
60 pub(super) fn on_transmit(&mut self, packet_length: u16) {
62 self.tokens = self.tokens.saturating_sub(packet_length.into())
63 }
64
65 pub(super) fn delay(
82 &mut self,
83 smoothed_rtt: Duration,
84 bytes_to_send: u64,
85 mtu: u16,
86 now: Instant,
87 controller_metrics: &ControllerMetrics,
88 ) -> Option<Duration> {
89 let window = controller_metrics.congestion_window;
90 debug_assert_ne!(
91 window, 0,
92 "zero-sized congestion control window is nonsense"
93 );
94
95 if let Some(pacing_rate) = controller_metrics.pacing_rate {
98 return self.delay_at_rate(pacing_rate, bytes_to_send, mtu, now);
99 }
100
101 let window = rate_limited_window(smoothed_rtt, window, self.max_bytes_per_second);
102 let inputs = WindowInputs { window, mtu };
103 if self.last_window_inputs != Some(inputs) {
104 self.capacity = optimal_capacity(smoothed_rtt, window, mtu);
105
106 self.tokens = self.capacity.min(self.tokens);
108 self.last_window_inputs = Some(inputs);
109 }
110
111 if self.tokens >= bytes_to_send {
113 return None;
114 }
115
116 if window > u64::from(u32::MAX) {
118 return None;
119 }
120
121 let window = window as u32;
122
123 let time_elapsed = now.checked_duration_since(self.prev).unwrap_or_else(|| {
124 warn!("received a timestamp early than a previous recorded time, ignoring");
125 Default::default()
126 });
127
128 if smoothed_rtt.as_nanos() == 0 {
129 return None;
130 }
131
132 let elapsed_rtts = time_elapsed.as_secs_f64() / smoothed_rtt.as_secs_f64();
133 let new_tokens = (window as f64 * 1.25 * elapsed_rtts).round() as u64;
134 self.tokens = self.tokens.saturating_add(new_tokens).min(self.capacity);
135
136 if new_tokens > 0 {
139 self.prev = now;
140 }
141
142 if self.tokens >= bytes_to_send {
144 return None;
145 }
146
147 let unscaled_delay = smoothed_rtt
148 .checked_mul((bytes_to_send.max(self.capacity) - self.tokens) as _)
149 .unwrap_or(Duration::MAX)
150 / window;
151
152 Some((unscaled_delay / 5) * 4)
155 }
156
157 fn delay_at_rate(
164 &mut self,
165 pacing_rate: u64,
166 bytes_to_send: u64,
167 mtu: u16,
168 now: Instant,
169 ) -> Option<Duration> {
170 let rate = match self.max_bytes_per_second {
174 Some(max_bytes_per_second) => Ord::min(pacing_rate, max_bytes_per_second),
175 None => pacing_rate,
176 }
177 .max(1);
178
179 let capacity = rate_capacity(rate, mtu);
180 if capacity != self.capacity {
181 self.capacity = capacity;
182 self.tokens = self.capacity.min(self.tokens);
184 }
185 self.last_window_inputs = None;
187
188 let time_elapsed = now.checked_duration_since(self.prev).unwrap_or_else(|| {
189 warn!("received a timestamp early than a previous recorded time, ignoring");
190 Default::default()
191 });
192 let new_tokens = (rate as f64 * time_elapsed.as_secs_f64()) as u64;
193
194 if new_tokens > 0 {
198 self.tokens = self.tokens.saturating_add(new_tokens).min(self.capacity);
199 self.prev = now;
200 }
201
202 let target = Ord::min(bytes_to_send, self.capacity);
205 if self.tokens >= target {
206 return None;
207 }
208
209 let deficit = target - self.tokens;
212 Some(Duration::from_secs_f64(deficit as f64 / rate as f64))
213 }
214}
215
216fn rate_capacity(pacing_rate: u64, mtu: u16) -> u64 {
222 let mtu = u64::from(mtu);
223 let bytes_in =
224 |interval: Duration| ((pacing_rate as u128 * interval.as_nanos()) / 1_000_000_000) as u64;
225
226 let target_capacity = bytes_in(TARGET_BURST_INTERVAL);
227 let max_capacity = Ord::max(bytes_in(MAX_BURST_INTERVAL), mtu);
229
230 Ord::min(
233 max_capacity,
234 target_capacity.clamp(MIN_BURST_SIZE * mtu, MAX_BURST_SIZE * mtu),
235 )
236}
237
238fn optimal_capacity(smoothed_rtt: Duration, window: u64, mtu: u16) -> u64 {
240 let rtt = smoothed_rtt.as_nanos().max(1);
241 let rate = u64::try_from(window as u128 * 1_000_000_000 / rtt).unwrap_or(u64::MAX);
242 rate_capacity(rate, mtu)
243}
244
245fn rate_limited_window(
249 smoothed_rtt: Duration,
250 window: u64,
251 max_bytes_per_second: Option<u64>,
252) -> u64 {
253 let Some(max_bytes_per_second) = max_bytes_per_second else {
254 return window;
255 };
256
257 let rate_window = max_bytes_per_second as f64 * smoothed_rtt.as_secs_f64();
258
259 let adjusted_rate_window = (rate_window / 1.25).round();
262
263 Ord::min(window, Ord::max(adjusted_rate_window as u64, 1))
264}
265
266const TARGET_BURST_INTERVAL: Duration = Duration::from_millis(2);
268
269const MAX_BURST_INTERVAL: Duration = Duration::from_millis(10);
273
274const MIN_BURST_SIZE: u64 = 10;
277
278const MAX_BURST_SIZE: u64 = 256;
280
281#[cfg(test)]
282mod tests {
283 use super::*;
284
285 const TEST_PACING_RATE: u64 = 12_500_000;
287
288 fn unpaced_metrics(congestion_window: u64) -> ControllerMetrics {
291 ControllerMetrics {
292 congestion_window,
293 ..Default::default()
294 }
295 }
296
297 fn paced_metrics(
300 congestion_window: u64,
301 pacing_rate: u64,
302 send_quantum: u64,
303 ) -> ControllerMetrics {
304 ControllerMetrics {
305 congestion_window,
306 pacing_rate: Some(pacing_rate),
307 send_quantum: Some(send_quantum),
308 ..Default::default()
309 }
310 }
311
312 fn burst_until_blocked(
318 pacer: &mut Pacer,
319 rtt: Duration,
320 mtu: u16,
321 now: Instant,
322 metrics: &ControllerMetrics,
323 ) -> Option<(Duration, u64)> {
324 let mut sent = 0;
325 for _ in 0..10_000 {
326 match pacer.delay(rtt, u64::from(mtu), mtu, now, metrics) {
327 Some(resume_after) => return Some((resume_after, sent)),
328 None => {
329 pacer.on_transmit(mtu);
330 sent += u64::from(mtu);
331 }
332 }
333 }
334 None
335 }
336
337 fn bytes_sent_over(
341 pacer: &mut Pacer,
342 rtt: Duration,
343 mtu: u16,
344 start: Instant,
345 duration: Duration,
346 metrics: &ControllerMetrics,
347 ) -> u64 {
348 const MAX_POLLS: u64 = 1_000_000;
351
352 let deadline = start + duration;
353 let mut at = start;
354 let mut sent = 0;
355 let mut polls = 0;
356 while at < deadline {
357 polls += 1;
358 assert!(
359 polls < MAX_POLLS,
360 "pacer made no progress: {sent} bytes emitted without reaching the deadline"
361 );
362 match pacer.delay(rtt, u64::from(mtu), mtu, at, metrics) {
363 None => {
364 pacer.on_transmit(mtu);
365 sent += u64::from(mtu);
366 }
367 Some(resume) => at += resume,
368 }
369 }
370 sent
371 }
372
373 #[test]
374 fn blocks_greedy_sender_at_controller_pacing_rate() {
375 let mtu = 1500;
376 let rtt = Duration::from_millis(50);
377 let window = 2_000_000;
378 let now = Instant::now();
379 let metrics = paced_metrics(window, TEST_PACING_RATE, 2 * u64::from(mtu));
381 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
382
383 assert!(
386 burst_until_blocked(&mut pacer, rtt, mtu, now, &metrics).is_some(),
387 "pacer never blocked while polled at a single instant, so the controller's \
388 pacing rate is not being enforced"
389 );
390 }
391
392 #[test]
393 fn pacing_delay_unblocks_once_it_expires() {
394 let mtu = 1500;
395 let rtt = Duration::from_millis(50);
396 let window = 2_000_000;
397 let now = Instant::now();
398 let metrics = paced_metrics(window, TEST_PACING_RATE, 2 * u64::from(mtu));
399 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
400
401 let (resume_after, _) = burst_until_blocked(&mut pacer, rtt, mtu, now, &metrics)
402 .expect("pacer must block once the burst budget is spent");
403
404 assert_eq!(
407 pacer.delay(rtt, u64::from(mtu), mtu, now + resume_after, &metrics),
408 None,
409 "the delay the pacer asked for must be long enough to unblock the send"
410 );
411 }
412
413 #[test]
414 fn aggregate_throughput_matches_controller_pacing_rate() {
415 const SECONDS: u64 = 1;
416
417 let mtu = 1500;
418 let rtt = Duration::from_millis(50);
419 let window = 2_000_000;
420 let metrics = paced_metrics(window, TEST_PACING_RATE, 2 * u64::from(mtu));
421 let start = Instant::now();
422 let mut pacer = Pacer::new(rtt, window, mtu, None, start);
423
424 let sent = bytes_sent_over(
425 &mut pacer,
426 rtt,
427 mtu,
428 start,
429 Duration::from_secs(SECONDS),
430 &metrics,
431 );
432
433 let expected = TEST_PACING_RATE * SECONDS;
434 let slack = expected / 20;
436 assert!(
437 sent <= expected + slack,
438 "emitted {sent} bytes in {SECONDS}s, but pacing_rate allows only {expected}"
439 );
440 assert!(
441 sent + slack >= expected,
442 "emitted {sent} bytes in {SECONDS}s, underrunning pacing_rate {expected}"
443 );
444 }
445
446 #[test]
447 fn does_not_panic_on_bad_instant() {
448 let old_instant = Instant::now();
449 let new_instant = old_instant + Duration::from_micros(15);
450 let rtt = Duration::from_micros(400);
451
452 assert!(
453 Pacer::new(rtt, 30000, 1500, None, new_instant)
454 .delay(
455 Duration::from_micros(0),
456 0,
457 1500,
458 old_instant,
459 &unpaced_metrics(1),
460 )
461 .is_none()
462 );
463 assert!(
464 Pacer::new(rtt, 30000, 1500, None, new_instant)
465 .delay(
466 Duration::from_micros(0),
467 1600,
468 1500,
469 old_instant,
470 &unpaced_metrics(1),
471 )
472 .is_none()
473 );
474 assert!(
475 Pacer::new(rtt, 30000, 1500, None, new_instant)
476 .delay(
477 Duration::from_micros(0),
478 1500,
479 1500,
480 old_instant,
481 &unpaced_metrics(3000),
482 )
483 .is_none()
484 );
485 }
486
487 #[test]
488 fn derives_initial_capacity() {
489 let window = 2_000_000;
490 let mtu = 1500;
491 let rtt = Duration::from_millis(50);
492 let now = Instant::now();
493
494 let pacer = Pacer::new(rtt, window, mtu, None, now);
495 assert_eq!(
496 pacer.capacity,
497 (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
498 );
499 assert_eq!(pacer.tokens, pacer.capacity);
500
501 let pacer = Pacer::new(Duration::from_millis(0), window, mtu, None, now);
502 assert_eq!(pacer.capacity, MAX_BURST_SIZE * mtu as u64);
503 assert_eq!(pacer.tokens, pacer.capacity);
504
505 let pacer = Pacer::new(rtt, 1, mtu, None, now);
506 assert_eq!(pacer.capacity, mtu as u64);
507 assert_eq!(pacer.tokens, pacer.capacity);
508 }
509
510 #[test]
511 fn adjusts_capacity() {
512 let window = 2_000_000;
513 let mtu = 1500;
514 let rtt = Duration::from_millis(50);
515 let now = Instant::now();
516
517 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
518 assert_eq!(
519 pacer.capacity,
520 (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
521 );
522 assert_eq!(pacer.tokens, pacer.capacity);
523 let initial_tokens = pacer.tokens;
524
525 pacer.delay(rtt, mtu as u64, mtu, now, &unpaced_metrics(window * 2));
526 assert_eq!(
527 pacer.capacity,
528 (2 * window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
529 );
530 assert_eq!(pacer.tokens, initial_tokens);
531
532 pacer.delay(rtt, mtu as u64, mtu, now, &unpaced_metrics(window / 2));
533 assert_eq!(
534 pacer.capacity,
535 (window as u128 / 2 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
536 );
537 assert_eq!(pacer.tokens, initial_tokens / 2);
538
539 pacer.delay(rtt, mtu as u64, mtu * 2, now, &unpaced_metrics(window));
540 assert_eq!(
541 pacer.capacity,
542 (window as u128 * TARGET_BURST_INTERVAL.as_nanos() / rtt.as_nanos()) as u64
543 );
544
545 pacer.delay(rtt, mtu as u64, 20_000, now, &unpaced_metrics(window));
546 assert_eq!(pacer.capacity, 20_000_u64 * MIN_BURST_SIZE);
547 }
548
549 #[test]
550 fn computes_pause_correctly() {
551 let window = 2_000_000u64;
552 let mtu = 1000;
553 let rtt = Duration::from_millis(50);
554 let old_instant = Instant::now();
555
556 let mut pacer = Pacer::new(rtt, window, mtu, None, old_instant);
557 let packet_capacity = pacer.capacity / mtu as u64;
558
559 for _ in 0..packet_capacity {
560 assert_eq!(
561 pacer.delay(rtt, mtu as u64, mtu, old_instant, &unpaced_metrics(window)),
562 None,
563 "When capacity is available packets should be sent immediately"
564 );
565
566 pacer.on_transmit(mtu);
567 }
568
569 let pace_duration = Duration::from_nanos((TARGET_BURST_INTERVAL.as_nanos() * 4 / 5) as u64);
570
571 let actual_delay = pacer
572 .delay(rtt, mtu as u64, mtu, old_instant, &unpaced_metrics(window))
573 .expect("Send must be delayed");
574
575 let diff = actual_delay.abs_diff(pace_duration);
576
577 assert!(
579 diff < Duration::from_nanos(2),
580 "expected ≈ {pace_duration:?}, got {actual_delay:?} (diff {diff:?})"
581 );
582 assert_eq!(
584 pacer.delay(
585 rtt,
586 mtu as u64,
587 mtu,
588 old_instant + pace_duration / 2,
589 &unpaced_metrics(window),
590 ),
591 None
592 );
593 assert_eq!(pacer.tokens, pacer.capacity / 2);
594
595 for _ in 0..packet_capacity / 2 {
596 assert_eq!(
597 pacer.delay(rtt, mtu as u64, mtu, old_instant, &unpaced_metrics(window)),
598 None,
599 "When capacity is available packets should be sent immediately"
600 );
601
602 pacer.on_transmit(mtu);
603 }
604
605 assert_eq!(
607 pacer.delay(
608 rtt,
609 mtu as u64,
610 mtu,
611 old_instant + pace_duration * 3 / 2,
612 &unpaced_metrics(window),
613 ),
614 None
615 );
616 assert_eq!(pacer.tokens, pacer.capacity);
617 }
618
619 #[test]
620 fn computes_pause_correctly_for_rate_limited() {
621 let window = 2_000_000u64;
622 let mtu = 1000;
623 let rtt = Duration::from_millis(50);
624 let old_instant = Instant::now();
625
626 let mut pacer = Pacer::new(rtt, window, mtu, Some(2_000), old_instant);
627 assert_eq!(
628 pacer.delay(rtt, 1_000, mtu, old_instant, &unpaced_metrics(window)),
629 None,
630 "When capacity is available packets should be sent immediately"
631 );
632 pacer.on_transmit(mtu);
633
634 let actual_delay = pacer
635 .delay(rtt, 1_000, mtu, old_instant, &unpaced_metrics(window))
636 .expect("Send must be delayed");
637
638 let expected_delay = Duration::from_millis(500);
639 let diff = actual_delay.abs_diff(expected_delay);
640
641 assert!(
643 diff < Duration::from_nanos(2),
644 "expected ≈ {expected_delay:?}, got {actual_delay:?} (diff {diff:?})"
645 );
646
647 let now = old_instant + expected_delay / 2;
649 assert_eq!(
650 pacer.delay(rtt, 500, mtu, now, &unpaced_metrics(window)),
651 None
652 );
653 }
654
655 #[test]
656 fn derives_burst_budget_from_controller_pacing_rate() {
657 let window = 2_000_000;
658 let mtu = 1500;
659 let rtt = Duration::from_millis(50);
660 let now = Instant::now();
661 let metrics = paced_metrics(window * 2, TEST_PACING_RATE, 2 * u64::from(mtu));
664 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
665
666 pacer.delay(rtt, u64::from(mtu), mtu, now, &metrics);
667
668 assert_eq!(pacer.capacity, rate_capacity(TEST_PACING_RATE, mtu));
669 assert_eq!(pacer.capacity, 25_000);
671 }
672
673 #[test]
674 fn pacing_delay_covers_exactly_the_token_shortfall() {
675 const RATE: u64 = 200_000_000;
677
678 let window = 2_000_000;
679 let mtu = 1500;
680 let rtt = Duration::from_millis(50);
681 let now = Instant::now();
682 let metrics = paced_metrics(window, RATE, 2 * u64::from(mtu));
683 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
684
685 let (resume_after, _) = burst_until_blocked(&mut pacer, rtt, mtu, now, &metrics)
686 .expect("pacer must block once the burst budget is spent");
687
688 let deficit = u64::from(mtu) - pacer.tokens;
691 assert_eq!(
692 resume_after,
693 Duration::from_secs_f64(deficit as f64 / RATE as f64)
694 );
695 }
696
697 #[test]
698 fn burst_is_bounded_by_the_target_interval() {
699 let window = 2_000_000;
700 let mtu = 1500;
701 let rtt = Duration::from_millis(50);
702 let now = Instant::now();
703 let metrics = paced_metrics(window, TEST_PACING_RATE, 2 * u64::from(mtu));
704 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
705
706 let (_, burst) = burst_until_blocked(&mut pacer, rtt, mtu, now, &metrics)
707 .expect("pacer must block once the burst budget is spent");
708
709 let budget = rate_capacity(TEST_PACING_RATE, mtu);
713 assert!(
714 burst <= budget + u64::from(mtu),
715 "burst of {burst} bytes overshoots the {budget} byte budget by over one datagram"
716 );
717 assert!(
718 burst + u64::from(mtu) >= budget,
719 "burst of {burst} bytes undershoots the {budget} byte budget by over one datagram"
720 );
721 }
722
723 #[test]
724 fn shrinks_burst_budget_when_pacing_rate_drops() {
725 let window = 2_000_000;
726 let mtu = 1500;
727 let rtt = Duration::from_millis(50);
728 let now = Instant::now();
729 let quantum = 2 * u64::from(mtu);
730 let fast = paced_metrics(window, TEST_PACING_RATE, quantum);
731 let slow = paced_metrics(window, TEST_PACING_RATE / 10, quantum);
732 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
733
734 assert_eq!(pacer.delay(rtt, u64::from(mtu), mtu, now, &fast), None);
736 assert_eq!(pacer.capacity, rate_capacity(TEST_PACING_RATE, mtu));
737
738 pacer.delay(rtt, u64::from(mtu), mtu, now, &slow);
741
742 let budget = rate_capacity(TEST_PACING_RATE / 10, mtu);
743 assert_eq!(pacer.capacity, budget);
744 assert!(
745 pacer.tokens <= budget,
746 "{} tokens outlive the {budget} byte budget of the lowered rate",
747 pacer.tokens
748 );
749 }
750
751 #[test]
752 fn rate_path_does_not_leave_stale_window_capacity() {
753 let window = 2_000_000;
754 let mtu = 1500;
755 let rtt = Duration::from_millis(50);
756 let now = Instant::now();
757 let mut pacer = Pacer::new(rtt, window, mtu, None, now);
758
759 pacer.delay(
762 rtt,
763 u64::from(mtu),
764 mtu,
765 now,
766 &paced_metrics(window, TEST_PACING_RATE, 2 * u64::from(mtu)),
767 );
768 assert_eq!(pacer.capacity, rate_capacity(TEST_PACING_RATE, mtu));
769
770 pacer.delay(rtt, u64::from(mtu), mtu, now, &unpaced_metrics(window));
773
774 assert_eq!(
775 pacer.capacity,
776 optimal_capacity(rtt, window, mtu),
777 "the window path kept a burst budget the rate path derived"
778 );
779 }
780
781 #[test]
782 fn max_bytes_per_second_overrides_a_higher_controller_rate() {
783 const SECONDS: u64 = 1;
784 const LIMIT: u64 = 125_000;
786
787 let window = 2_000_000;
788 let mtu = 1500;
789 let rtt = Duration::from_millis(50);
790 let start = Instant::now();
791 let metrics = paced_metrics(window, TEST_PACING_RATE, 2 * u64::from(mtu));
792 let mut pacer = Pacer::new(rtt, window, mtu, Some(LIMIT), start);
793
794 let sent = bytes_sent_over(
795 &mut pacer,
796 rtt,
797 mtu,
798 start,
799 Duration::from_secs(SECONDS),
800 &metrics,
801 );
802
803 let expected = LIMIT * SECONDS;
805 let slack = expected / 20;
806 assert!(
807 sent <= expected + slack,
808 "emitted {sent} bytes in {SECONDS}s, over the {expected} byte ceiling"
809 );
810 assert!(
811 sent + slack >= expected,
812 "emitted {sent} bytes in {SECONDS}s, underrunning the {expected} byte ceiling"
813 );
814 }
815}