gfe-relnote: In QUIC, when doing cwnd bootstrap, slow pacing rate if it is likely causing overshoot. Protected by gfe2_reloadable_flag_quic_bbr_mitigate_overly_large_bandwidth_sample.
PiperOrigin-RevId: 288958446
Change-Id: Ia076b0f27d7d9302aa567a8577b25b0ad10da7cc
diff --git a/quic/core/congestion_control/bbr_sender.cc b/quic/core/congestion_control/bbr_sender.cc
index b750e0a..bb63b55 100644
--- a/quic/core/congestion_control/bbr_sender.cc
+++ b/quic/core/congestion_control/bbr_sender.cc
@@ -135,7 +135,9 @@
probe_rtt_skipped_if_similar_rtt_(false),
probe_rtt_disabled_if_app_limited_(false),
app_limited_since_last_probe_rtt_(false),
- min_rtt_since_last_probe_rtt_(QuicTime::Delta::Infinite()) {
+ min_rtt_since_last_probe_rtt_(QuicTime::Delta::Infinite()),
+ network_parameters_adjusted_(false),
+ bytes_lost_with_network_parameters_adjusted_(0) {
if (stats_) {
// Clear some startup stats if |stats_| has been used by another sender,
// which happens e.g. when QuicConnection switch send algorithms.
@@ -377,6 +379,12 @@
QuicBandwidth new_pacing_rate =
QuicBandwidth::FromBytesAndTimeDelta(congestion_window_, GetMinRtt());
pacing_rate_ = std::max(pacing_rate_, new_pacing_rate);
+ if (GetQuicReloadableFlag(
+ quic_bbr_mitigate_overly_large_bandwidth_sample)) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_bbr_mitigate_overly_large_bandwidth_sample, 1, 4);
+ network_parameters_adjusted_ = true;
+ }
}
}
}
@@ -473,7 +481,7 @@
// After the model is updated, recalculate the pacing rate and congestion
// window.
- CalculatePacingRate();
+ CalculatePacingRate(bytes_lost);
CalculateCongestionWindow(bytes_acked, excess_acked);
CalculateRecoveryWindow(bytes_acked, bytes_lost);
@@ -811,7 +819,7 @@
}
}
-void BbrSender::CalculatePacingRate() {
+void BbrSender::CalculatePacingRate(QuicByteCount bytes_lost) {
if (BandwidthEstimate().IsZero()) {
return;
}
@@ -829,6 +837,40 @@
initial_congestion_window_, rtt_stats_->min_rtt());
return;
}
+
+ if (network_parameters_adjusted_) {
+ bytes_lost_with_network_parameters_adjusted_ += bytes_lost;
+ // Check for overshooting with network parameters adjusted when pacing rate
+ // > target_rate and loss has been detected.
+ if (pacing_rate_ > target_rate &&
+ bytes_lost_with_network_parameters_adjusted_ > 0) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_bbr_mitigate_overly_large_bandwidth_sample, 2, 4);
+ if (has_non_app_limited_sample_ ||
+ bytes_lost_with_network_parameters_adjusted_ * 2 >
+ initial_congestion_window_) {
+ // We are fairly sure overshoot happens if 1) there is at least one
+ // non app-limited bw sample or 2) half of IW gets lost. Slow pacing
+ // rate.
+ if (has_non_app_limited_sample_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_bbr_mitigate_overly_large_bandwidth_sample, 3, 4);
+ } else {
+ QUIC_RELOADABLE_FLAG_COUNT_N(
+ quic_bbr_mitigate_overly_large_bandwidth_sample, 4, 4);
+ }
+ // Do not let the pacing rate drop below the connection's initial pacing
+ // rate.
+ pacing_rate_ =
+ std::max(target_rate,
+ QuicBandwidth::FromBytesAndTimeDelta(
+ initial_congestion_window_, rtt_stats_->min_rtt()));
+ bytes_lost_with_network_parameters_adjusted_ = 0;
+ network_parameters_adjusted_ = false;
+ }
+ }
+ }
+
// Slow the pacing rate in STARTUP once loss has ever been detected.
const bool has_ever_detected_loss = end_recovery_at_.IsInitialized();
if (slower_startup_ && has_ever_detected_loss &&
diff --git a/quic/core/congestion_control/bbr_sender.h b/quic/core/congestion_control/bbr_sender.h
index 9a811fa..db0f330 100644
--- a/quic/core/congestion_control/bbr_sender.h
+++ b/quic/core/congestion_control/bbr_sender.h
@@ -233,7 +233,7 @@
QuicByteCount newly_acked_bytes);
// Determines the appropriate pacing rate for the connection.
- void CalculatePacingRate();
+ void CalculatePacingRate(QuicByteCount bytes_lost);
// Determines the appropriate congestion window for the connection.
void CalculateCongestionWindow(QuicByteCount bytes_acked,
QuicByteCount excess_acked);
@@ -392,6 +392,12 @@
bool probe_rtt_disabled_if_app_limited_;
bool app_limited_since_last_probe_rtt_;
QuicTime::Delta min_rtt_since_last_probe_rtt_;
+
+ // True if network parameters are adjusted, and this will be reset if
+ // overshooting is detected and pacing rate gets slowed.
+ bool network_parameters_adjusted_;
+ // Bytes lost after network parameters gets adjusted.
+ QuicByteCount bytes_lost_with_network_parameters_adjusted_;
};
QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
diff --git a/quic/core/congestion_control/bbr_sender_test.cc b/quic/core/congestion_control/bbr_sender_test.cc
index d34d15b..c8b1b77 100644
--- a/quic/core/congestion_control/bbr_sender_test.cc
+++ b/quic/core/congestion_control/bbr_sender_test.cc
@@ -1421,5 +1421,39 @@
}
}
+TEST_F(BbrSenderTest, MitigateCwndBootstrappingOvershoot) {
+ SetQuicReloadableFlag(quic_bbr_mitigate_overly_large_bandwidth_sample, true);
+ CreateDefaultSetup();
+ bbr_sender_.AddBytesToTransfer(1 * 1024 * 1024);
+
+ // Wait until an ACK comes back.
+ const QuicTime::Delta timeout = QuicTime::Delta::FromSeconds(5);
+ bool simulator_result = simulator_.RunUntilOrTimeout(
+ [this]() { return !sender_->ExportDebugState().min_rtt.IsZero(); },
+ timeout);
+ ASSERT_TRUE(simulator_result);
+
+ // Bootstrap cwnd by a overly large bandwidth sample.
+ bbr_sender_.connection()->AdjustNetworkParameters(
+ SendAlgorithmInterface::NetworkParams(8 * kTestLinkBandwidth,
+ QuicTime::Delta::Zero(), false));
+ QuicBandwidth pacing_rate = sender_->PacingRate(0);
+ EXPECT_EQ(8 * kTestLinkBandwidth, pacing_rate);
+
+ // Wait until pacing_rate decreases.
+ simulator_result = simulator_.RunUntilOrTimeout(
+ [this, pacing_rate]() { return sender_->PacingRate(0) < pacing_rate; },
+ timeout);
+ ASSERT_TRUE(simulator_result);
+ EXPECT_EQ(BbrSender::STARTUP, sender_->ExportDebugState().mode);
+ if (GetQuicReloadableFlag(quic_conservative_cwnd_and_pacing_gains)) {
+ EXPECT_APPROX_EQ(2.0f * sender_->BandwidthEstimate(),
+ sender_->PacingRate(0), 0.01f);
+ } else {
+ EXPECT_APPROX_EQ(2.885f * sender_->BandwidthEstimate(),
+ sender_->PacingRate(0), 0.01f);
+ }
+}
+
} // namespace test
} // namespace quic