Commit 05b1c638 authored by Ian Swett's avatar Ian Swett Committed by Commit Bot

Reduce the sending rate of QUIC BBR as the connection observes more packets...

Reduce the sending rate of QUIC BBR as the connection observes more packets lost.  Protected by FLAGS_quic_reloadable_flag_quic_bbr_startup_rate_reduction.

Merge internal cls: 218417489 and 220238389

R=rch@chromium.org

Change-Id: I246bc6894f4c67cf6b86a759905a720222453277
Reviewed-on: https://chromium-review.googlesource.com/c/1335878
Commit-Queue: Ryan Hamilton <rch@chromium.org>
Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609353}
parent 08f74b8d
......@@ -310,3 +310,9 @@ QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_fix_spurious_ack_alarm, false)
// If true, QuicSpdyStream::WritevBody() will convert iovs into QuicMemSliceSpan
// and call WriteMemSlices instead.
QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_call_write_mem_slices, false)
// If true, enables the BBS4 and BBS5 connection options, which reduce BBR's
// pacing rate in STARTUP as more losses occur as a fraction of CWND.
QUIC_FLAG(bool,
FLAGS_quic_reloadable_flag_quic_bbr_startup_rate_reduction,
false)
......@@ -127,6 +127,8 @@ BbrSender::BbrSender(const RttStats* rtt_stats,
is_app_limited_recovery_(false),
slower_startup_(false),
rate_based_startup_(false),
startup_rate_reduction_multiplier_(0),
startup_bytes_lost_(0),
initial_conservation_in_startup_(CONSERVATION),
enable_ack_aggregation_during_startup_(false),
expire_ack_aggregation_in_startup_(false),
......@@ -267,6 +269,18 @@ void BbrSender::SetFromConfig(const QuicConfig& config,
if (config.HasClientRequestedIndependentOption(kBBS3, perspective)) {
initial_conservation_in_startup_ = GROWTH;
}
if (GetQuicReloadableFlag(quic_bbr_startup_rate_reduction) &&
config.HasClientRequestedIndependentOption(kBBS4, perspective)) {
rate_based_startup_ = true;
// Hits 1.25x pacing multiplier when ~2/3 CWND is lost.
startup_rate_reduction_multiplier_ = 1;
}
if (GetQuicReloadableFlag(quic_bbr_startup_rate_reduction) &&
config.HasClientRequestedIndependentOption(kBBS5, perspective)) {
rate_based_startup_ = true;
// Hits 1.25x pacing multiplier when ~1/3 CWND is lost.
startup_rate_reduction_multiplier_ = 2;
}
if (config.HasClientRequestedIndependentOption(kBBR4, perspective)) {
max_ack_height_.SetWindowLength(2 * kBandwidthWindowSize);
}
......@@ -446,6 +460,9 @@ void BbrSender::EnterProbeBandwidthMode(QuicTime now) {
void BbrSender::DiscardLostPackets(const LostPacketVector& lost_packets) {
for (const LostPacket& packet : lost_packets) {
sampler_.OnPacketLost(packet.packet_number);
if (startup_rate_reduction_multiplier_ != 0 && mode_ == STARTUP) {
startup_bytes_lost_ += packet.bytes_lost;
}
}
}
......@@ -749,7 +766,23 @@ void BbrSender::CalculatePacingRate() {
return;
}
// Do not decrease the pacing rate during the startup.
// Slow the pacing rate in STARTUP by the bytes_lost / CWND.
if (startup_rate_reduction_multiplier_ != 0 && has_ever_detected_loss &&
has_non_app_limited_sample_) {
if (startup_bytes_lost_ > congestion_window_) {
pacing_rate_ = BandwidthEstimate();
} else {
pacing_rate_ =
(1 - (startup_bytes_lost_ * startup_rate_reduction_multiplier_ *
1.0f / congestion_window_)) *
target_rate;
// Ensure the pacing rate doesn't drop below the bandwidth estimate.
pacing_rate_ = std::max(pacing_rate_, BandwidthEstimate());
}
return;
}
// Do not decrease the pacing rate during startup.
pacing_rate_ = std::max(pacing_rate_, target_rate);
}
......
......@@ -369,6 +369,12 @@ class QUIC_EXPORT_PRIVATE BbrSender : public SendAlgorithmInterface {
bool slower_startup_;
// When true, disables packet conservation in STARTUP.
bool rate_based_startup_;
// When non-zero, decreases the rate in STARTUP by the total number of bytes
// lost in STARTUP divided by CWND.
uint8_t startup_rate_reduction_multiplier_;
// Sum of bytes lost in STARTUP.
QuicByteCount startup_bytes_lost_;
// Used as the initial packet conservation mode when first entering recovery.
RecoveryState initial_conservation_in_startup_;
// When true, add the most recent ack aggregation measurement during STARTUP.
......
......@@ -1152,6 +1152,106 @@ TEST_F(BbrSenderTest, SimpleTransferNoConservationInStartup) {
EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited);
}
// Ensures no change in congestion window in STARTUP after loss, but that the
// rate decreases.
TEST_F(BbrSenderTest, SimpleTransferStartupRateReduction) {
SetQuicReloadableFlag(quic_bbr_startup_rate_reduction, true);
CreateSmallBufferSetup();
SetConnectionOption(kBBS4);
// Run until the full bandwidth is reached and check how many rounds it was.
bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024);
bool used_conservation_cwnd = false;
bool simulator_result = simulator_.RunUntilOrTimeout(
[this, &used_conservation_cwnd]() {
if (!sender_->ExportDebugState().is_at_full_bandwidth &&
sender_->GetCongestionWindow() <
sender_->ExportDebugState().congestion_window) {
used_conservation_cwnd = true;
}
// Exit once a loss is hit.
return bbr_sender_.connection()->GetStats().packets_lost > 0 ||
sender_->ExportDebugState().is_at_full_bandwidth;
},
QuicTime::Delta::FromSeconds(5));
ASSERT_TRUE(simulator_result);
EXPECT_TRUE(sender_->InRecovery());
EXPECT_FALSE(used_conservation_cwnd);
EXPECT_EQ(BbrSender::STARTUP, sender_->ExportDebugState().mode);
EXPECT_NE(0u, bbr_sender_.connection()->GetStats().packets_lost);
// Lose each outstanding packet and the pacing rate decreases.
const QuicBandwidth original_pacing_rate = sender_->PacingRate(0);
QuicBandwidth pacing_rate = original_pacing_rate;
const QuicByteCount original_cwnd = sender_->GetCongestionWindow();
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(0, kMaxPacketSize));
QuicPacketNumber largest_sent =
bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket();
for (QuicPacketNumber packet_number =
bbr_sender_.connection()->sent_packet_manager().GetLeastUnacked();
packet_number <= largest_sent; ++packet_number) {
lost_packets[0].packet_number = packet_number;
sender_->OnCongestionEvent(false, 0, clock_->Now(), {}, lost_packets);
EXPECT_EQ(original_cwnd, sender_->GetCongestionWindow());
EXPECT_GT(original_pacing_rate, sender_->PacingRate(0));
EXPECT_GE(pacing_rate, sender_->PacingRate(0));
EXPECT_LE(sender_->BandwidthEstimate(), sender_->PacingRate(0));
pacing_rate = sender_->PacingRate(0);
}
}
// Ensures no change in congestion window in STARTUP after loss, but that the
// rate decreases twice as fast as BBS4.
TEST_F(BbrSenderTest, SimpleTransferDoubleStartupRateReduction) {
SetQuicReloadableFlag(quic_bbr_startup_rate_reduction, true);
CreateSmallBufferSetup();
SetConnectionOption(kBBS5);
// Run until the full bandwidth is reached and check how many rounds it was.
bbr_sender_.AddBytesToTransfer(12 * 1024 * 1024);
bool used_conservation_cwnd = false;
bool simulator_result = simulator_.RunUntilOrTimeout(
[this, &used_conservation_cwnd]() {
if (!sender_->ExportDebugState().is_at_full_bandwidth &&
sender_->GetCongestionWindow() <
sender_->ExportDebugState().congestion_window) {
used_conservation_cwnd = true;
}
// Exit once a loss is hit.
return bbr_sender_.connection()->GetStats().packets_lost > 0 ||
sender_->ExportDebugState().is_at_full_bandwidth;
},
QuicTime::Delta::FromSeconds(5));
ASSERT_TRUE(simulator_result);
EXPECT_TRUE(sender_->InRecovery());
EXPECT_FALSE(used_conservation_cwnd);
EXPECT_EQ(BbrSender::STARTUP, sender_->ExportDebugState().mode);
EXPECT_NE(0u, bbr_sender_.connection()->GetStats().packets_lost);
// Lose each outstanding packet and the pacing rate decreases.
const QuicBandwidth original_pacing_rate = sender_->PacingRate(0);
QuicBandwidth pacing_rate = original_pacing_rate;
const QuicByteCount original_cwnd = sender_->GetCongestionWindow();
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(0, kMaxPacketSize));
QuicPacketNumber largest_sent =
bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket();
for (QuicPacketNumber packet_number =
bbr_sender_.connection()->sent_packet_manager().GetLeastUnacked();
packet_number <= largest_sent; ++packet_number) {
lost_packets[0].packet_number = packet_number;
sender_->OnCongestionEvent(false, 0, clock_->Now(), {}, lost_packets);
EXPECT_EQ(original_cwnd, sender_->GetCongestionWindow());
EXPECT_GT(original_pacing_rate, sender_->PacingRate(0));
EXPECT_GE(pacing_rate, sender_->PacingRate(0));
EXPECT_LE(sender_->BandwidthEstimate(), sender_->PacingRate(0));
pacing_rate = sender_->PacingRate(0);
}
}
TEST_F(BbrSenderTest, DerivedPacingGainStartup) {
SetQuicReloadableFlag(quic_bbr_slower_startup3, true);
CreateDefaultSetup();
......
......@@ -86,6 +86,10 @@ const QuicTag kBBS2 = TAG('B', 'B', 'S', '2'); // More aggressive packet
// conservation in BBR STARTUP
const QuicTag kBBS3 = TAG('B', 'B', 'S', '3'); // Slowstart packet
// conservation in BBR STARTUP
const QuicTag kBBS4 = TAG('B', 'B', 'S', '4'); // Reduce rate in STARTUP by
// bytes_lost / CWND.
const QuicTag kBBS5 = TAG('B', 'B', 'S', '5'); // Reduce rate in STARTUP by
// 2 * bytes_lost / CWND.
const QuicTag kBBRR = TAG('B', 'B', 'R', 'R'); // Rate-based recovery in BBR
const QuicTag kBBR1 = TAG('B', 'B', 'R', '1'); // DEPRECATED
const QuicTag kBBR2 = TAG('B', 'B', 'R', '2'); // DEPRECATED
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment