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)