OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/congestion_control/tcp_cubic_sender.h" | 5 #include "net/quic/congestion_control/tcp_cubic_sender.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "net/quic/congestion_control/prr_sender.h" | 10 #include "net/quic/congestion_control/prr_sender.h" |
(...skipping 13 matching lines...) Expand all Loading... |
24 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; | 24 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; |
25 const int kMaxBurstLength = 3; | 25 const int kMaxBurstLength = 3; |
26 const float kRenoBeta = 0.7f; // Reno backoff factor. | 26 const float kRenoBeta = 0.7f; // Reno backoff factor. |
27 const uint32 kDefaultNumConnections = 2; // N-connection emulation. | 27 const uint32 kDefaultNumConnections = 2; // N-connection emulation. |
28 } // namespace | 28 } // namespace |
29 | 29 |
30 TcpCubicSender::TcpCubicSender(const QuicClock* clock, | 30 TcpCubicSender::TcpCubicSender(const QuicClock* clock, |
31 const RttStats* rtt_stats, | 31 const RttStats* rtt_stats, |
32 bool reno, | 32 bool reno, |
33 QuicPacketCount initial_tcp_congestion_window, | 33 QuicPacketCount initial_tcp_congestion_window, |
34 QuicPacketCount max_tcp_congestion_window, | |
35 QuicConnectionStats* stats) | 34 QuicConnectionStats* stats) |
36 : hybrid_slow_start_(clock), | 35 : hybrid_slow_start_(clock), |
37 cubic_(clock), | 36 cubic_(clock), |
38 rtt_stats_(rtt_stats), | 37 rtt_stats_(rtt_stats), |
39 stats_(stats), | 38 stats_(stats), |
40 reno_(reno), | 39 reno_(reno), |
41 num_connections_(kDefaultNumConnections), | 40 num_connections_(kDefaultNumConnections), |
42 congestion_window_count_(0), | 41 num_acked_packets_(0), |
43 largest_sent_sequence_number_(0), | 42 largest_sent_sequence_number_(0), |
44 largest_acked_sequence_number_(0), | 43 largest_acked_sequence_number_(0), |
45 largest_sent_at_last_cutback_(0), | 44 largest_sent_at_last_cutback_(0), |
46 congestion_window_(initial_tcp_congestion_window), | 45 congestion_window_(initial_tcp_congestion_window), |
47 slowstart_threshold_(max_tcp_congestion_window), | 46 slowstart_threshold_(std::numeric_limits<uint64>::max()), |
48 last_cutback_exited_slowstart_(false), | 47 last_cutback_exited_slowstart_(false), |
49 max_tcp_congestion_window_(max_tcp_congestion_window), | |
50 clock_(clock) { | 48 clock_(clock) { |
51 } | 49 } |
52 | 50 |
53 TcpCubicSender::~TcpCubicSender() { | 51 TcpCubicSender::~TcpCubicSender() { |
54 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); | 52 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); |
55 } | 53 } |
56 | 54 |
57 void TcpCubicSender::SetFromConfig(const QuicConfig& config, | 55 void TcpCubicSender::SetFromConfig(const QuicConfig& config, |
58 bool is_server, | 56 bool is_server, |
59 bool using_pacing) { | 57 bool using_pacing) { |
(...skipping 22 matching lines...) Expand all Loading... |
82 } | 80 } |
83 | 81 |
84 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( | 82 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( |
85 cached_network_params.bandwidth_estimate_bytes_per_second()); | 83 cached_network_params.bandwidth_estimate_bytes_per_second()); |
86 QuicTime::Delta rtt_ms = | 84 QuicTime::Delta rtt_ms = |
87 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); | 85 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); |
88 | 86 |
89 // Make sure CWND is in appropriate range (in case of bad data). | 87 // Make sure CWND is in appropriate range (in case of bad data). |
90 QuicPacketCount new_congestion_window = | 88 QuicPacketCount new_congestion_window = |
91 bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize; | 89 bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize; |
92 congestion_window_ = max(min(new_congestion_window, kMaxTcpCongestionWindow), | 90 congestion_window_ = max( |
93 kMinCongestionWindowForBandwidthResumption); | 91 min(new_congestion_window, kMaxCongestionWindowForBandwidthResumption), |
| 92 kMinCongestionWindowForBandwidthResumption); |
94 | 93 |
95 // TODO(rjshade): Set appropriate CWND when previous connection was in slow | 94 // TODO(rjshade): Set appropriate CWND when previous connection was in slow |
96 // start at time of estimate. | 95 // start at time of estimate. |
97 return true; | 96 return true; |
98 } | 97 } |
99 | 98 |
100 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { | 99 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { |
101 num_connections_ = max(1, num_connections); | 100 num_connections_ = max(1, num_connections); |
102 cubic_.SetNumConnections(num_connections_); | 101 cubic_.SetNumConnections(num_connections_); |
103 } | 102 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); | 173 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); |
175 } | 174 } |
176 slowstart_threshold_ = congestion_window_; | 175 slowstart_threshold_ = congestion_window_; |
177 // Enforce TCP's minimum congestion window of 2*MSS. | 176 // Enforce TCP's minimum congestion window of 2*MSS. |
178 if (congestion_window_ < kMinimumCongestionWindow) { | 177 if (congestion_window_ < kMinimumCongestionWindow) { |
179 congestion_window_ = kMinimumCongestionWindow; | 178 congestion_window_ = kMinimumCongestionWindow; |
180 } | 179 } |
181 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; | 180 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; |
182 // reset packet count from congestion avoidance mode. We start | 181 // reset packet count from congestion avoidance mode. We start |
183 // counting again when we're out of recovery. | 182 // counting again when we're out of recovery. |
184 congestion_window_count_ = 0; | 183 num_acked_packets_ = 0; |
185 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ | 184 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ |
186 << " slowstart threshold: " << slowstart_threshold_; | 185 << " slowstart threshold: " << slowstart_threshold_; |
187 } | 186 } |
188 | 187 |
189 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, | 188 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, |
190 QuicByteCount /*bytes_in_flight*/, | 189 QuicByteCount /*bytes_in_flight*/, |
191 QuicPacketSequenceNumber sequence_number, | 190 QuicPacketSequenceNumber sequence_number, |
192 QuicByteCount bytes, | 191 QuicByteCount bytes, |
193 HasRetransmittableData is_retransmittable) { | 192 HasRetransmittableData is_retransmittable) { |
194 // Only update bytes_in_flight_ for data packets. | 193 // Only update bytes_in_flight_ for data packets. |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 void TcpCubicSender::MaybeIncreaseCwnd( | 294 void TcpCubicSender::MaybeIncreaseCwnd( |
296 QuicPacketSequenceNumber acked_sequence_number, | 295 QuicPacketSequenceNumber acked_sequence_number, |
297 QuicByteCount bytes_in_flight) { | 296 QuicByteCount bytes_in_flight) { |
298 LOG_IF(DFATAL, InRecovery()) << "Never increase the CWND during recovery."; | 297 LOG_IF(DFATAL, InRecovery()) << "Never increase the CWND during recovery."; |
299 if (!IsCwndLimited(bytes_in_flight)) { | 298 if (!IsCwndLimited(bytes_in_flight)) { |
300 // We don't update the congestion window unless we are close to using the | 299 // We don't update the congestion window unless we are close to using the |
301 // window we have available. | 300 // window we have available. |
302 return; | 301 return; |
303 } | 302 } |
304 if (InSlowStart()) { | 303 if (InSlowStart()) { |
305 // congestion_window_cnt is the number of acks since last change of snd_cwnd | 304 // TCP slow start, exponential growth, increase by one for each ACK. |
306 if (congestion_window_ < max_tcp_congestion_window_) { | 305 ++congestion_window_; |
307 // TCP slow start, exponential growth, increase by one for each ACK. | |
308 ++congestion_window_; | |
309 } | |
310 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ | 306 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ |
311 << " slowstart threshold: " << slowstart_threshold_; | 307 << " slowstart threshold: " << slowstart_threshold_; |
312 return; | 308 return; |
313 } | 309 } |
314 if (congestion_window_ >= max_tcp_congestion_window_) { | |
315 return; | |
316 } | |
317 // Congestion avoidance | 310 // Congestion avoidance |
318 if (reno_) { | 311 if (reno_) { |
319 // Classic Reno congestion avoidance. | 312 // Classic Reno congestion avoidance. |
320 ++congestion_window_count_; | 313 ++num_acked_packets_; |
321 // Divide by num_connections to smoothly increase the CWND at a faster | 314 // Divide by num_connections to smoothly increase the CWND at a faster |
322 // rate than conventional Reno. | 315 // rate than conventional Reno. |
323 if (congestion_window_count_ * num_connections_ >= congestion_window_) { | 316 if (num_acked_packets_ * num_connections_ >= congestion_window_) { |
324 ++congestion_window_; | 317 ++congestion_window_; |
325 congestion_window_count_ = 0; | 318 num_acked_packets_ = 0; |
326 } | 319 } |
327 | 320 |
328 DVLOG(1) << "Reno; congestion window: " << congestion_window_ | 321 DVLOG(1) << "Reno; congestion window: " << congestion_window_ |
329 << " slowstart threshold: " << slowstart_threshold_ | 322 << " slowstart threshold: " << slowstart_threshold_ |
330 << " congestion window count: " << congestion_window_count_; | 323 << " congestion window count: " << num_acked_packets_; |
331 } else { | 324 } else { |
332 congestion_window_ = min(max_tcp_congestion_window_, | 325 congestion_window_ = cubic_.CongestionWindowAfterAck(congestion_window_, |
333 cubic_.CongestionWindowAfterAck( | 326 rtt_stats_->min_rtt()); |
334 congestion_window_, rtt_stats_->min_rtt())); | |
335 DVLOG(1) << "Cubic; congestion window: " << congestion_window_ | 327 DVLOG(1) << "Cubic; congestion window: " << congestion_window_ |
336 << " slowstart threshold: " << slowstart_threshold_; | 328 << " slowstart threshold: " << slowstart_threshold_; |
337 } | 329 } |
338 } | 330 } |
339 | 331 |
340 void TcpCubicSender::OnRetransmissionTimeout(bool packets_retransmitted) { | 332 void TcpCubicSender::OnRetransmissionTimeout(bool packets_retransmitted) { |
341 largest_sent_at_last_cutback_ = 0; | 333 largest_sent_at_last_cutback_ = 0; |
342 if (!packets_retransmitted) { | 334 if (!packets_retransmitted) { |
343 return; | 335 return; |
344 } | 336 } |
345 cubic_.Reset(); | 337 cubic_.Reset(); |
346 hybrid_slow_start_.Restart(); | 338 hybrid_slow_start_.Restart(); |
347 slowstart_threshold_ = congestion_window_ / 2; | 339 slowstart_threshold_ = congestion_window_ / 2; |
348 congestion_window_ = kMinimumCongestionWindow; | 340 congestion_window_ = kMinimumCongestionWindow; |
349 } | 341 } |
350 | 342 |
351 CongestionControlType TcpCubicSender::GetCongestionControlType() const { | 343 CongestionControlType TcpCubicSender::GetCongestionControlType() const { |
352 return reno_ ? kReno : kCubic; | 344 return reno_ ? kReno : kCubic; |
353 } | 345 } |
354 | 346 |
355 } // namespace net | 347 } // namespace net |
OLD | NEW |