When true, the B204 connection option reduces the MaxAckHeight filter's extra acked when MaxBW increases and B205 causes BBRv2 to include extra acked in STARTUP's CWND. Protected by quic_reloadable_flag_quic_bbr2_startup_extra_acked. PiperOrigin-RevId: 400933672
diff --git a/quic/core/congestion_control/bandwidth_sampler.cc b/quic/core/congestion_control/bandwidth_sampler.cc index 49f2b72..240e9dd 100644 --- a/quic/core/congestion_control/bandwidth_sampler.cc +++ b/quic/core/congestion_control/bandwidth_sampler.cc
@@ -24,12 +24,40 @@ } QuicByteCount MaxAckHeightTracker::Update( - QuicBandwidth bandwidth_estimate, QuicRoundTripCount round_trip_count, + QuicBandwidth bandwidth_estimate, bool is_new_max_bandwidth, + QuicRoundTripCount round_trip_count, QuicPacketNumber last_sent_packet_number, QuicPacketNumber last_acked_packet_number, QuicTime ack_time, QuicByteCount bytes_acked) { bool force_new_epoch = false; + if (reduce_extra_acked_on_bandwidth_increase_ && is_new_max_bandwidth) { + // Save and clear existing entries. + ExtraAckedEvent best = max_ack_height_filter_.GetBest(); + ExtraAckedEvent second_best = max_ack_height_filter_.GetSecondBest(); + ExtraAckedEvent third_best = max_ack_height_filter_.GetThirdBest(); + max_ack_height_filter_.Clear(); + + // Reinsert the heights into the filter after recalculating. + QuicByteCount expected_bytes_acked = bandwidth_estimate * best.time_delta; + if (expected_bytes_acked < best.bytes_acked) { + best.extra_acked = best.bytes_acked - expected_bytes_acked; + max_ack_height_filter_.Update(best, best.round); + } + expected_bytes_acked = bandwidth_estimate * second_best.time_delta; + if (expected_bytes_acked < second_best.bytes_acked) { + QUICHE_DCHECK_LE(best.round, second_best.round); + second_best.extra_acked = second_best.bytes_acked - expected_bytes_acked; + max_ack_height_filter_.Update(second_best, second_best.round); + } + expected_bytes_acked = bandwidth_estimate * third_best.time_delta; + if (expected_bytes_acked < third_best.bytes_acked) { + QUICHE_DCHECK_LE(second_best.round, third_best.round); + third_best.extra_acked = third_best.bytes_acked - expected_bytes_acked; + max_ack_height_filter_.Update(third_best, third_best.round); + } + } + // If any packet sent after the start of the epoch has been acked, start a new // epoch. if (start_new_aggregation_epoch_after_full_round_ && @@ -42,6 +70,11 @@ "last_sent_packet_number_before_epoch_:" << last_sent_packet_number_before_epoch_ << ", last_acked_packet_number:" << last_acked_packet_number; + if (reduce_extra_acked_on_bandwidth_increase_) { + QUIC_BUG(quic_bwsampler_46) + << "A full round of aggregation should never " + << "pass with startup_include_extra_acked(B204) enabled."; + } force_new_epoch = true; } if (aggregation_epoch_start_time_ == QuicTime::Zero() || force_new_epoch) { @@ -54,8 +87,8 @@ // Compute how many bytes are expected to be delivered, assuming max bandwidth // is correct. - QuicByteCount expected_bytes_acked = - bandwidth_estimate * (ack_time - aggregation_epoch_start_time_); + QuicTime::Delta aggregation_delta = ack_time - aggregation_epoch_start_time_; + QuicByteCount expected_bytes_acked = bandwidth_estimate * aggregation_delta; // Reset the current aggregation epoch as soon as the ack arrival rate is less // than or equal to the max bandwidth. if (aggregation_epoch_bytes_ <= @@ -68,8 +101,7 @@ << ack_aggregation_bandwidth_threshold_ << ", expected_bytes_acked:" << expected_bytes_acked << ", bandwidth_estimate:" << bandwidth_estimate - << ", aggregation_duration:" - << (ack_time - aggregation_epoch_start_time_) + << ", aggregation_duration:" << aggregation_delta << ", new_aggregation_epoch:" << ack_time << ", new_aggregation_bytes_acked:" << bytes_acked; // Reset to start measuring a new aggregation epoch. @@ -92,7 +124,11 @@ << ", expected_bytes_acked:" << expected_bytes_acked << ", aggregation_epoch_bytes_:" << aggregation_epoch_bytes_ << ", extra_bytes_acked:" << extra_bytes_acked; - max_ack_height_filter_.Update(extra_bytes_acked, round_trip_count); + ExtraAckedEvent new_event; + new_event.extra_acked = extra_bytes_acked; + new_event.bytes_acked = aggregation_epoch_bytes_; + new_event.time_delta = aggregation_delta; + max_ack_height_filter_.Update(new_event, round_trip_count); return extra_bytes_acked; } @@ -309,18 +345,21 @@ : last_acked_packet_send_state; } + bool is_new_max_bandwidth = event_sample.sample_max_bandwidth > max_bandwidth; max_bandwidth = std::max(max_bandwidth, event_sample.sample_max_bandwidth); if (limit_max_ack_height_tracker_by_send_rate_) { max_bandwidth = std::max(max_bandwidth, max_send_rate); } - event_sample.extra_acked = OnAckEventEnd( - std::min(est_bandwidth_upper_bound, max_bandwidth), round_trip_count); + // TODO(ianswett): Why is the min being passed in here? + event_sample.extra_acked = + OnAckEventEnd(std::min(est_bandwidth_upper_bound, max_bandwidth), + is_new_max_bandwidth, round_trip_count); return event_sample; } QuicByteCount BandwidthSampler::OnAckEventEnd( - QuicBandwidth bandwidth_estimate, + QuicBandwidth bandwidth_estimate, bool is_new_max_bandwidth, QuicRoundTripCount round_trip_count) { const QuicByteCount newly_acked_bytes = total_bytes_acked_ - total_bytes_acked_after_last_ack_event_; @@ -329,10 +368,10 @@ return 0; } total_bytes_acked_after_last_ack_event_ = total_bytes_acked_; - QuicByteCount extra_acked = max_ack_height_tracker_.Update( - bandwidth_estimate, round_trip_count, last_sent_packet_, - last_acked_packet_, last_acked_packet_ack_time_, newly_acked_bytes); + bandwidth_estimate, is_new_max_bandwidth, round_trip_count, + last_sent_packet_, last_acked_packet_, last_acked_packet_ack_time_, + newly_acked_bytes); // If |extra_acked| is zero, i.e. this ack event marks the start of a new ack // aggregation epoch, save LessRecentPoint, which is the last ack point of the // previous epoch, as a A0 candidate.
diff --git a/quic/core/congestion_control/bandwidth_sampler.h b/quic/core/congestion_control/bandwidth_sampler.h index bef8250..8145717 100644 --- a/quic/core/congestion_control/bandwidth_sampler.h +++ b/quic/core/congestion_control/bandwidth_sampler.h
@@ -78,6 +78,24 @@ QuicByteCount bytes_in_flight; }; +struct QUIC_NO_EXPORT ExtraAckedEvent { + // The excess bytes acknowlwedged in the time delta for this event. + QuicByteCount extra_acked = 0; + + // The bytes acknowledged and time delta from the event. + QuicByteCount bytes_acked = 0; + QuicTime::Delta time_delta = QuicTime::Delta::Zero(); + // The round trip of the event. + QuicRoundTripCount round = 0; + + inline bool operator>=(const ExtraAckedEvent& other) const { + return extra_acked >= other.extra_acked; + } + inline bool operator==(const ExtraAckedEvent& other) const { + return extra_acked == other.extra_acked; + } +}; + struct QUIC_EXPORT_PRIVATE BandwidthSample { // The bandwidth at that particular sample. Zero if no valid bandwidth sample // is available. @@ -100,11 +118,14 @@ class QUIC_EXPORT_PRIVATE MaxAckHeightTracker { public: explicit MaxAckHeightTracker(QuicRoundTripCount initial_filter_window) - : max_ack_height_filter_(initial_filter_window, 0, 0) {} + : max_ack_height_filter_(initial_filter_window, ExtraAckedEvent(), 0) {} - QuicByteCount Get() const { return max_ack_height_filter_.GetBest(); } + QuicByteCount Get() const { + return max_ack_height_filter_.GetBest().extra_acked; + } QuicByteCount Update(QuicBandwidth bandwidth_estimate, + bool is_new_max_bandwidth, QuicRoundTripCount round_trip_count, QuicPacketNumber last_sent_packet_number, QuicPacketNumber last_acked_packet_number, @@ -115,7 +136,10 @@ } void Reset(QuicByteCount new_height, QuicRoundTripCount new_time) { - max_ack_height_filter_.Reset(new_height, new_time); + ExtraAckedEvent new_event; + new_event.extra_acked = new_height; + new_event.round = new_time; + max_ack_height_filter_.Reset(new_event, new_time); } void SetAckAggregationBandwidthThreshold(double threshold) { @@ -126,6 +150,10 @@ start_new_aggregation_epoch_after_full_round_ = value; } + void SetReduceExtraAckedOnBandwidthIncrease(bool value) { + reduce_extra_acked_on_bandwidth_increase_ = value; + } + double ack_aggregation_bandwidth_threshold() const { return ack_aggregation_bandwidth_threshold_; } @@ -137,10 +165,9 @@ private: // Tracks the maximum number of bytes acked faster than the estimated // bandwidth. - using MaxAckHeightFilter = WindowedFilter<QuicByteCount, - MaxFilter<QuicByteCount>, - QuicRoundTripCount, - QuicRoundTripCount>; + using MaxAckHeightFilter = + WindowedFilter<ExtraAckedEvent, MaxFilter<ExtraAckedEvent>, + QuicRoundTripCount, QuicRoundTripCount>; MaxAckHeightFilter max_ack_height_filter_; // The time this aggregation started and the number of bytes acked during it. @@ -154,6 +181,7 @@ double ack_aggregation_bandwidth_threshold_ = GetQuicFlag(FLAGS_quic_ack_aggregation_bandwidth_threshold); bool start_new_aggregation_epoch_after_full_round_ = false; + bool reduce_extra_acked_on_bandwidth_increase_ = false; }; // An interface common to any class that can provide bandwidth samples from the @@ -335,6 +363,7 @@ QuicBandwidth est_bandwidth_upper_bound, QuicRoundTripCount round_trip_count) override; QuicByteCount OnAckEventEnd(QuicBandwidth bandwidth_estimate, + bool is_new_max_bandwidth, QuicRoundTripCount round_trip_count); void OnAppLimited() override; @@ -373,6 +402,10 @@ limit_max_ack_height_tracker_by_send_rate_ = value; } + void SetReduceExtraAckedOnBandwidthIncrease(bool value) { + max_ack_height_tracker_.SetReduceExtraAckedOnBandwidthIncrease(value); + } + // AckPoint represents a point on the ack line. struct QUIC_NO_EXPORT AckPoint { QuicTime ack_time = QuicTime::Zero();
diff --git a/quic/core/congestion_control/bandwidth_sampler_test.cc b/quic/core/congestion_control/bandwidth_sampler_test.cc index a371079..0e0dac4 100644 --- a/quic/core/congestion_control/bandwidth_sampler_test.cc +++ b/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -756,7 +756,7 @@ for (QuicByteCount bytes = 0; bytes < aggregation_bytes; bytes += bytes_per_ack) { QuicByteCount extra_acked = tracker_.Update( - bandwidth_, RoundTripCount(), last_sent_packet_number_, + bandwidth_, true, RoundTripCount(), last_sent_packet_number_, last_acked_packet_number_, now_, bytes_per_ack); QUIC_VLOG(1) << "T" << now_ << ": Update after " << bytes_per_ack << " bytes acked, " << extra_acked << " extra bytes acked"; @@ -882,8 +882,9 @@ // Update with a tiny bandwidth causes a very low expected bytes acked, which // in turn causes the current epoch to continue if the |tracker_| doesn't // check the packet numbers. - tracker_.Update(bandwidth_ * 0.1, RoundTripCount(), last_sent_packet_number_, - last_acked_packet_number_, now_, 100); + tracker_.Update(bandwidth_ * 0.1, true, RoundTripCount(), + last_sent_packet_number_, last_acked_packet_number_, now_, + 100); if (GetQuicReloadableFlag( quic_bbr_start_new_aggregation_epoch_after_a_full_round)) {
diff --git a/quic/core/congestion_control/bbr2_misc.h b/quic/core/congestion_control/bbr2_misc.h index a603064..d017b55 100644 --- a/quic/core/congestion_control/bbr2_misc.h +++ b/quic/core/congestion_control/bbr2_misc.h
@@ -95,6 +95,10 @@ // If false, exit STARTUP on loss only if bandwidth is below threshold. bool always_exit_startup_on_excess_loss = false; + // If true, inclue extra acked during STARTUP and proactively reduce extra + // acked when bandwidth increases. + bool startup_include_extra_acked = false; + /* * DRAIN parameters. */ @@ -431,6 +435,10 @@ bandwidth_sampler_.SetMaxAckHeightTrackerWindowLength(value); } + void SetReduceExtraAckedOnBandwidthIncrease(bool value) { + bandwidth_sampler_.SetReduceExtraAckedOnBandwidthIncrease(value); + } + bool MaybeExpireMinRtt(const Bbr2CongestionEvent& congestion_event); QuicBandwidth BandwidthEstimate() const {
diff --git a/quic/core/congestion_control/bbr2_sender.cc b/quic/core/congestion_control/bbr2_sender.cc index bddb06a..1e27649 100644 --- a/quic/core/congestion_control/bbr2_sender.cc +++ b/quic/core/congestion_control/bbr2_sender.cc
@@ -175,6 +175,25 @@ quic_bbr2_check_cwnd_limited_before_aggregation_epoch); params_.probe_bw_check_cwnd_limited_before_aggregation_epoch = true; } + if (GetQuicReloadableFlag(quic_bbr2_no_probe_up_exit_if_no_queue) && + ContainsQuicTag(connection_options, kB202)) { + params_.probe_up_dont_exit_if_no_queue_ = true; + } + if (GetQuicReloadableFlag(quic_bbr2_ignore_inflight_hi_in_probe_up) && + ContainsQuicTag(connection_options, kB203)) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_hi_in_probe_up); + params_.probe_up_ignore_inflight_hi = true; + } + if (GetQuicReloadableFlag(quic_bbr2_startup_extra_acked) && + ContainsQuicTag(connection_options, kB204)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_startup_extra_acked, 1, 2); + model_.SetReduceExtraAckedOnBandwidthIncrease(true); + } + if (GetQuicReloadableFlag(quic_bbr2_startup_extra_acked) && + ContainsQuicTag(connection_options, kB205)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_startup_extra_acked, 2, 2); + params_.startup_include_extra_acked = true; + } if (GetQuicReloadableFlag( quic_bbr_start_new_aggregation_epoch_after_a_full_round) && ContainsQuicTag(connection_options, kBBRA)) { @@ -191,15 +210,6 @@ ContainsQuicTag(connection_options, kBBQ0)) { params_.probe_up_includes_acks_after_cwnd_limited = true; } - if (GetQuicReloadableFlag(quic_bbr2_no_probe_up_exit_if_no_queue) && - ContainsQuicTag(connection_options, kB202)) { - params_.probe_up_dont_exit_if_no_queue_ = true; - } - if (GetQuicReloadableFlag(quic_bbr2_ignore_inflight_hi_in_probe_up) && - ContainsQuicTag(connection_options, kB203)) { - QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_ignore_inflight_hi_in_probe_up); - params_.probe_up_ignore_inflight_hi = true; - } if (GetQuicReloadableFlag(quic_bbr2_startup_probe_up_loss_events) && ContainsQuicTag(connection_options, kB206)) { @@ -392,7 +402,7 @@ QuicByteCount target_cwnd = GetTargetCongestionWindow(model_.cwnd_gain()); const QuicByteCount prior_cwnd = cwnd_; - if (model_.full_bandwidth_reached()) { + if (model_.full_bandwidth_reached() || Params().startup_include_extra_acked) { target_cwnd += model_.MaxAckHeight(); cwnd_ = std::min(prior_cwnd + bytes_acked, target_cwnd); } else if (prior_cwnd < target_cwnd || prior_cwnd < 2 * initial_cwnd_) {
diff --git a/quic/core/congestion_control/bbr2_simulator_test.cc b/quic/core/congestion_control/bbr2_simulator_test.cc index 18a9829..4b59a55 100644 --- a/quic/core/congestion_control/bbr2_simulator_test.cc +++ b/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -921,6 +921,150 @@ sender_->ExportDebugState().bandwidth_hi, 0.91f); } +// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B204 +TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseB204)) { + SetQuicReloadableFlag(quic_bbr2_startup_extra_acked, true); + SetConnectionOption(kB204); + DefaultTopologyParams params; + params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000); + params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100); + CreateNetwork(params); + + sender_endpoint_.AddBytesToTransfer(10 * 1024 * 1024); + + simulator_.RunFor(QuicTime::Delta::FromSeconds(15)); + EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT})); + QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow(); + + EXPECT_APPROX_EQ(params.test_link.bandwidth, + sender_->ExportDebugState().bandwidth_est, 0.1f); + EXPECT_LE(sender_loss_rate_in_packets(), 0.25); + + // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps. + params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000); + TestLink()->set_bandwidth(params.test_link.bandwidth); + + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_endpoint_.bytes_to_transfer() == 0; }, + QuicTime::Delta::FromSeconds(50)); + EXPECT_TRUE(simulator_result); + // Ensure the full bandwidth is discovered. + EXPECT_APPROX_EQ(params.test_link.bandwidth, + sender_->ExportDebugState().bandwidth_hi, 0.02f); +} + +// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B204 +// in the presence of ACK aggregation. +TEST_F(Bbr2DefaultTopologyTest, + QUIC_SLOW_TEST(BandwidthIncreaseB204Aggregation)) { + SetQuicReloadableFlag(quic_bbr2_startup_extra_acked, true); + SetConnectionOption(kB204); + DefaultTopologyParams params; + params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000); + params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100); + CreateNetwork(params); + + // 2 RTTs of aggregation, with a max of 10kb. + EnableAggregation(10 * 1024, 2 * params.RTT()); + + // Reduce the payload to 2MB because 10MB takes too long. + sender_endpoint_.AddBytesToTransfer(2 * 1024 * 1024); + + simulator_.RunFor(QuicTime::Delta::FromSeconds(15)); + EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT})); + QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow(); + + // This is much farther off when aggregation is present, + // Ideally BSAO or another option would fix this. + EXPECT_APPROX_EQ(params.test_link.bandwidth, + sender_->ExportDebugState().bandwidth_est, 0.50f); + EXPECT_LE(sender_loss_rate_in_packets(), 0.35); + + // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps. + params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000); + TestLink()->set_bandwidth(params.test_link.bandwidth); + + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_endpoint_.bytes_to_transfer() == 0; }, + QuicTime::Delta::FromSeconds(50)); + EXPECT_TRUE(simulator_result); + // Ensure at least 10% of full bandwidth is discovered. + EXPECT_APPROX_EQ(params.test_link.bandwidth, + sender_->ExportDebugState().bandwidth_hi, 0.95f); +} + +// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B205 +TEST_F(Bbr2DefaultTopologyTest, QUIC_SLOW_TEST(BandwidthIncreaseB205)) { + SetQuicReloadableFlag(quic_bbr2_startup_extra_acked, true); + SetConnectionOption(kB205); + DefaultTopologyParams params; + params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000); + params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100); + CreateNetwork(params); + + sender_endpoint_.AddBytesToTransfer(10 * 1024 * 1024); + + simulator_.RunFor(QuicTime::Delta::FromSeconds(15)); + EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT})); + QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow(); + + EXPECT_APPROX_EQ(params.test_link.bandwidth, + sender_->ExportDebugState().bandwidth_est, 0.1f); + EXPECT_LE(sender_loss_rate_in_packets(), 0.10); + + // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps. + params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000); + TestLink()->set_bandwidth(params.test_link.bandwidth); + + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_endpoint_.bytes_to_transfer() == 0; }, + QuicTime::Delta::FromSeconds(50)); + EXPECT_TRUE(simulator_result); + // Ensure the full bandwidth is discovered. + EXPECT_APPROX_EQ(params.test_link.bandwidth, + sender_->ExportDebugState().bandwidth_hi, 0.1f); +} + +// Test Bbr2's reaction to a 100x bandwidth increase during a transfer with B205 +// in the presence of ACK aggregation. +TEST_F(Bbr2DefaultTopologyTest, + QUIC_SLOW_TEST(BandwidthIncreaseB205Aggregation)) { + SetQuicReloadableFlag(quic_bbr2_startup_extra_acked, true); + SetConnectionOption(kB205); + DefaultTopologyParams params; + params.local_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(15000); + params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(100); + CreateNetwork(params); + + // 2 RTTs of aggregation, with a max of 10kb. + EnableAggregation(10 * 1024, 2 * params.RTT()); + + // Reduce the payload to 2MB because 10MB takes too long. + sender_endpoint_.AddBytesToTransfer(2 * 1024 * 1024); + + simulator_.RunFor(QuicTime::Delta::FromSeconds(15)); + EXPECT_TRUE(Bbr2ModeIsOneOf({Bbr2Mode::PROBE_BW, Bbr2Mode::PROBE_RTT})); + QUIC_LOG(INFO) << "Bandwidth increasing at time " << SimulatedNow(); + + // This is much farther off when aggregation is present, + // Ideally BSAO or another option would fix this. + EXPECT_APPROX_EQ(params.test_link.bandwidth, + sender_->ExportDebugState().bandwidth_est, 0.45f); + EXPECT_LE(sender_loss_rate_in_packets(), 0.15); + + // Now increase the bottleneck bandwidth from 100Kbps to 10Mbps. + params.test_link.bandwidth = QuicBandwidth::FromKBitsPerSecond(10000); + TestLink()->set_bandwidth(params.test_link.bandwidth); + + bool simulator_result = simulator_.RunUntilOrTimeout( + [this]() { return sender_endpoint_.bytes_to_transfer() == 0; }, + QuicTime::Delta::FromSeconds(50)); + EXPECT_TRUE(simulator_result); + // Ensure at least 5% of full bandwidth is discovered. + EXPECT_APPROX_EQ(params.test_link.bandwidth, + sender_->ExportDebugState().bandwidth_hi, 0.9f); +} + // Test the number of losses incurred by the startup phase in a situation when // the buffer is less than BDP. TEST_F(Bbr2DefaultTopologyTest, PacketLossOnSmallBufferStartup) {
diff --git a/quic/core/congestion_control/windowed_filter.h b/quic/core/congestion_control/windowed_filter.h index 8949a9c..a777ac5 100644 --- a/quic/core/congestion_control/windowed_filter.h +++ b/quic/core/congestion_control/windowed_filter.h
@@ -71,6 +71,7 @@ WindowedFilter(TimeDeltaT window_length, T zero_value, TimeT zero_time) : window_length_(window_length), zero_value_(zero_value), + zero_time_(zero_time), estimates_{Sample(zero_value_, zero_time), Sample(zero_value_, zero_time), Sample(zero_value_, zero_time)} {} @@ -138,6 +139,8 @@ Sample(new_sample, new_time); } + void Clear() { Reset(zero_value_, zero_time_); } + T GetBest() const { return estimates_[0].sample; } T GetSecondBest() const { return estimates_[1].sample; } T GetThirdBest() const { return estimates_[2].sample; } @@ -152,6 +155,7 @@ TimeDeltaT window_length_; // Time length of window. T zero_value_; // Uninitialized value of T. + TimeT zero_time_; // Uninitialized value of TimeT. Sample estimates_[3]; // Best estimate is element 0. };
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index ed6bdae..f0bcd7f 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -166,6 +166,10 @@ const QuicTag kB203 = TAG('B', '2', '0', '3'); // Ignore inflight_hi until // PROBE_UP is exited. const QuicTag kB206 = TAG('B', '2', '0', '6'); // Exit STARTUP after 2 losses. +const QuicTag kB204 = TAG('B', '2', '0', '4'); // Reduce extra acked when + // MaxBW incrases. +const QuicTag kB205 = TAG('B', '2', '0', '5'); // Add extra acked to CWND in + // STARTUP. const QuicTag kNTLP = TAG('N', 'T', 'L', 'P'); // No tail loss probe const QuicTag k1TLP = TAG('1', 'T', 'L', 'P'); // 1 tail loss probe const QuicTag k1RTO = TAG('1', 'R', 'T', 'O'); // Send 1 packet upon RTO
diff --git a/quic/core/quic_flags_list.h b/quic/core/quic_flags_list.h index 205ac02..acbe982 100644 --- a/quic/core/quic_flags_list.h +++ b/quic/core/quic_flags_list.h
@@ -131,6 +131,8 @@ QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_unified_iw_options, true) // When true, the B203 connection option causes the Bbr2Sender to ignore inflight_hi during PROBE_UP and increase it when the bytes delivered without loss are higher. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_ignore_inflight_hi_in_probe_up, true) +// When true, the B204 connection option enables extra acked in STARTUP, but also adds new logic to decrease it whenever max bandwidth increases. +QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_startup_extra_acked, true) // When true, the BBQ0 connection option causes QUIC BBR2 to add bytes_acked to probe_up_acked if the connection hasn\'t been app-limited since inflight_hi was utilized. QUIC_FLAG(FLAGS_quic_reloadable_flag_quic_bbr2_add_bytes_acked_after_inflight_hi_limited, true) // When true, the BBR4 copt sets the extra_acked window to 20 RTTs and BBR5 sets it to 40 RTTs.