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