gfe-relnote: In QUIC, re-calculate pacing rate when cwnd gets bootstrapped. Protected by gfe2_reloadable_flag_quic_bbr_fix_pacing_rate.
PiperOrigin-RevId: 277502654
Change-Id: I2c76d7a6ddb7e6097ed294d08b51678e455fa2b1
diff --git a/quic/core/congestion_control/bbr_sender.cc b/quic/core/congestion_control/bbr_sender.cc
index b0fd50d..1ba6b42 100644
--- a/quic/core/congestion_control/bbr_sender.cc
+++ b/quic/core/congestion_control/bbr_sender.cc
@@ -372,6 +372,13 @@
set_high_cwnd_gain(kDerivedHighCWNDGain);
}
congestion_window_ = new_cwnd;
+ if (GetQuicReloadableFlag(quic_bbr_fix_pacing_rate)) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_fix_pacing_rate);
+ // Pace at the rate of new_cwnd / RTT.
+ QuicBandwidth new_pacing_rate =
+ QuicBandwidth::FromBytesAndTimeDelta(congestion_window_, GetMinRtt());
+ pacing_rate_ = std::max(pacing_rate_, new_pacing_rate);
+ }
}
}
diff --git a/quic/core/congestion_control/bbr_sender_test.cc b/quic/core/congestion_control/bbr_sender_test.cc
index 8ecab87..290cf4c 100644
--- a/quic/core/congestion_control/bbr_sender_test.cc
+++ b/quic/core/congestion_control/bbr_sender_test.cc
@@ -1308,5 +1308,73 @@
->GetSlowStartDuration());
}
+// Regression test for b/143540157.
+TEST_F(BbrSenderTest, RecalculatePacingRateOnCwndChange1RTT) {
+ 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);
+ const QuicByteCount previous_cwnd =
+ sender_->ExportDebugState().congestion_window;
+
+ // Bootstrap cwnd.
+ bbr_sender_.connection()->AdjustNetworkParameters(
+ kTestLinkBandwidth, QuicTime::Delta::Zero(), false);
+ EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth);
+ EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate());
+ EXPECT_LT(previous_cwnd, sender_->ExportDebugState().congestion_window);
+
+ if (GetQuicReloadableFlag(quic_bbr_fix_pacing_rate)) {
+ // Verify pacing rate is re-calculated based on the new cwnd and min_rtt.
+ EXPECT_APPROX_EQ(QuicBandwidth::FromBytesAndTimeDelta(
+ sender_->ExportDebugState().congestion_window,
+ sender_->ExportDebugState().min_rtt),
+ sender_->PacingRate(/*bytes_in_flight=*/0), 0.01f);
+ } else {
+ // Pacing rate is still based on initial cwnd.
+ EXPECT_APPROX_EQ(QuicBandwidth::FromBytesAndTimeDelta(
+ kInitialCongestionWindowPackets * kDefaultTCPMSS,
+ sender_->ExportDebugState().min_rtt),
+ sender_->PacingRate(/*bytes_in_flight=*/0), 0.01f);
+ }
+}
+
+TEST_F(BbrSenderTest, RecalculatePacingRateOnCwndChange0RTT) {
+ CreateDefaultSetup();
+ // Initial RTT is available.
+ const_cast<RttStats*>(rtt_stats_)->set_initial_rtt(kTestRtt);
+
+ // Bootstrap cwnd.
+ bbr_sender_.connection()->AdjustNetworkParameters(
+ kTestLinkBandwidth, QuicTime::Delta::Zero(), false);
+ EXPECT_EQ(kTestLinkBandwidth, sender_->ExportDebugState().max_bandwidth);
+ EXPECT_EQ(kTestLinkBandwidth, sender_->BandwidthEstimate());
+ EXPECT_LT(kInitialCongestionWindowPackets * kDefaultTCPMSS,
+ sender_->ExportDebugState().congestion_window);
+ // No Rtt sample is available.
+ EXPECT_TRUE(sender_->ExportDebugState().min_rtt.IsZero());
+
+ if (GetQuicReloadableFlag(quic_bbr_fix_pacing_rate)) {
+ // Verify pacing rate is re-calculated based on the new cwnd and initial
+ // RTT.
+ EXPECT_APPROX_EQ(QuicBandwidth::FromBytesAndTimeDelta(
+ sender_->ExportDebugState().congestion_window,
+ rtt_stats_->initial_rtt()),
+ sender_->PacingRate(/*bytes_in_flight=*/0), 0.01f);
+ } else {
+ // Pacing rate is still based on initial cwnd.
+ EXPECT_APPROX_EQ(
+ 2.885f * QuicBandwidth::FromBytesAndTimeDelta(
+ kInitialCongestionWindowPackets * kDefaultTCPMSS,
+ rtt_stats_->initial_rtt()),
+ sender_->PacingRate(/*bytes_in_flight=*/0), 0.01f);
+ }
+}
+
} // namespace test
} // namespace quic