1use std::time::Duration;
28use std::time::Instant;
29
30use crate::minmax::Minmax;
31use crate::recovery::GRANULARITY;
32
33pub(crate) const RTT_WINDOW: Duration = Duration::from_secs(300);
34
35pub struct RttStats {
36 pub(super) latest_rtt: Duration,
37
38 max_rtt: Duration,
39
40 pub(super) smoothed_rtt: Duration,
41
42 pub(super) rttvar: Duration,
43
44 pub(super) min_rtt: Minmax<Duration>,
45
46 pub(super) max_ack_delay: Duration,
47
48 pub(super) has_first_rtt_sample: bool,
49}
50
51impl std::fmt::Debug for RttStats {
52 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
53 f.debug_struct("RttStats")
54 .field("lastest_rtt", &self.latest_rtt)
55 .field("srtt", &self.smoothed_rtt)
56 .field("minrtt", &*self.min_rtt)
57 .field("rttvar", &self.rttvar)
58 .finish()
59 }
60}
61
62impl RttStats {
63 pub(crate) fn new(initial_rtt: Duration, max_ack_delay: Duration) -> Self {
64 RttStats {
65 latest_rtt: Duration::ZERO,
66 min_rtt: Minmax::new(initial_rtt),
67 smoothed_rtt: initial_rtt,
68 max_rtt: initial_rtt,
69 rttvar: initial_rtt / 2,
70 has_first_rtt_sample: false,
71 max_ack_delay,
72 }
73 }
74
75 pub(crate) fn update_rtt(
76 &mut self, latest_rtt: Duration, mut ack_delay: Duration, now: Instant,
77 handshake_confirmed: bool,
78 ) {
79 self.latest_rtt = latest_rtt;
80
81 if !self.has_first_rtt_sample {
82 self.min_rtt.reset(now, latest_rtt);
83 self.smoothed_rtt = latest_rtt;
84 self.max_rtt = latest_rtt;
85 self.rttvar = latest_rtt / 2;
86 self.has_first_rtt_sample = true;
87 return;
88 }
89
90 self.min_rtt.running_min(RTT_WINDOW, now, latest_rtt);
92
93 self.max_rtt = self.max_rtt.max(latest_rtt);
94
95 if handshake_confirmed {
97 ack_delay = ack_delay.min(self.max_ack_delay);
98 }
99
100 let mut adjusted_rtt = latest_rtt;
102 if latest_rtt >= *self.min_rtt + ack_delay {
103 adjusted_rtt = latest_rtt - ack_delay;
104 }
105
106 self.rttvar = self.rttvar * 3 / 4 +
107 Duration::from_nanos(
108 self.smoothed_rtt
109 .as_nanos()
110 .abs_diff(adjusted_rtt.as_nanos()) as u64 /
111 4,
112 );
113
114 self.smoothed_rtt = self.smoothed_rtt * 7 / 8 + adjusted_rtt / 8;
115 }
116
117 pub(crate) fn rtt(&self) -> Duration {
118 self.smoothed_rtt
119 }
120
121 #[allow(dead_code)]
122 pub(crate) fn latest_rtt(&self) -> Duration {
123 self.latest_rtt
124 }
125
126 pub(crate) fn rttvar(&self) -> Duration {
127 self.rttvar
128 }
129
130 pub(crate) fn min_rtt(&self) -> Option<Duration> {
131 if self.has_first_rtt_sample {
132 Some(*self.min_rtt)
133 } else {
134 None
135 }
136 }
137
138 pub(crate) fn max_rtt(&self) -> Option<Duration> {
139 if self.has_first_rtt_sample {
140 Some(self.max_rtt)
141 } else {
142 None
143 }
144 }
145
146 pub(crate) fn loss_delay(&self, time_thresh: f64) -> Duration {
147 self.latest_rtt
148 .max(self.smoothed_rtt)
149 .mul_f64(time_thresh)
150 .max(GRANULARITY)
151 }
152}