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