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