diff --git a/quiche/include/quiche.h b/quiche/include/quiche.h index 2d0a74dae2..23a47c8b9e 100644 --- a/quiche/include/quiche.h +++ b/quiche/include/quiche.h @@ -666,6 +666,9 @@ typedef struct { // The estimated round-trip time variation (in nanoseconds). uint64_t rttvar; + // The number of large jumps in round-trip time observed. + uint64_t rtt_jumps; + // The size of the path's congestion window in bytes. size_t cwnd; diff --git a/quiche/src/ffi.rs b/quiche/src/ffi.rs index ed07ca7b6e..44cfe800af 100644 --- a/quiche/src/ffi.rs +++ b/quiche/src/ffi.rs @@ -1303,6 +1303,7 @@ pub struct PathStats { rtt: u64, min_rtt: u64, rttvar: u64, + rtt_jumps: u64, cwnd: usize, sent_bytes: u64, recv_bytes: u64, @@ -1332,6 +1333,7 @@ pub extern fn quiche_conn_path_stats( out.rtt = stats.rtt.as_nanos() as u64; out.min_rtt = stats.min_rtt.unwrap_or_default().as_nanos() as u64; out.rttvar = stats.rttvar.as_nanos() as u64; + out.rtt_jumps = stats.rtt_jumps; out.cwnd = stats.cwnd; out.sent_bytes = stats.sent_bytes; out.recv_bytes = stats.recv_bytes; diff --git a/quiche/src/path.rs b/quiche/src/path.rs index f773e4aee6..900c23938c 100644 --- a/quiche/src/path.rs +++ b/quiche/src/path.rs @@ -486,6 +486,7 @@ impl Path { rtt: self.recovery.rtt(), min_rtt: self.recovery.min_rtt(), rttvar: self.recovery.rttvar(), + rtt_jumps: self.recovery.rtt_jumps(), cwnd: self.recovery.cwnd(), sent_bytes: self.sent_bytes, recv_bytes: self.recv_bytes, @@ -866,6 +867,9 @@ pub struct PathStats { /// variation. pub rttvar: time::Duration, + /// The number of large jumps in round-trip time observed. + pub rtt_jumps: u64, + /// The size of the connection's congestion window in bytes. pub cwnd: usize, @@ -910,8 +914,8 @@ impl std::fmt::Debug for PathStats { )?; write!( f, - "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} cwnd={}", - self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.cwnd, + "recv={} sent={} lost={} retrans={} rtt={:?} min_rtt={:?} rttvar={:?} rtt_jumps={} cwnd={}", + self.recv, self.sent, self.lost, self.retrans, self.rtt, self.min_rtt, self.rttvar, self.rtt_jumps, self.cwnd, )?; write!( diff --git a/quiche/src/recovery/mod.rs b/quiche/src/recovery/mod.rs index 4433c61c02..b197f59c92 100644 --- a/quiche/src/recovery/mod.rs +++ b/quiche/src/recovery/mod.rs @@ -723,6 +723,10 @@ impl Recovery { self.rtt_stats.rttvar } + pub fn rtt_jumps(&self) -> u64 { + self.rtt_stats.rtt_jumps + } + pub fn pto(&self) -> Duration { self.rtt() + cmp::max(self.rtt_stats.rttvar * 4, GRANULARITY) } @@ -961,6 +965,7 @@ impl std::fmt::Debug for Recovery { write!(f, "srtt={:?} ", self.rtt_stats.smoothed_rtt)?; write!(f, "min_rtt={:?} ", *self.rtt_stats.min_rtt)?; write!(f, "rttvar={:?} ", self.rtt_stats.rttvar)?; + write!(f, "rtt_jumps={:?} ", self.rtt_stats.rtt_jumps)?; write!(f, "cwnd={} ", self.cwnd())?; write!(f, "ssthresh={} ", self.congestion.ssthresh)?; write!(f, "bytes_in_flight={} ", self.bytes_in_flight)?; diff --git a/quiche/src/recovery/rtt.rs b/quiche/src/recovery/rtt.rs index c61f7cf341..6fc7723658 100644 --- a/quiche/src/recovery/rtt.rs +++ b/quiche/src/recovery/rtt.rs @@ -33,6 +33,8 @@ pub(crate) const INITIAL_RTT: Duration = Duration::from_millis(333); pub(crate) const RTT_WINDOW: Duration = Duration::from_secs(300); +const JUMP_THRESHOLD: u32 = 3; + pub struct RttStats { pub(super) latest_rtt: Duration, @@ -45,6 +47,8 @@ pub struct RttStats { pub(super) max_ack_delay: Duration, pub(super) first_rtt_sample: Option, + + pub(super) rtt_jumps: u64, } impl std::fmt::Debug for RttStats { @@ -54,6 +58,7 @@ impl std::fmt::Debug for RttStats { .field("srtt", &self.smoothed_rtt) .field("minrtt", &*self.min_rtt) .field("rttvar", &self.rttvar) + .field("rtt_jumps", &self.rtt_jumps) .finish() } } @@ -67,6 +72,7 @@ impl RttStats { rttvar: INITIAL_RTT / 2, first_rtt_sample: None, max_ack_delay, + rtt_jumps: 0, } } @@ -98,6 +104,10 @@ impl RttStats { adjusted_rtt = latest_rtt - ack_delay; } + if adjusted_rtt >= self.smoothed_rtt * JUMP_THRESHOLD { + self.rtt_jumps += 1; + } + self.rttvar = self.rttvar * 3 / 4 + Duration::from_nanos( self.smoothed_rtt