Skip to content

Commit cff7ed2

Browse files
committed
add HMM RTT jump detector
1 parent eb875fc commit cff7ed2

10 files changed

Lines changed: 1469 additions & 413 deletions

File tree

quiche/src/recovery/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ gcongestion/ Next-gen CC (BBR2)
3939
probe_bw.rs ProbeBW mode (bandwidth probing cycles)
4040
probe_rtt.rs ProbeRTT mode (min RTT measurement)
4141
network_model.rs Bandwidth/RTT model, BbrParams application
42-
rtt_jump_detector.rs Global-min RTT jump detection
42+
rtt_jump_detector/ RTT jump detection (global-min + HMM)
4343
bbr.rs BBR (v1, not actively used)
4444
```
4545

quiche/src/recovery/congestion/recovery.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -924,9 +924,9 @@ impl RecoveryOps for LegacyRecovery {
924924
}
925925

926926
fn rtt_persistent_jump_count(&self) -> u64 {
927-
// Persistent RTT jump counts are produced by the BBR2 global-min RTT
928-
// jump detector. Legacy Reno/CUBIC recovery does not own a BBR2
929-
// network model or run that detector, but it still implements
927+
// Persistent RTT jump counts are produced by the BBR2 RTT jump
928+
// detector. Legacy Reno/CUBIC recovery does not own a BBR2 network
929+
// model or run that detector, but it still implements
930930
// RecoveryOps so PathStats can be populated through one shared
931931
// interface. Report zero to indicate that no detector is active on
932932
// this path.

quiche/src/recovery/gcongestion/bbr2/network_model.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ pub(super) struct BBRv2NetworkModel {
193193
/// The most recent ack rate from the BandwidthSampler.
194194
latest_ack_rate: Option<Bandwidth>,
195195

196+
/// Detector for persistent RTT jump episodes.
196197
rtt_jump_detector: RttJumpDetector,
197198
}
198199

@@ -242,7 +243,7 @@ impl BBRv2NetworkModel {
242243
latest_send_rate: None,
243244
latest_ack_rate: None,
244245

245-
rtt_jump_detector: RttJumpDetector::new(),
246+
rtt_jump_detector: RttJumpDetector::new(params.rtt_jump_detector),
246247
}
247248
}
248249

@@ -369,8 +370,7 @@ impl BBRv2NetworkModel {
369370
if let Some(rtt_sample) = sample.sample_rtt {
370371
congestion_event.sample_min_rtt = Some(rtt_sample);
371372

372-
self.rtt_jump_detector.on_rtt_sample_with_mode(
373-
params.rtt_jump_detector,
373+
self.rtt_jump_detector.on_rtt_sample(
374374
rtt_sample,
375375
event_time,
376376
self.full_bandwidth_reached,
@@ -930,6 +930,28 @@ mod tests {
930930
assert!(model.last_persistent_jump_time().is_some());
931931
}
932932

933+
#[test]
934+
fn hmm_detector_can_be_enabled() {
935+
let params = &rtt_jump_params(BbrRttJumpDetector::Hmm);
936+
let mut model = BBRv2NetworkModel::new(params, RTT);
937+
let base = Instant::now();
938+
939+
for pkt in 1..9u64 {
940+
ack_with_rtt(&mut model, params, pkt, base, ms(pkt * 10), RTT);
941+
}
942+
model.set_full_bandwidth_reached();
943+
944+
let mut offset = 200u64;
945+
for pkt in 9u64..40 {
946+
ack_with_rtt(&mut model, params, pkt, base, ms(offset), RTT_3X);
947+
offset += 100;
948+
}
949+
950+
assert_eq!(model.rtt_persistent_jump_count(), 1);
951+
assert!(model.is_rtt_jump_persistent());
952+
assert!(model.last_persistent_jump_time().is_some());
953+
}
954+
933955
#[test]
934956
fn global_min_detector_sustained_step_becomes_persistent() {
935957
let params = &rtt_jump_params(BbrRttJumpDetector::GlobalMin);
@@ -1012,4 +1034,28 @@ mod tests {
10121034
assert_eq!(model.rtt_persistent_jump_count(), 1);
10131035
assert!(model.is_rtt_jump_persistent());
10141036
}
1037+
1038+
#[test]
1039+
fn hmm_detector_ignores_startup_rtt_jump_until_full_bandwidth() {
1040+
let params = &rtt_jump_params(BbrRttJumpDetector::Hmm);
1041+
let mut model = BBRv2NetworkModel::new(params, RTT);
1042+
let base = Instant::now();
1043+
1044+
for pkt in 1..9u64 {
1045+
ack_with_rtt(&mut model, params, pkt, base, ms(pkt * 10), RTT);
1046+
}
1047+
1048+
for pkt in 9u64..20 {
1049+
ack_with_rtt(&mut model, params, pkt, base, ms(pkt * 100), RTT_3X);
1050+
}
1051+
1052+
assert_eq!(model.rtt_persistent_jump_count(), 0);
1053+
assert!(!model.is_rtt_jump_active());
1054+
1055+
model.set_full_bandwidth_reached();
1056+
ack_with_rtt(&mut model, params, 20, base, ms(2100), RTT_3X);
1057+
1058+
assert_eq!(model.rtt_persistent_jump_count(), 0);
1059+
assert!(!model.is_rtt_jump_persistent());
1060+
}
10151061
}

0 commit comments

Comments
 (0)