xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/congestion_control/pacing_sender.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/core/congestion_control/pacing_sender.h"
6 
7 #include "quiche/quic/core/quic_bandwidth.h"
8 #include "quiche/quic/platform/api/quic_flag_utils.h"
9 #include "quiche/quic/platform/api/quic_flags.h"
10 #include "quiche/quic/platform/api/quic_logging.h"
11 
12 namespace quic {
13 namespace {
14 
15 // Configured maximum size of the burst coming out of quiescence.  The burst
16 // is never larger than the current CWND in packets.
17 static const uint32_t kInitialUnpacedBurst = 10;
18 
19 }  // namespace
20 
PacingSender()21 PacingSender::PacingSender()
22     : sender_(nullptr),
23       max_pacing_rate_(QuicBandwidth::Zero()),
24       burst_tokens_(kInitialUnpacedBurst),
25       ideal_next_packet_send_time_(QuicTime::Zero()),
26       initial_burst_size_(kInitialUnpacedBurst),
27       lumpy_tokens_(0),
28       pacing_limited_(false) {}
29 
~PacingSender()30 PacingSender::~PacingSender() {}
31 
set_sender(SendAlgorithmInterface * sender)32 void PacingSender::set_sender(SendAlgorithmInterface* sender) {
33   QUICHE_DCHECK(sender != nullptr);
34   sender_ = sender;
35 }
36 
OnCongestionEvent(bool rtt_updated,QuicByteCount bytes_in_flight,QuicTime event_time,const AckedPacketVector & acked_packets,const LostPacketVector & lost_packets,QuicPacketCount num_ect,QuicPacketCount num_ce)37 void PacingSender::OnCongestionEvent(bool rtt_updated,
38                                      QuicByteCount bytes_in_flight,
39                                      QuicTime event_time,
40                                      const AckedPacketVector& acked_packets,
41                                      const LostPacketVector& lost_packets,
42                                      QuicPacketCount num_ect,
43                                      QuicPacketCount num_ce) {
44   QUICHE_DCHECK(sender_ != nullptr);
45   if (!lost_packets.empty()) {
46     // Clear any burst tokens when entering recovery.
47     burst_tokens_ = 0;
48   }
49   sender_->OnCongestionEvent(rtt_updated, bytes_in_flight, event_time,
50                              acked_packets, lost_packets, num_ect, num_ce);
51 }
52 
OnPacketSent(QuicTime sent_time,QuicByteCount bytes_in_flight,QuicPacketNumber packet_number,QuicByteCount bytes,HasRetransmittableData has_retransmittable_data)53 void PacingSender::OnPacketSent(
54     QuicTime sent_time, QuicByteCount bytes_in_flight,
55     QuicPacketNumber packet_number, QuicByteCount bytes,
56     HasRetransmittableData has_retransmittable_data) {
57   QUICHE_DCHECK(sender_ != nullptr);
58   QUIC_DVLOG(3) << "Packet " << packet_number << " with " << bytes
59                 << " bytes sent at " << sent_time
60                 << ". bytes_in_flight: " << bytes_in_flight;
61   sender_->OnPacketSent(sent_time, bytes_in_flight, packet_number, bytes,
62                         has_retransmittable_data);
63   if (has_retransmittable_data != HAS_RETRANSMITTABLE_DATA) {
64     return;
65   }
66 
67   if (remove_non_initial_burst_) {
68     QUIC_RELOADABLE_FLAG_COUNT_N(quic_pacing_remove_non_initial_burst, 1, 2);
69   } else {
70     // If in recovery, the connection is not coming out of quiescence.
71     if (bytes_in_flight == 0 && !sender_->InRecovery()) {
72       // Add more burst tokens anytime the connection is leaving quiescence, but
73       // limit it to the equivalent of a single bulk write, not exceeding the
74       // current CWND in packets.
75       burst_tokens_ =
76           std::min(initial_burst_size_,
77                    static_cast<uint32_t>(sender_->GetCongestionWindow() /
78                                          kDefaultTCPMSS));
79     }
80   }
81 
82   if (burst_tokens_ > 0) {
83     --burst_tokens_;
84     ideal_next_packet_send_time_ = QuicTime::Zero();
85     pacing_limited_ = false;
86     return;
87   }
88 
89   // The next packet should be sent as soon as the current packet has been
90   // transferred.  PacingRate is based on bytes in flight including this packet.
91   QuicTime::Delta delay =
92       PacingRate(bytes_in_flight + bytes).TransferTime(bytes);
93   if (!pacing_limited_ || lumpy_tokens_ == 0) {
94     // Reset lumpy_tokens_ if either application or cwnd throttles sending or
95     // token runs out.
96     lumpy_tokens_ = std::max(
97         1u, std::min(static_cast<uint32_t>(GetQuicFlag(quic_lumpy_pacing_size)),
98                      static_cast<uint32_t>(
99                          (sender_->GetCongestionWindow() *
100                           GetQuicFlag(quic_lumpy_pacing_cwnd_fraction)) /
101                          kDefaultTCPMSS)));
102     if (sender_->BandwidthEstimate() <
103         QuicBandwidth::FromKBitsPerSecond(
104             GetQuicFlag(quic_lumpy_pacing_min_bandwidth_kbps))) {
105       // Below 1.2Mbps, send 1 packet at once, because one full-sized packet
106       // is about 10ms of queueing.
107       lumpy_tokens_ = 1u;
108     }
109     if ((bytes_in_flight + bytes) >= sender_->GetCongestionWindow()) {
110       // Don't add lumpy_tokens if the congestion controller is CWND limited.
111       lumpy_tokens_ = 1u;
112     }
113   }
114   --lumpy_tokens_;
115   if (pacing_limited_) {
116     // Make up for lost time since pacing throttles the sending.
117     ideal_next_packet_send_time_ = ideal_next_packet_send_time_ + delay;
118   } else {
119     ideal_next_packet_send_time_ =
120         std::max(ideal_next_packet_send_time_ + delay, sent_time + delay);
121   }
122   // Stop making up for lost time if underlying sender prevents sending.
123   pacing_limited_ = sender_->CanSend(bytes_in_flight + bytes);
124 }
125 
OnApplicationLimited()126 void PacingSender::OnApplicationLimited() {
127   // The send is application limited, stop making up for lost time.
128   pacing_limited_ = false;
129 }
130 
SetBurstTokens(uint32_t burst_tokens)131 void PacingSender::SetBurstTokens(uint32_t burst_tokens) {
132   initial_burst_size_ = burst_tokens;
133   burst_tokens_ = std::min(
134       initial_burst_size_,
135       static_cast<uint32_t>(sender_->GetCongestionWindow() / kDefaultTCPMSS));
136 }
137 
TimeUntilSend(QuicTime now,QuicByteCount bytes_in_flight) const138 QuicTime::Delta PacingSender::TimeUntilSend(
139     QuicTime now, QuicByteCount bytes_in_flight) const {
140   QUICHE_DCHECK(sender_ != nullptr);
141 
142   if (!sender_->CanSend(bytes_in_flight)) {
143     // The underlying sender prevents sending.
144     return QuicTime::Delta::Infinite();
145   }
146 
147   if (remove_non_initial_burst_) {
148     QUIC_RELOADABLE_FLAG_COUNT_N(quic_pacing_remove_non_initial_burst, 2, 2);
149     if (burst_tokens_ > 0 || lumpy_tokens_ > 0) {
150       // Don't pace if we have burst or lumpy tokens available.
151       QUIC_DVLOG(1) << "Can send packet now. burst_tokens:" << burst_tokens_
152                     << ", lumpy_tokens:" << lumpy_tokens_;
153       return QuicTime::Delta::Zero();
154     }
155   } else {
156     if (burst_tokens_ > 0 || bytes_in_flight == 0 || lumpy_tokens_ > 0) {
157       // Don't pace if we have burst tokens available or leaving quiescence.
158       QUIC_DVLOG(1) << "Sending packet now. burst_tokens:" << burst_tokens_
159                     << ", bytes_in_flight:" << bytes_in_flight
160                     << ", lumpy_tokens:" << lumpy_tokens_;
161       return QuicTime::Delta::Zero();
162     }
163   }
164 
165   // If the next send time is within the alarm granularity, send immediately.
166   if (ideal_next_packet_send_time_ > now + kAlarmGranularity) {
167     QUIC_DVLOG(1) << "Delaying packet: "
168                   << (ideal_next_packet_send_time_ - now).ToMicroseconds();
169     return ideal_next_packet_send_time_ - now;
170   }
171 
172   QUIC_DVLOG(1) << "Can send packet now. ideal_next_packet_send_time: "
173                 << ideal_next_packet_send_time_ << ", now: " << now;
174   return QuicTime::Delta::Zero();
175 }
176 
PacingRate(QuicByteCount bytes_in_flight) const177 QuicBandwidth PacingSender::PacingRate(QuicByteCount bytes_in_flight) const {
178   QUICHE_DCHECK(sender_ != nullptr);
179   if (!max_pacing_rate_.IsZero()) {
180     return QuicBandwidth::FromBitsPerSecond(
181         std::min(max_pacing_rate_.ToBitsPerSecond(),
182                  sender_->PacingRate(bytes_in_flight).ToBitsPerSecond()));
183   }
184   return sender_->PacingRate(bytes_in_flight);
185 }
186 
187 }  // namespace quic
188