| 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 |