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