gfe-relnote: For QUIC BBR/BBRv2, move max ack height tracking to BandwidthSampler. BBR change protected by --gfe2_reloadable_flag_quic_track_ack_height_in_bandwidth_sampler. BBRv2 protected by existing --gfe2_reloadable_flag_quic_default_to_bbr_v2.
PiperOrigin-RevId: 262018910
Change-Id: I392d82737a85bdf7de6de5918f0b9ea43a653329
diff --git a/quic/core/congestion_control/bandwidth_sampler.cc b/quic/core/congestion_control/bandwidth_sampler.cc
index 11a625c..39c7051 100644
--- a/quic/core/congestion_control/bandwidth_sampler.cc
+++ b/quic/core/congestion_control/bandwidth_sampler.cc
@@ -6,13 +6,42 @@
#include <algorithm>
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.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 {
-BandwidthSampler::BandwidthSampler()
+
+QuicByteCount MaxAckHeightTracker::Update(QuicBandwidth bandwidth_estimate,
+ QuicRoundTripCount round_trip_count,
+ QuicTime ack_time,
+ QuicByteCount bytes_acked) {
+ // 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_);
+ // 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_ <= expected_bytes_acked) {
+ // Reset to start measuring a new aggregation epoch.
+ aggregation_epoch_bytes_ = bytes_acked;
+ aggregation_epoch_start_time_ = ack_time;
+ return 0;
+ }
+
+ aggregation_epoch_bytes_ += bytes_acked;
+
+ // Compute how many extra bytes were delivered vs max bandwidth.
+ QuicByteCount extra_bytes_acked =
+ aggregation_epoch_bytes_ - expected_bytes_acked;
+ max_ack_height_filter_.Update(extra_bytes_acked, round_trip_count);
+ return extra_bytes_acked;
+}
+
+BandwidthSampler::BandwidthSampler(
+ QuicRoundTripCount max_height_tracker_window_length)
: total_bytes_sent_(0),
total_bytes_acked_(0),
total_bytes_lost_(0),
@@ -21,7 +50,9 @@
last_acked_packet_ack_time_(QuicTime::Zero()),
is_app_limited_(false),
connection_state_map_(),
- max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)) {}
+ max_tracked_packets_(GetQuicFlag(FLAGS_quic_max_tracked_packet_count)),
+ max_ack_height_tracker_(max_height_tracker_window_length),
+ total_bytes_acked_after_last_ack_event_(0) {}
BandwidthSampler::~BandwidthSampler() {}
@@ -69,6 +100,22 @@
"in it.";
}
+QuicByteCount BandwidthSampler::OnAckEventEnd(
+ QuicBandwidth bandwidth_estimate,
+ QuicRoundTripCount round_trip_count) {
+ const QuicByteCount newly_acked_bytes =
+ total_bytes_acked_ - total_bytes_acked_after_last_ack_event_;
+
+ if (newly_acked_bytes == 0) {
+ return 0;
+ }
+ total_bytes_acked_after_last_ack_event_ = total_bytes_acked_;
+
+ return max_ack_height_tracker_.Update(bandwidth_estimate, round_trip_count,
+ last_acked_packet_ack_time_,
+ newly_acked_bytes);
+}
+
BandwidthSample BandwidthSampler::OnPacketAcknowledged(
QuicTime ack_time,
QuicPacketNumber packet_number) {
diff --git a/quic/core/congestion_control/bandwidth_sampler.h b/quic/core/congestion_control/bandwidth_sampler.h
index 9a58cf6..6af16b7 100644
--- a/quic/core/congestion_control/bandwidth_sampler.h
+++ b/quic/core/congestion_control/bandwidth_sampler.h
@@ -5,6 +5,8 @@
#ifndef QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_
#define QUICHE_QUIC_CORE_CONGESTION_CONTROL_BANDWIDTH_SAMPLER_H_
+#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h"
#include "net/third_party/quiche/src/quic/core/packet_number_indexed_queue.h"
#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
#include "net/third_party/quiche/src/quic/core/quic_packets.h"
@@ -75,6 +77,41 @@
: bandwidth(QuicBandwidth::Zero()), rtt(QuicTime::Delta::Zero()) {}
};
+class QUIC_EXPORT_PRIVATE MaxAckHeightTracker {
+ public:
+ explicit MaxAckHeightTracker(QuicRoundTripCount initial_filter_window)
+ : max_ack_height_filter_(initial_filter_window, 0, 0) {}
+
+ QuicByteCount Get() const { return max_ack_height_filter_.GetBest(); }
+
+ QuicByteCount Update(QuicBandwidth bandwidth_estimate,
+ QuicRoundTripCount round_trip_count,
+ QuicTime ack_time,
+ QuicByteCount bytes_acked);
+
+ void SetFilterWindowLength(QuicRoundTripCount length) {
+ max_ack_height_filter_.SetWindowLength(length);
+ }
+
+ void Reset(QuicByteCount new_height, QuicRoundTripCount new_time) {
+ max_ack_height_filter_.Reset(new_height, new_time);
+ }
+
+ private:
+ // Tracks the maximum number of bytes acked faster than the estimated
+ // bandwidth.
+ typedef WindowedFilter<QuicByteCount,
+ MaxFilter<QuicByteCount>,
+ QuicRoundTripCount,
+ QuicRoundTripCount>
+ MaxAckHeightFilter;
+ MaxAckHeightFilter max_ack_height_filter_;
+
+ // The time this aggregation started and the number of bytes acked during it.
+ QuicTime aggregation_epoch_start_time_ = QuicTime::Zero();
+ QuicByteCount aggregation_epoch_bytes_ = 0;
+};
+
// An interface common to any class that can provide bandwidth samples from the
// information per individual acknowledged packet.
class QUIC_EXPORT_PRIVATE BandwidthSamplerInterface {
@@ -204,7 +241,8 @@
// connection is app-limited, the approach works in other cases too.
class QUIC_EXPORT_PRIVATE BandwidthSampler : public BandwidthSamplerInterface {
public:
- BandwidthSampler();
+ explicit BandwidthSampler(
+ QuicRoundTripCount max_height_tracker_window_length);
~BandwidthSampler() override;
void OnPacketSent(QuicTime sent_time,
@@ -214,6 +252,8 @@
HasRetransmittableData has_retransmittable_data) override;
BandwidthSample OnPacketAcknowledged(QuicTime ack_time,
QuicPacketNumber packet_number) override;
+ QuicByteCount OnAckEventEnd(QuicBandwidth bandwidth_estimate,
+ QuicRoundTripCount round_trip_count);
SendTimeState OnPacketLost(QuicPacketNumber packet_number) override;
void OnAppLimited() override;
@@ -228,6 +268,17 @@
QuicPacketNumber end_of_app_limited_phase() const override;
+ QuicByteCount max_ack_height() const { return max_ack_height_tracker_.Get(); }
+
+ void SetMaxAckHeightTrackerWindowLength(QuicRoundTripCount length) {
+ max_ack_height_tracker_.SetFilterWindowLength(length);
+ }
+
+ void ResetMaxAckHeightTracker(QuicByteCount new_height,
+ QuicRoundTripCount new_time) {
+ max_ack_height_tracker_.Reset(new_height, new_time);
+ }
+
private:
friend class test::BandwidthSamplerPeer;
@@ -333,6 +384,9 @@
QuicTime ack_time,
QuicPacketNumber packet_number,
const ConnectionStateOnSentPacket& sent_packet);
+
+ MaxAckHeightTracker max_ack_height_tracker_;
+ QuicByteCount total_bytes_acked_after_last_ack_event_;
};
} // namespace quic
diff --git a/quic/core/congestion_control/bandwidth_sampler_test.cc b/quic/core/congestion_control/bandwidth_sampler_test.cc
index 750b14e..9e36bdc 100644
--- a/quic/core/congestion_control/bandwidth_sampler_test.cc
+++ b/quic/core/congestion_control/bandwidth_sampler_test.cc
@@ -32,7 +32,8 @@
// A test fixture with utility methods for BandwidthSampler tests.
class BandwidthSamplerTest : public QuicTest {
protected:
- BandwidthSamplerTest() : bytes_in_flight_(0) {
+ BandwidthSamplerTest()
+ : sampler_(/*max_height_tracker_window_length=*/0), bytes_in_flight_(0) {
// Ensure that the clock does not start at zero.
clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
}
diff --git a/quic/core/congestion_control/bbr2_misc.cc b/quic/core/congestion_control/bbr2_misc.cc
index 56e7270..e2fc8f0 100644
--- a/quic/core/congestion_control/bbr2_misc.cc
+++ b/quic/core/congestion_control/bbr2_misc.cc
@@ -77,42 +77,14 @@
return last_acked_sample.bandwidth_sample.state_at_send;
}
-QuicByteCount Bbr2MaxAckHeightTracker::Update(
- const QuicBandwidth& bandwidth_estimate,
- QuicRoundTripCount round_trip_count,
- QuicTime ack_time,
- QuicByteCount bytes_acked) {
- // TODO(wub): Find out whether TCP adds bytes_acked before or after the check.
- aggregation_epoch_bytes_ += bytes_acked;
-
- // 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_);
- // 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_ <= expected_bytes_acked) {
- // Reset to start measuring a new aggregation epoch.
- aggregation_epoch_bytes_ = bytes_acked;
- aggregation_epoch_start_time_ = ack_time;
- return 0;
- }
-
- // Compute how many extra bytes were delivered vs max bandwidth.
- QuicByteCount extra_bytes_acked =
- aggregation_epoch_bytes_ - expected_bytes_acked;
- max_ack_height_filter_.Update(extra_bytes_acked, round_trip_count);
- return extra_bytes_acked;
-}
-
Bbr2NetworkModel::Bbr2NetworkModel(const Bbr2Params* params,
QuicTime::Delta initial_rtt,
QuicTime initial_rtt_timestamp,
float cwnd_gain,
float pacing_gain)
: params_(params),
+ bandwidth_sampler_(params->initial_max_ack_height_filter_window),
min_rtt_filter_(initial_rtt, initial_rtt_timestamp),
- max_ack_height_tracker_(params->initial_max_ack_height_filter_window),
cwnd_gain_(cwnd_gain),
pacing_gain_(pacing_gain) {}
@@ -198,8 +170,7 @@
congestion_event->bytes_lost = total_bytes_lost() - prior_bytes_lost;
bytes_lost_in_round_ += congestion_event->bytes_lost;
- max_ack_height_tracker_.Update(BandwidthEstimate(), RoundTripCount(),
- event_time, congestion_event->bytes_acked);
+ bandwidth_sampler_.OnAckEventEnd(BandwidthEstimate(), RoundTripCount());
if (!congestion_event->end_of_round_trip) {
return;
diff --git a/quic/core/congestion_control/bbr2_misc.h b/quic/core/congestion_control/bbr2_misc.h
index d38163b..303e299 100644
--- a/quic/core/congestion_control/bbr2_misc.h
+++ b/quic/core/congestion_control/bbr2_misc.h
@@ -20,8 +20,6 @@
namespace quic {
-typedef uint64_t QuicRoundTripCount;
-
template <typename T>
class QUIC_EXPORT_PRIVATE Limits {
public:
@@ -272,32 +270,6 @@
QUIC_EXPORT_PRIVATE const SendTimeState& SendStateOfLargestPacket(
const Bbr2CongestionEvent& congestion_event);
-class QUIC_EXPORT_PRIVATE Bbr2MaxAckHeightTracker {
- public:
- explicit Bbr2MaxAckHeightTracker(QuicRoundTripCount initial_filter_window)
- : max_ack_height_filter_(initial_filter_window, 0, 0) {}
-
- QuicByteCount Get() const { return max_ack_height_filter_.GetBest(); }
-
- QuicByteCount Update(const QuicBandwidth& bandwidth_estimate,
- QuicRoundTripCount round_trip_count,
- QuicTime ack_time,
- QuicByteCount bytes_acked);
-
- private:
- // Tracks the maximum number of bytes acked faster than the sending rate.
- typedef WindowedFilter<QuicByteCount,
- MaxFilter<QuicByteCount>,
- QuicRoundTripCount,
- QuicRoundTripCount>
- MaxAckHeightFilter;
- MaxAckHeightFilter max_ack_height_filter_;
-
- // The time this aggregation started and the number of bytes acked during it.
- QuicTime aggregation_epoch_start_time_ = QuicTime::Zero();
- QuicByteCount aggregation_epoch_bytes_ = 0;
-};
-
// Bbr2NetworkModel takes low level congestion signals(packets sent/acked/lost)
// as input and produces BBRv2 model parameters like inflight_(hi|lo),
// bandwidth_(hi|lo), bandwidth and rtt estimates, etc.
@@ -353,7 +325,9 @@
QuicBandwidth MaxBandwidth() const { return max_bandwidth_filter_.Get(); }
- QuicByteCount MaxAckHeight() const { return max_ack_height_tracker_.Get(); }
+ QuicByteCount MaxAckHeight() const {
+ return bandwidth_sampler_.max_ack_height();
+ }
bool MaybeExpireMinRtt(const Bbr2CongestionEvent& congestion_event);
@@ -433,8 +407,6 @@
Bbr2MaxBandwidthFilter max_bandwidth_filter_;
MinRttFilter min_rtt_filter_;
- Bbr2MaxAckHeightTracker max_ack_height_tracker_;
-
// Bytes lost in the current round. Updated once per congestion event.
QuicByteCount bytes_lost_in_round_ = 0;
diff --git a/quic/core/congestion_control/bbr_sender.cc b/quic/core/congestion_control/bbr_sender.cc
index 65a637c..bea0d00 100644
--- a/quic/core/congestion_control/bbr_sender.cc
+++ b/quic/core/congestion_control/bbr_sender.cc
@@ -90,6 +90,7 @@
random_(random),
stats_(stats),
mode_(STARTUP),
+ sampler_(kBandwidthWindowSize),
round_trip_count_(0),
max_bandwidth_(kBandwidthWindowSize, QuicBandwidth::Zero(), 0),
max_ack_height_(kBandwidthWindowSize, 0, 0),
@@ -136,7 +137,12 @@
probe_rtt_skipped_if_similar_rtt_(false),
probe_rtt_disabled_if_app_limited_(false),
app_limited_since_last_probe_rtt_(false),
- min_rtt_since_last_probe_rtt_(QuicTime::Delta::Infinite()) {
+ min_rtt_since_last_probe_rtt_(QuicTime::Delta::Infinite()),
+ quic_track_ack_height_in_bandwidth_sampler_(
+ GetQuicReloadableFlag(quic_track_ack_height_in_bandwidth_sampler)) {
+ if (quic_track_ack_height_in_bandwidth_sampler_) {
+ QUIC_RELOADABLE_FLAG_COUNT(quic_track_ack_height_in_bandwidth_sampler);
+ }
if (stats_) {
stats_->slowstart_count = 0;
stats_->slowstart_start_time = QuicTime::Zero();
@@ -284,10 +290,18 @@
startup_rate_reduction_multiplier_ = 2;
}
if (config.HasClientRequestedIndependentOption(kBBR4, perspective)) {
- max_ack_height_.SetWindowLength(2 * kBandwidthWindowSize);
+ if (quic_track_ack_height_in_bandwidth_sampler_) {
+ sampler_.SetMaxAckHeightTrackerWindowLength(2 * kBandwidthWindowSize);
+ } else {
+ max_ack_height_.SetWindowLength(2 * kBandwidthWindowSize);
+ }
}
if (config.HasClientRequestedIndependentOption(kBBR5, perspective)) {
- max_ack_height_.SetWindowLength(4 * kBandwidthWindowSize);
+ if (quic_track_ack_height_in_bandwidth_sampler_) {
+ sampler_.SetMaxAckHeightTrackerWindowLength(4 * kBandwidthWindowSize);
+ } else {
+ max_ack_height_.SetWindowLength(4 * kBandwidthWindowSize);
+ }
}
if (GetQuicReloadableFlag(quic_bbr_less_probe_rtt) &&
config.HasClientRequestedIndependentOption(kBBR6, perspective)) {
@@ -405,7 +419,10 @@
const QuicByteCount bytes_acked =
sampler_.total_bytes_acked() - total_bytes_acked_before;
- excess_acked = UpdateAckAggregationBytes(event_time, bytes_acked);
+ excess_acked = quic_track_ack_height_in_bandwidth_sampler_
+ ? sampler_.OnAckEventEnd(max_bandwidth_.GetBest(),
+ round_trip_count_)
+ : UpdateAckAggregationBytes(event_time, bytes_acked);
}
// Handle logic specific to PROBE_BW mode.
@@ -647,7 +664,11 @@
rounds_without_bandwidth_gain_ = 0;
if (expire_ack_aggregation_in_startup_) {
// Expire old excess delivery measurements now that bandwidth increased.
- max_ack_height_.Reset(0, round_trip_count_);
+ if (quic_track_ack_height_in_bandwidth_sampler_) {
+ sampler_.ResetMaxAckHeightTracker(0, round_trip_count_);
+ } else {
+ max_ack_height_.Reset(0, round_trip_count_);
+ }
}
return;
}
@@ -847,7 +868,9 @@
GetTargetCongestionWindow(congestion_window_gain_);
if (is_at_full_bandwidth_) {
// Add the max recently measured ack aggregation to CWND.
- target_window += max_ack_height_.GetBest();
+ target_window += quic_track_ack_height_in_bandwidth_sampler_
+ ? sampler_.max_ack_height()
+ : max_ack_height_.GetBest();
} else if (enable_ack_aggregation_during_startup_) {
// Add the most recent excess acked. Because CWND never decreases in
// STARTUP, this will automatically create a very localized max filter.
diff --git a/quic/core/congestion_control/bbr_sender.h b/quic/core/congestion_control/bbr_sender.h
index a4d9925..b74b783 100644
--- a/quic/core/congestion_control/bbr_sender.h
+++ b/quic/core/congestion_control/bbr_sender.h
@@ -25,8 +25,6 @@
class RttStats;
-typedef uint64_t QuicRoundTripCount;
-
// BbrSender implements BBR congestion control algorithm. BBR aims to estimate
// the current available Bottleneck Bandwidth and RTT (hence the name), and
// regulates the pacing rate and the size of the congestion window based on
@@ -401,6 +399,8 @@
bool probe_rtt_disabled_if_app_limited_;
bool app_limited_since_last_probe_rtt_;
QuicTime::Delta min_rtt_since_last_probe_rtt_;
+ // Latched value of --quic_track_ack_height_in_bandwidth_sampler.
+ const bool quic_track_ack_height_in_bandwidth_sampler_;
};
QUIC_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
diff --git a/quic/core/congestion_control/send_algorithm_interface.h b/quic/core/congestion_control/send_algorithm_interface.h
index 69f7455..dab8fc2 100644
--- a/quic/core/congestion_control/send_algorithm_interface.h
+++ b/quic/core/congestion_control/send_algorithm_interface.h
@@ -24,6 +24,8 @@
namespace quic {
+typedef uint64_t QuicRoundTripCount;
+
class CachedNetworkParameters;
class RttStats;