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;