gfe-relnote: Change QUIC BBRv2 to reduce bandwidth_lo when the BBQ6, BBQ7, BBQ8, and BBQ9 connection options are present. Protected by quic_reloadable_flag_quic_bbr_bw_startup. PiperOrigin-RevId: 347676357 Change-Id: Ica5cb228663c826594c9c35a49e0a18f191ec004
diff --git a/quic/core/congestion_control/bbr2_misc.cc b/quic/core/congestion_control/bbr2_misc.cc index 0be3253..eb29983 100644 --- a/quic/core/congestion_control/bbr2_misc.cc +++ b/quic/core/congestion_control/bbr2_misc.cc
@@ -168,6 +168,7 @@ inflight_latest_ = sample.sample_max_inflight; } + // Adapt lower bounds(bandwidth_lo and inflight_lo). AdaptLowerBounds(*congestion_event); if (!congestion_event->end_of_round_trip) { @@ -185,6 +186,63 @@ void Bbr2NetworkModel::AdaptLowerBounds( const Bbr2CongestionEvent& congestion_event) { + if (Params().bw_lo_mode_ != Bbr2Params::DEFAULT) { + DCHECK(Params().bw_startup); + if (congestion_event.bytes_lost == 0) { + return; + } + // Ignore losses from packets sent when probing for more bandwidth in + // STARTUP or PROBE_UP when they're lost in DRAIN or PROBE_DOWN. + if (pacing_gain_ < 1) { + return; + } + // Decrease bandwidth_lo whenever there is loss. + // Set bandwidth_lo_ if it is not yet set. + if (bandwidth_lo_.IsInfinite()) { + bandwidth_lo_ = MaxBandwidth(); + } + switch (Params().bw_lo_mode_) { + case Bbr2Params::MIN_RTT_REDUCTION: + bandwidth_lo_ = + bandwidth_lo_ - QuicBandwidth::FromBytesAndTimeDelta( + congestion_event.bytes_lost, MinRtt()); + break; + case Bbr2Params::INFLIGHT_REDUCTION: { + // Use a max of BDP and inflight to avoid starving app-limited flows. + const QuicByteCount effective_inflight = + std::max(BDP(), congestion_event.prior_bytes_in_flight); + // This could use bytes_lost_in_round if the bandwidth_lo_ was saved + // when entering 'recovery', but this BBRv2 implementation doesn't have + // recovery defined. + bandwidth_lo_ = bandwidth_lo_ * + ((effective_inflight - congestion_event.bytes_lost) / + static_cast<double>(effective_inflight)); + break; + } + case Bbr2Params::CWND_REDUCTION: + bandwidth_lo_ = + bandwidth_lo_ * + ((congestion_event.prior_cwnd - congestion_event.bytes_lost) / + static_cast<double>(congestion_event.prior_cwnd)); + break; + case Bbr2Params::DEFAULT: + QUIC_BUG << "Unreachable case DEFAULT."; + } + if (pacing_gain_ > Params().startup_full_bw_threshold) { + // In STARTUP, pacing_gain_ is applied to bandwidth_lo_, so this backs + // that multiplication out to allow the pacing rate to decrease, + // but not below bandwidth_latest_ * startup_full_bw_threshold. + bandwidth_lo_ = + std::max(bandwidth_lo_, + bandwidth_latest_ * + (Params().startup_full_bw_threshold / pacing_gain_)); + } else { + // Ensure bandwidth_lo isn't lower than bandwidth_latest_. + bandwidth_lo_ = std::max(bandwidth_lo_, bandwidth_latest_); + } + // This early return ignores inflight_lo as well. + return; + } if (!congestion_event.end_of_round_trip || congestion_event.is_probing_for_bandwidth) { return;
diff --git a/quic/core/congestion_control/bbr2_misc.h b/quic/core/congestion_control/bbr2_misc.h index c26d2f9..f02e22d 100644 --- a/quic/core/congestion_control/bbr2_misc.h +++ b/quic/core/congestion_control/bbr2_misc.h
@@ -195,6 +195,23 @@ // Can be disabled by connection option 'B2RC'. bool enable_reno_coexistence = true; + + // For experimentation to improve fast convergence upon loss. + enum QuicBandwidthLoMode : uint8_t { + DEFAULT = 0, + MIN_RTT_REDUCTION = 1, // 'BBQ7' + INFLIGHT_REDUCTION = 2, // 'BBQ8' + CWND_REDUCTION = 3, // 'BBQ9' + }; + + // Different modes change bandwidth_lo_ differently upon loss. + QuicBandwidthLoMode bw_lo_mode_ = QuicBandwidthLoMode::DEFAULT; + + // Set the pacing gain to 25% larger than the recent BW increase in STARTUP. + bool decrease_startup_pacing_at_end_of_round = false; + + // Latch the flag for quic_bbr2_bw_startup. + const bool bw_startup = GetQuicReloadableFlag(quic_bbr2_bw_startup); }; class QUIC_EXPORT_PRIVATE RoundTripCounter {
diff --git a/quic/core/congestion_control/bbr2_sender.cc b/quic/core/congestion_control/bbr2_sender.cc index c12c4e2..b27196b 100644 --- a/quic/core/congestion_control/bbr2_sender.cc +++ b/quic/core/congestion_control/bbr2_sender.cc
@@ -133,6 +133,9 @@ if (ContainsQuicTag(connection_options, kBBQ2)) { params_.startup_cwnd_gain = 2.885; params_.drain_cwnd_gain = 2.885; + if (params_.bw_startup) { + model_.set_cwnd_gain(params_.startup_cwnd_gain); + } } if (ContainsQuicTag(connection_options, kB2NE)) { params_.always_exit_startup_on_excess_loss = false; @@ -156,6 +159,22 @@ if (ContainsQuicTag(connection_options, kBSAO)) { model_.EnableOverestimateAvoidance(); } + if (params_.bw_startup && ContainsQuicTag(connection_options, kBBQ6)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_bw_startup, 1, 4); + params_.decrease_startup_pacing_at_end_of_round = true; + } + if (params_.bw_startup && ContainsQuicTag(connection_options, kBBQ7)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_bw_startup, 2, 4); + params_.bw_lo_mode_ = Bbr2Params::QuicBandwidthLoMode::MIN_RTT_REDUCTION; + } + if (params_.bw_startup && ContainsQuicTag(connection_options, kBBQ8)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_bw_startup, 3, 4); + params_.bw_lo_mode_ = Bbr2Params::QuicBandwidthLoMode::INFLIGHT_REDUCTION; + } + if (params_.bw_startup && ContainsQuicTag(connection_options, kBBQ9)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_bw_startup, 4, 4); + params_.bw_lo_mode_ = Bbr2Params::QuicBandwidthLoMode::CWND_REDUCTION; + } } Limits<QuicByteCount> Bbr2Sender::GetCwndLimitsByMode() const { @@ -303,11 +322,14 @@ } QuicBandwidth target_rate = model_.pacing_gain() * model_.BandwidthEstimate(); - if (model_.full_bandwidth_reached()) { + if (model_.full_bandwidth_reached() || + params_.decrease_startup_pacing_at_end_of_round || + params_.bw_lo_mode_ != Bbr2Params::DEFAULT) { pacing_rate_ = target_rate; return; } + // By default, the pacing rate never decreases in STARTUP. if (target_rate > pacing_rate_) { pacing_rate_ = target_rate; }
diff --git a/quic/core/congestion_control/bbr2_simulator_test.cc b/quic/core/congestion_control/bbr2_simulator_test.cc index 5aec9cb..f681650 100644 --- a/quic/core/congestion_control/bbr2_simulator_test.cc +++ b/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -121,7 +121,11 @@ class Bbr2SimulatorTest : public QuicTest { protected: - Bbr2SimulatorTest() : simulator_(&random_) {} + Bbr2SimulatorTest() : simulator_(&random_) { + // Enable this for all tests because it moves where cwnd and pacing gain + // are initialized. + SetQuicReloadableFlag(quic_bbr2_bw_startup, true); + } void SetUp() override { if (GetQuicFlag(FLAGS_quic_bbr2_test_regression_mode) == "regress") { @@ -583,7 +587,72 @@ CreateNetwork(params); DriveOutOfStartup(params); - EXPECT_LE(sender_loss_rate_in_packets(), 0.20); + // Packet loss is smaller with a CWND gain of 2 than 2.889. + EXPECT_LE(sender_loss_rate_in_packets(), 0.05); +} + +// Test the number of losses decreases with packet-conservation pacing. +TEST_F(Bbr2DefaultTopologyTest, PacketLossBBQ6SmallBufferStartup) { + SetQuicReloadableFlag(quic_bbr2_bw_startup, true); + SetConnectionOption(kBBQ2); // Increase CWND gain. + SetConnectionOption(kBBQ6); + DefaultTopologyParams params; + params.switch_queue_capacity_in_bdp = 0.5; + CreateNetwork(params); + + DriveOutOfStartup(params); + EXPECT_LE(sender_loss_rate_in_packets(), 0.0575); + // bandwidth_lo is cleared exiting STARTUP. + EXPECT_EQ(sender_->ExportDebugState().bandwidth_lo, + QuicBandwidth::Infinite()); +} + +// Test the number of losses decreases with min_rtt packet-conservation pacing. +TEST_F(Bbr2DefaultTopologyTest, PacketLossBBQ7SmallBufferStartup) { + SetQuicReloadableFlag(quic_bbr2_bw_startup, true); + SetConnectionOption(kBBQ2); // Increase CWND gain. + SetConnectionOption(kBBQ7); + DefaultTopologyParams params; + params.switch_queue_capacity_in_bdp = 0.5; + CreateNetwork(params); + + DriveOutOfStartup(params); + EXPECT_LE(sender_loss_rate_in_packets(), 0.06); + // bandwidth_lo is cleared exiting STARTUP. + EXPECT_EQ(sender_->ExportDebugState().bandwidth_lo, + QuicBandwidth::Infinite()); +} + +// Test the number of losses decreases with Inflight packet-conservation pacing. +TEST_F(Bbr2DefaultTopologyTest, PacketLossBBQ8SmallBufferStartup) { + SetQuicReloadableFlag(quic_bbr2_bw_startup, true); + SetConnectionOption(kBBQ2); // Increase CWND gain. + SetConnectionOption(kBBQ8); + DefaultTopologyParams params; + params.switch_queue_capacity_in_bdp = 0.5; + CreateNetwork(params); + + DriveOutOfStartup(params); + EXPECT_LE(sender_loss_rate_in_packets(), 0.065); + // bandwidth_lo is cleared exiting STARTUP. + EXPECT_EQ(sender_->ExportDebugState().bandwidth_lo, + QuicBandwidth::Infinite()); +} + +// Test the number of losses decreases with CWND packet-conservation pacing. +TEST_F(Bbr2DefaultTopologyTest, PacketLossBBQ9SmallBufferStartup) { + SetQuicReloadableFlag(quic_bbr2_bw_startup, true); + SetConnectionOption(kBBQ2); // Increase CWND gain. + SetConnectionOption(kBBQ9); + DefaultTopologyParams params; + params.switch_queue_capacity_in_bdp = 0.5; + CreateNetwork(params); + + DriveOutOfStartup(params); + EXPECT_LE(sender_loss_rate_in_packets(), 0.065); + // bandwidth_lo is cleared exiting STARTUP. + EXPECT_EQ(sender_->ExportDebugState().bandwidth_lo, + QuicBandwidth::Infinite()); } // Verify the behavior of the algorithm in the case when the connection sends
diff --git a/quic/core/congestion_control/bbr2_startup.cc b/quic/core/congestion_control/bbr2_startup.cc index 5d02de7..9486eb1 100644 --- a/quic/core/congestion_control/bbr2_startup.cc +++ b/quic/core/congestion_control/bbr2_startup.cc
@@ -8,6 +8,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h" #include "net/third_party/quiche/src/quic/core/quic_bandwidth.h" #include "net/third_party/quiche/src/quic/core/quic_types.h" +#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h" #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h" namespace quic { @@ -22,6 +23,11 @@ sender_->connection_stats_->slowstart_count = 1; sender_->connection_stats_->slowstart_duration = QuicTimeAccumulator(); sender_->connection_stats_->slowstart_duration.Start(now); + if (sender->Params().bw_startup) { + // Enter() is never called for Startup, so the gains needs to be set here. + model_->set_pacing_gain(Params().startup_pacing_gain); + model_->set_cwnd_gain(Params().startup_cwnd_gain); + } } void Bbr2StartupMode::Enter(QuicTime /*now*/, @@ -32,6 +38,8 @@ void Bbr2StartupMode::Leave(QuicTime now, const Bbr2CongestionEvent* /*congestion_event*/) { sender_->connection_stats_->slowstart_duration.Stop(now); + // Clear bandwidth_lo if it's set during STARTUP. + model_->clear_bandwidth_lo(); } Bbr2Mode Bbr2StartupMode::OnCongestionEvent( @@ -50,8 +58,42 @@ } } - model_->set_pacing_gain(Params().startup_pacing_gain); - model_->set_cwnd_gain(Params().startup_cwnd_gain); + if (Params().decrease_startup_pacing_at_end_of_round) { + DCHECK_GT(model_->pacing_gain(), 0); + DCHECK(Params().bw_startup); + if (congestion_event.end_of_round_trip && + !congestion_event.last_sample_is_app_limited) { + // Multiply by startup_pacing_gain, so if the bandwidth doubles, + // the pacing gain will be the full startup_pacing_gain. + if (max_bw_at_round_beginning_ > QuicBandwidth::Zero()) { + const float bandwidth_ratio = + std::max(1., model_->MaxBandwidth().ToBitsPerSecond() / + static_cast<double>( + max_bw_at_round_beginning_.ToBitsPerSecond())); + // Even when bandwidth isn't increasing, use a gain large enough to + // cause a startup_full_bw_threshold increase. + const float new_gain = + ((bandwidth_ratio - 1) * (Params().startup_pacing_gain - + Params().startup_full_bw_threshold)) + + Params().startup_full_bw_threshold; + // Allow the pacing gain to decrease. + model_->set_pacing_gain( + std::min(Params().startup_pacing_gain, new_gain)); + // Clear bandwidth_lo if it's less than the pacing rate. + // This avoids a constantly app-limited flow from having it's pacing + // gain effectively decreased below 1.25. + if (model_->bandwidth_lo() < + model_->MaxBandwidth() * model_->pacing_gain()) { + model_->clear_bandwidth_lo(); + } + } + max_bw_at_round_beginning_ = model_->MaxBandwidth(); + } + } else if (!Params().bw_startup) { + // When the flag is enabled, set these in the constructor. + model_->set_pacing_gain(Params().startup_pacing_gain); + model_->set_cwnd_gain(Params().startup_cwnd_gain); + } // TODO(wub): Maybe implement STARTUP => PROBE_RTT. return model_->full_bandwidth_reached() ? Bbr2Mode::DRAIN : Bbr2Mode::STARTUP;
diff --git a/quic/core/congestion_control/bbr2_startup.h b/quic/core/congestion_control/bbr2_startup.h index f753a1e..6b44ae8 100644 --- a/quic/core/congestion_control/bbr2_startup.h +++ b/quic/core/congestion_control/bbr2_startup.h
@@ -57,6 +57,8 @@ const Bbr2Params& Params() const; void CheckExcessiveLosses(const Bbr2CongestionEvent& congestion_event); + // Used when the pacing gain can decrease in STARTUP. + QuicBandwidth max_bw_at_round_beginning_ = QuicBandwidth::Zero(); }; QUIC_EXPORT_PRIVATE std::ostream& operator<<(
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index d0420cc..acf44a4 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -108,6 +108,14 @@ const QuicTag kBBQ5 = TAG('B', 'B', 'Q', '5'); // Expire ack aggregation upon // bandwidth increase in // STARTUP. +const QuicTag kBBQ6 = TAG('B', 'B', 'Q', '6'); // Reduce STARTUP gain to 25% + // more than BW increase. +const QuicTag kBBQ7 = TAG('B', 'B', 'Q', '7'); // Reduce bw_lo by + // bytes_lost/min_rtt. +const QuicTag kBBQ8 = TAG('B', 'B', 'Q', '8'); // Reduce bw_lo by + // bw_lo * bytes_lost/inflight +const QuicTag kBBQ9 = TAG('B', 'B', 'Q', '9'); // Reduce bw_lo by + // bw_lo * bytes_lost/cwnd const QuicTag kRENO = TAG('R', 'E', 'N', 'O'); // Reno Congestion Control const QuicTag kTPCC = TAG('P', 'C', 'C', '\0'); // Performance-Oriented // Congestion Control
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h index 50b6c9e..912455f 100644 --- a/quic/core/quic_flags_list.h +++ b/quic/core/quic_flags_list.h
@@ -11,6 +11,7 @@ QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allocate_stream_sequencer_buffer_blocks_on_demand, false) QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_allow_client_enabled_bbr_v2, false) QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_avoid_too_low_probe_bw_cwnd, false) +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_bw_startup, false) QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_disable_reno_coexistence, false) QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_fewer_startup_round_trips, false) QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_use_bytes_delivered, false)