| 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, |
| 34 QuicConnectionStats* stats) | 35 QuicConnectionStats* stats) |
| 35 : hybrid_slow_start_(clock), | 36 : hybrid_slow_start_(clock), |
| 36 cubic_(clock), | 37 cubic_(clock), |
| 37 rtt_stats_(rtt_stats), | 38 rtt_stats_(rtt_stats), |
| 38 stats_(stats), | 39 stats_(stats), |
| 39 reno_(reno), | 40 reno_(reno), |
| 40 num_connections_(kDefaultNumConnections), | 41 num_connections_(kDefaultNumConnections), |
| 41 num_acked_packets_(0), | 42 congestion_window_count_(0), |
| 42 largest_sent_sequence_number_(0), | 43 largest_sent_sequence_number_(0), |
| 43 largest_acked_sequence_number_(0), | 44 largest_acked_sequence_number_(0), |
| 44 largest_sent_at_last_cutback_(0), | 45 largest_sent_at_last_cutback_(0), |
| 45 congestion_window_(initial_tcp_congestion_window), | 46 congestion_window_(initial_tcp_congestion_window), |
| 46 min_congestion_window_(kDefaultMinimumCongestionWindow), | 47 min_congestion_window_(kDefaultMinimumCongestionWindow), |
| 47 slowstart_threshold_(std::numeric_limits<uint64>::max()), | 48 slowstart_threshold_(max_tcp_congestion_window), |
| 48 last_cutback_exited_slowstart_(false), | 49 last_cutback_exited_slowstart_(false), |
| 50 max_tcp_congestion_window_(max_tcp_congestion_window), |
| 49 clock_(clock) { | 51 clock_(clock) { |
| 50 } | 52 } |
| 51 | 53 |
| 52 TcpCubicSender::~TcpCubicSender() { | 54 TcpCubicSender::~TcpCubicSender() { |
| 53 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); | 55 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); |
| 54 } | 56 } |
| 55 | 57 |
| 56 void TcpCubicSender::SetFromConfig(const QuicConfig& config, | 58 void TcpCubicSender::SetFromConfig(const QuicConfig& config, |
| 57 Perspective perspective, | 59 Perspective perspective, |
| 58 bool using_pacing) { | 60 bool using_pacing) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 86 } | 88 } |
| 87 | 89 |
| 88 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( | 90 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( |
| 89 cached_network_params.bandwidth_estimate_bytes_per_second()); | 91 cached_network_params.bandwidth_estimate_bytes_per_second()); |
| 90 QuicTime::Delta rtt_ms = | 92 QuicTime::Delta rtt_ms = |
| 91 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); | 93 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); |
| 92 | 94 |
| 93 // Make sure CWND is in appropriate range (in case of bad data). | 95 // Make sure CWND is in appropriate range (in case of bad data). |
| 94 QuicPacketCount new_congestion_window = | 96 QuicPacketCount new_congestion_window = |
| 95 bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize; | 97 bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize; |
| 96 congestion_window_ = max( | 98 congestion_window_ = max(min(new_congestion_window, kMaxTcpCongestionWindow), |
| 97 min(new_congestion_window, kMaxCongestionWindowForBandwidthResumption), | 99 kMinCongestionWindowForBandwidthResumption); |
| 98 kMinCongestionWindowForBandwidthResumption); | |
| 99 | 100 |
| 100 // TODO(rjshade): Set appropriate CWND when previous connection was in slow | 101 // TODO(rjshade): Set appropriate CWND when previous connection was in slow |
| 101 // start at time of estimate. | 102 // start at time of estimate. |
| 102 return true; | 103 return true; |
| 103 } | 104 } |
| 104 | 105 |
| 105 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { | 106 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { |
| 106 num_connections_ = max(1, num_connections); | 107 num_connections_ = max(1, num_connections); |
| 107 cubic_.SetNumConnections(num_connections_); | 108 cubic_.SetNumConnections(num_connections_); |
| 108 } | 109 } |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 179 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); | 180 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); |
| 180 } | 181 } |
| 181 slowstart_threshold_ = congestion_window_; | 182 slowstart_threshold_ = congestion_window_; |
| 182 // Enforce a minimum congestion window. | 183 // Enforce a minimum congestion window. |
| 183 if (congestion_window_ < min_congestion_window_) { | 184 if (congestion_window_ < min_congestion_window_) { |
| 184 congestion_window_ = min_congestion_window_; | 185 congestion_window_ = min_congestion_window_; |
| 185 } | 186 } |
| 186 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; | 187 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; |
| 187 // reset packet count from congestion avoidance mode. We start | 188 // reset packet count from congestion avoidance mode. We start |
| 188 // counting again when we're out of recovery. | 189 // counting again when we're out of recovery. |
| 189 num_acked_packets_ = 0; | 190 congestion_window_count_ = 0; |
| 190 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ | 191 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ |
| 191 << " slowstart threshold: " << slowstart_threshold_; | 192 << " slowstart threshold: " << slowstart_threshold_; |
| 192 } | 193 } |
| 193 | 194 |
| 194 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, | 195 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, |
| 195 QuicByteCount /*bytes_in_flight*/, | 196 QuicByteCount /*bytes_in_flight*/, |
| 196 QuicPacketSequenceNumber sequence_number, | 197 QuicPacketSequenceNumber sequence_number, |
| 197 QuicByteCount bytes, | 198 QuicByteCount bytes, |
| 198 HasRetransmittableData is_retransmittable) { | 199 HasRetransmittableData is_retransmittable) { |
| 199 // Only update bytes_in_flight_ for data packets. | 200 // Only update bytes_in_flight_ for data packets. |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 void TcpCubicSender::MaybeIncreaseCwnd( | 301 void TcpCubicSender::MaybeIncreaseCwnd( |
| 301 QuicPacketSequenceNumber acked_sequence_number, | 302 QuicPacketSequenceNumber acked_sequence_number, |
| 302 QuicByteCount bytes_in_flight) { | 303 QuicByteCount bytes_in_flight) { |
| 303 LOG_IF(DFATAL, InRecovery()) << "Never increase the CWND during recovery."; | 304 LOG_IF(DFATAL, InRecovery()) << "Never increase the CWND during recovery."; |
| 304 if (!IsCwndLimited(bytes_in_flight)) { | 305 if (!IsCwndLimited(bytes_in_flight)) { |
| 305 // We don't update the congestion window unless we are close to using the | 306 // We don't update the congestion window unless we are close to using the |
| 306 // window we have available. | 307 // window we have available. |
| 307 return; | 308 return; |
| 308 } | 309 } |
| 309 if (InSlowStart()) { | 310 if (InSlowStart()) { |
| 310 // TCP slow start, exponential growth, increase by one for each ACK. | 311 // congestion_window_cnt is the number of acks since last change of snd_cwnd |
| 311 ++congestion_window_; | 312 if (congestion_window_ < max_tcp_congestion_window_) { |
| 313 // TCP slow start, exponential growth, increase by one for each ACK. |
| 314 ++congestion_window_; |
| 315 } |
| 312 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ | 316 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ |
| 313 << " slowstart threshold: " << slowstart_threshold_; | 317 << " slowstart threshold: " << slowstart_threshold_; |
| 314 return; | 318 return; |
| 315 } | 319 } |
| 320 if (congestion_window_ >= max_tcp_congestion_window_) { |
| 321 return; |
| 322 } |
| 316 // Congestion avoidance | 323 // Congestion avoidance |
| 317 if (reno_) { | 324 if (reno_) { |
| 318 // Classic Reno congestion avoidance. | 325 // Classic Reno congestion avoidance. |
| 319 ++num_acked_packets_; | 326 ++congestion_window_count_; |
| 320 // Divide by num_connections to smoothly increase the CWND at a faster | 327 // Divide by num_connections to smoothly increase the CWND at a faster |
| 321 // rate than conventional Reno. | 328 // rate than conventional Reno. |
| 322 if (num_acked_packets_ * num_connections_ >= congestion_window_) { | 329 if (congestion_window_count_ * num_connections_ >= congestion_window_) { |
| 323 ++congestion_window_; | 330 ++congestion_window_; |
| 324 num_acked_packets_ = 0; | 331 congestion_window_count_ = 0; |
| 325 } | 332 } |
| 326 | 333 |
| 327 DVLOG(1) << "Reno; congestion window: " << congestion_window_ | 334 DVLOG(1) << "Reno; congestion window: " << congestion_window_ |
| 328 << " slowstart threshold: " << slowstart_threshold_ | 335 << " slowstart threshold: " << slowstart_threshold_ |
| 329 << " congestion window count: " << num_acked_packets_; | 336 << " congestion window count: " << congestion_window_count_; |
| 330 } else { | 337 } else { |
| 331 congestion_window_ = cubic_.CongestionWindowAfterAck(congestion_window_, | 338 congestion_window_ = min(max_tcp_congestion_window_, |
| 332 rtt_stats_->min_rtt()); | 339 cubic_.CongestionWindowAfterAck( |
| 340 congestion_window_, rtt_stats_->min_rtt())); |
| 333 DVLOG(1) << "Cubic; congestion window: " << congestion_window_ | 341 DVLOG(1) << "Cubic; congestion window: " << congestion_window_ |
| 334 << " slowstart threshold: " << slowstart_threshold_; | 342 << " slowstart threshold: " << slowstart_threshold_; |
| 335 } | 343 } |
| 336 } | 344 } |
| 337 | 345 |
| 338 void TcpCubicSender::OnRetransmissionTimeout(bool packets_retransmitted) { | 346 void TcpCubicSender::OnRetransmissionTimeout(bool packets_retransmitted) { |
| 339 largest_sent_at_last_cutback_ = 0; | 347 largest_sent_at_last_cutback_ = 0; |
| 340 if (!packets_retransmitted) { | 348 if (!packets_retransmitted) { |
| 341 return; | 349 return; |
| 342 } | 350 } |
| 343 cubic_.Reset(); | 351 cubic_.Reset(); |
| 344 hybrid_slow_start_.Restart(); | 352 hybrid_slow_start_.Restart(); |
| 345 slowstart_threshold_ = congestion_window_ / 2; | 353 slowstart_threshold_ = congestion_window_ / 2; |
| 346 congestion_window_ = min_congestion_window_; | 354 congestion_window_ = min_congestion_window_; |
| 347 } | 355 } |
| 348 | 356 |
| 349 CongestionControlType TcpCubicSender::GetCongestionControlType() const { | 357 CongestionControlType TcpCubicSender::GetCongestionControlType() const { |
| 350 return reno_ ? kReno : kCubic; | 358 return reno_ ? kReno : kCubic; |
| 351 } | 359 } |
| 352 | 360 |
| 353 } // namespace net | 361 } // namespace net |
| OLD | NEW |