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