gfe-relnote: Only pace out 1 packet at once if the bandwidth is less than 1.2Mbits/sec, similar to TCP BBR. Protected by --gfe2_reloadable_flag_quic_no_lumpy_pacing_at_low_bw.

PiperOrigin-RevId: 242115271
Change-Id: I4f6bc853ff52f9aa30cf58b12aa7b71c1839df2e
diff --git a/quic/core/congestion_control/pacing_sender.cc b/quic/core/congestion_control/pacing_sender.cc
index 348f410..45e8bae 100644
--- a/quic/core/congestion_control/pacing_sender.cc
+++ b/quic/core/congestion_control/pacing_sender.cc
@@ -4,7 +4,9 @@
 
 #include "net/third_party/quiche/src/quic/core/congestion_control/pacing_sender.h"
 
+#include "net/third_party/quiche/src/quic/core/quic_bandwidth.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 {
@@ -94,6 +96,13 @@
                          (sender_->GetCongestionWindow() *
                           GetQuicFlag(FLAGS_quic_lumpy_pacing_cwnd_fraction)) /
                          kDefaultTCPMSS)));
+    if (GetQuicReloadableFlag(quic_no_lumpy_pacing_at_low_bw) &&
+        sender_->BandwidthEstimate() <
+            QuicBandwidth::FromKBitsPerSecond(1200)) {
+      // Below 1.2Mbps, send 1 packet at once, because one full-sized packet
+      // is about 10ms of queueing.
+      lumpy_tokens_ = 1u;
+    }
   }
   --lumpy_tokens_;
   if (pacing_limited_) {
@@ -134,7 +143,8 @@
     return ideal_next_packet_send_time_ - now;
   }
 
-  QUIC_DVLOG(1) << "Sending packet now";
+  QUIC_DVLOG(1) << "Sending packet now. ideal_next_packet_send_time: "
+                << ideal_next_packet_send_time_ << ", now: " << now;
   return QuicTime::Delta::Zero();
 }
 
diff --git a/quic/core/congestion_control/pacing_sender_test.cc b/quic/core/congestion_control/pacing_sender_test.cc
index 0bb9258..3ed881a 100644
--- a/quic/core/congestion_control/pacing_sender_test.cc
+++ b/quic/core/congestion_control/pacing_sender_test.cc
@@ -47,6 +47,8 @@
     pacing_sender_ = QuicMakeUnique<PacingSender>();
     pacing_sender_->set_sender(mock_sender_.get());
     EXPECT_CALL(*mock_sender_, PacingRate(_)).WillRepeatedly(Return(bandwidth));
+    EXPECT_CALL(*mock_sender_, BandwidthEstimate())
+        .WillRepeatedly(Return(bandwidth));
     if (burst_size == 0) {
       EXPECT_CALL(*mock_sender_, OnCongestionEvent(_, _, _, _, _));
       LostPacketVector lost_packets;
@@ -428,5 +430,31 @@
   CheckPacketIsDelayed(QuicTime::Delta::FromMilliseconds(2));
 }
 
+TEST_F(PacingSenderTest, NoLumpyPacingForLowBandwidthFlows) {
+  // Set lumpy size to be 3, and cwnd faction to 0.5
+  SetQuicFlag(&FLAGS_quic_lumpy_pacing_size, 3);
+  SetQuicFlag(&FLAGS_quic_lumpy_pacing_cwnd_fraction, 0.5f);
+  SetQuicReloadableFlag(quic_no_lumpy_pacing_at_low_bw, true);
+
+  // Configure pacing rate of 1 packet per 100 ms.
+  QuicTime::Delta inter_packet_delay = QuicTime::Delta::FromMilliseconds(100);
+  InitPacingRate(kInitialBurstPackets, QuicBandwidth::FromBytesAndTimeDelta(
+                                           kMaxPacketSize, inter_packet_delay));
+  UpdateRtt();
+
+  // Send kInitialBurstPackets packets, and verify that they are not paced.
+  for (int i = 0; i < kInitialBurstPackets; ++i) {
+    CheckPacketIsSentImmediately();
+  }
+
+  // The first packet after burst token exhausted is also sent immediately,
+  // because ideal_next_packet_send_time has not been set yet.
+  CheckPacketIsSentImmediately();
+
+  for (int i = 0; i < 200; ++i) {
+    CheckPacketIsDelayed(inter_packet_delay);
+  }
+}
+
 }  // namespace test
 }  // namespace quic