OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "net/quic/congestion_control/tcp_cubic_sender_packets.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/metrics/histogram_macros.h" | |
10 #include "net/quic/congestion_control/prr_sender.h" | |
11 #include "net/quic/congestion_control/rtt_stats.h" | |
12 #include "net/quic/crypto/crypto_protocol.h" | |
13 #include "net/quic/proto/cached_network_parameters.pb.h" | |
14 #include "net/quic/quic_bug_tracker.h" | |
15 #include "net/quic/quic_flags.h" | |
16 | |
17 using std::max; | |
18 using std::min; | |
19 | |
20 namespace net { | |
21 | |
22 namespace { | |
23 // Constants based on TCP defaults. | |
24 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a | |
25 // fast retransmission. The cwnd after a timeout is still 1. | |
26 const QuicPacketCount kDefaultMinimumCongestionWindow = 2; | |
27 } // namespace | |
28 | |
29 TcpCubicSenderPackets::TcpCubicSenderPackets( | |
30 const QuicClock* clock, | |
31 const RttStats* rtt_stats, | |
32 bool reno, | |
33 QuicPacketCount initial_tcp_congestion_window, | |
34 QuicPacketCount max_tcp_congestion_window, | |
35 QuicConnectionStats* stats) | |
36 : TcpCubicSenderBase(clock, rtt_stats, reno, stats), | |
37 cubic_(clock), | |
38 congestion_window_count_(0), | |
39 congestion_window_(initial_tcp_congestion_window), | |
40 min_congestion_window_(kDefaultMinimumCongestionWindow), | |
41 slowstart_threshold_(max_tcp_congestion_window), | |
42 max_tcp_congestion_window_(max_tcp_congestion_window), | |
43 initial_tcp_congestion_window_(initial_tcp_congestion_window), | |
44 initial_max_tcp_congestion_window_(max_tcp_congestion_window), | |
45 min_slow_start_exit_window_(min_congestion_window_) {} | |
46 | |
47 TcpCubicSenderPackets::~TcpCubicSenderPackets() {} | |
48 | |
49 void TcpCubicSenderPackets::SetCongestionWindowFromBandwidthAndRtt( | |
50 QuicBandwidth bandwidth, | |
51 QuicTime::Delta rtt) { | |
52 QuicPacketCount new_congestion_window = | |
53 bandwidth.ToBytesPerPeriod(rtt) / kDefaultTCPMSS; | |
54 if (FLAGS_quic_no_lower_bw_resumption_limit) { | |
55 // Limit new CWND to be in the range [1, kMaxCongestionWindow]. | |
56 congestion_window_ = | |
57 max(min_congestion_window_, | |
58 min(new_congestion_window, kMaxResumptionCongestionWindow)); | |
59 } else { | |
60 congestion_window_ = | |
61 max(min(new_congestion_window, kMaxResumptionCongestionWindow), | |
62 kMinCongestionWindowForBandwidthResumption); | |
63 } | |
64 } | |
65 | |
66 void TcpCubicSenderPackets::SetCongestionWindowInPackets( | |
67 QuicPacketCount congestion_window) { | |
68 congestion_window_ = congestion_window; | |
69 } | |
70 | |
71 void TcpCubicSenderPackets::SetMinCongestionWindowInPackets( | |
72 QuicPacketCount congestion_window) { | |
73 min_congestion_window_ = congestion_window; | |
74 } | |
75 | |
76 void TcpCubicSenderPackets::SetNumEmulatedConnections(int num_connections) { | |
77 TcpCubicSenderBase::SetNumEmulatedConnections(num_connections); | |
78 cubic_.SetNumConnections(num_connections_); | |
79 } | |
80 | |
81 void TcpCubicSenderPackets::ExitSlowstart() { | |
82 slowstart_threshold_ = congestion_window_; | |
83 } | |
84 | |
85 void TcpCubicSenderPackets::OnPacketLost(QuicPacketNumber packet_number, | |
86 QuicByteCount lost_bytes, | |
87 QuicByteCount bytes_in_flight) { | |
88 // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets | |
89 // already sent should be treated as a single loss event, since it's expected. | |
90 if (packet_number <= largest_sent_at_last_cutback_) { | |
91 if (last_cutback_exited_slowstart_) { | |
92 ++stats_->slowstart_packets_lost; | |
93 stats_->slowstart_bytes_lost += lost_bytes; | |
94 if (slow_start_large_reduction_) { | |
95 if (stats_->slowstart_packets_lost == 1 || | |
96 (stats_->slowstart_bytes_lost / kDefaultTCPMSS) > | |
97 (stats_->slowstart_bytes_lost - lost_bytes) / kDefaultTCPMSS) { | |
98 // Reduce congestion window by 1 for every mss of bytes lost. | |
99 congestion_window_ = | |
100 max(congestion_window_ - 1, min_slow_start_exit_window_); | |
101 } | |
102 slowstart_threshold_ = congestion_window_; | |
103 } | |
104 } | |
105 DVLOG(1) << "Ignoring loss for largest_missing:" << packet_number | |
106 << " because it was sent prior to the last CWND cutback."; | |
107 return; | |
108 } | |
109 ++stats_->tcp_loss_events; | |
110 last_cutback_exited_slowstart_ = InSlowStart(); | |
111 if (InSlowStart()) { | |
112 ++stats_->slowstart_packets_lost; | |
113 } | |
114 | |
115 if (!no_prr_) { | |
116 prr_.OnPacketLost(bytes_in_flight); | |
117 } | |
118 | |
119 // TODO(jri): Separate out all of slow start into a separate class. | |
120 if (slow_start_large_reduction_ && InSlowStart()) { | |
121 DCHECK_LT(1u, congestion_window_); | |
122 if (congestion_window_ >= 2 * initial_tcp_congestion_window_) { | |
123 min_slow_start_exit_window_ = congestion_window_ / 2; | |
124 } | |
125 congestion_window_ = congestion_window_ - 1; | |
126 } else if (reno_) { | |
127 congestion_window_ = congestion_window_ * RenoBeta(); | |
128 } else { | |
129 congestion_window_ = | |
130 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); | |
131 } | |
132 // Enforce a minimum congestion window. | |
133 if (congestion_window_ < min_congestion_window_) { | |
134 congestion_window_ = min_congestion_window_; | |
135 } | |
136 slowstart_threshold_ = congestion_window_; | |
137 largest_sent_at_last_cutback_ = largest_sent_packet_number_; | |
138 // reset packet count from congestion avoidance mode. We start | |
139 // counting again when we're out of recovery. | |
140 congestion_window_count_ = 0; | |
141 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ | |
142 << " slowstart threshold: " << slowstart_threshold_; | |
143 } | |
144 | |
145 QuicByteCount TcpCubicSenderPackets::GetCongestionWindow() const { | |
146 return congestion_window_ * kDefaultTCPMSS; | |
147 } | |
148 | |
149 QuicByteCount TcpCubicSenderPackets::GetSlowStartThreshold() const { | |
150 return slowstart_threshold_ * kDefaultTCPMSS; | |
151 } | |
152 | |
153 // Called when we receive an ack. Normal TCP tracks how many packets one ack | |
154 // represents, but quic has a separate ack for each packet. | |
155 void TcpCubicSenderPackets::MaybeIncreaseCwnd( | |
156 QuicPacketNumber acked_packet_number, | |
157 QuicByteCount /*acked_bytes*/, | |
158 QuicByteCount bytes_in_flight) { | |
159 QUIC_BUG_IF(InRecovery()) << "Never increase the CWND during recovery."; | |
160 // Do not increase the congestion window unless the sender is close to using | |
161 // the current window. | |
162 if (!IsCwndLimited(bytes_in_flight)) { | |
163 cubic_.OnApplicationLimited(); | |
164 return; | |
165 } | |
166 if (congestion_window_ >= max_tcp_congestion_window_) { | |
167 return; | |
168 } | |
169 if (InSlowStart()) { | |
170 // TCP slow start, exponential growth, increase by one for each ACK. | |
171 ++congestion_window_; | |
172 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ | |
173 << " slowstart threshold: " << slowstart_threshold_; | |
174 return; | |
175 } | |
176 // Congestion avoidance | |
177 if (reno_) { | |
178 // Classic Reno congestion avoidance. | |
179 ++congestion_window_count_; | |
180 // Divide by num_connections to smoothly increase the CWND at a faster | |
181 // rate than conventional Reno. | |
182 if (congestion_window_count_ * num_connections_ >= congestion_window_) { | |
183 ++congestion_window_; | |
184 congestion_window_count_ = 0; | |
185 } | |
186 | |
187 DVLOG(1) << "Reno; congestion window: " << congestion_window_ | |
188 << " slowstart threshold: " << slowstart_threshold_ | |
189 << " congestion window count: " << congestion_window_count_; | |
190 } else { | |
191 congestion_window_ = min(max_tcp_congestion_window_, | |
192 cubic_.CongestionWindowAfterAck( | |
193 congestion_window_, rtt_stats_->min_rtt())); | |
194 DVLOG(1) << "Cubic; congestion window: " << congestion_window_ | |
195 << " slowstart threshold: " << slowstart_threshold_; | |
196 } | |
197 } | |
198 | |
199 void TcpCubicSenderPackets::HandleRetransmissionTimeout() { | |
200 cubic_.Reset(); | |
201 slowstart_threshold_ = congestion_window_ / 2; | |
202 congestion_window_ = min_congestion_window_; | |
203 } | |
204 | |
205 void TcpCubicSenderPackets::OnConnectionMigration() { | |
206 TcpCubicSenderBase::OnConnectionMigration(); | |
207 cubic_.Reset(); | |
208 congestion_window_count_ = 0; | |
209 congestion_window_ = initial_tcp_congestion_window_; | |
210 slowstart_threshold_ = initial_max_tcp_congestion_window_; | |
211 max_tcp_congestion_window_ = initial_max_tcp_congestion_window_; | |
212 } | |
213 | |
214 CongestionControlType TcpCubicSenderPackets::GetCongestionControlType() const { | |
215 return reno_ ? kReno : kCubic; | |
216 } | |
217 | |
218 } // namespace net | |
OLD | NEW |