| 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_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
| 10 #include "net/quic/congestion_control/prr_sender.h" | 10 #include "net/quic/congestion_control/prr_sender.h" |
| 11 #include "net/quic/congestion_control/rtt_stats.h" | 11 #include "net/quic/congestion_control/rtt_stats.h" |
| 12 #include "net/quic/crypto/crypto_protocol.h" | 12 #include "net/quic/crypto/crypto_protocol.h" |
| 13 #include "net/quic/proto/cached_network_parameters.pb.h" | 13 #include "net/quic/proto/cached_network_parameters.pb.h" |
| 14 #include "net/quic/quic_flags.h" | 14 #include "net/quic/quic_flags.h" |
| 15 | 15 |
| 16 using std::max; | 16 using std::max; |
| 17 using std::min; | 17 using std::min; |
| 18 | 18 |
| 19 namespace net { | 19 namespace net { |
| 20 | 20 |
| 21 namespace { | 21 namespace { |
| 22 // Constants based on TCP defaults. | 22 // Constants based on TCP defaults. |
| 23 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a | 23 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a |
| 24 // fast retransmission. The cwnd after a timeout is still 1. | 24 // fast retransmission. The cwnd after a timeout is still 1. |
| 25 const QuicPacketCount kDefaultMinimumCongestionWindow = 2; | 25 const QuicPacketCount kDefaultMinimumCongestionWindow = 2; |
| 26 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; | 26 const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS; |
| 27 const QuicByteCount kMaxBurstBytes = 3 * kMaxSegmentSize; | |
| 28 const float kRenoBeta = 0.7f; // Reno backoff factor. | 27 const float kRenoBeta = 0.7f; // Reno backoff factor. |
| 29 const uint32 kDefaultNumConnections = 2; // N-connection emulation. | 28 const uint32 kDefaultNumConnections = 2; // N-connection emulation. |
| 30 } // namespace | 29 } // namespace |
| 31 | 30 |
| 32 TcpCubicSender::TcpCubicSender(const QuicClock* clock, | 31 TcpCubicSender::TcpCubicSender(const QuicClock* clock, |
| 33 const RttStats* rtt_stats, | 32 const RttStats* rtt_stats, |
| 34 bool reno, | 33 bool reno, |
| 35 QuicPacketCount initial_tcp_congestion_window, | 34 QuicPacketCount initial_tcp_congestion_window, |
| 36 QuicPacketCount max_tcp_congestion_window, | 35 QuicPacketCount max_tcp_congestion_window, |
| 37 QuicConnectionStats* stats) | 36 QuicConnectionStats* stats) |
| 38 : cubic_(clock), | 37 : cubic_(clock), |
| 39 rtt_stats_(rtt_stats), | 38 rtt_stats_(rtt_stats), |
| 40 stats_(stats), | 39 stats_(stats), |
| 41 reno_(reno), | 40 reno_(reno), |
| 42 num_connections_(kDefaultNumConnections), | 41 num_connections_(kDefaultNumConnections), |
| 43 congestion_window_count_(0), | 42 congestion_window_count_(0), |
| 44 largest_sent_packet_number_(0), | 43 largest_sent_packet_number_(0), |
| 45 largest_acked_packet_number_(0), | 44 largest_acked_packet_number_(0), |
| 46 largest_sent_at_last_cutback_(0), | 45 largest_sent_at_last_cutback_(0), |
| 47 congestion_window_(initial_tcp_congestion_window), | 46 congestion_window_(initial_tcp_congestion_window), |
| 48 min_congestion_window_(kDefaultMinimumCongestionWindow), | 47 min_congestion_window_(kDefaultMinimumCongestionWindow), |
| 49 min4_mode_(false), | 48 min4_mode_(false), |
| 50 slowstart_threshold_(max_tcp_congestion_window), | 49 slowstart_threshold_(max_tcp_congestion_window), |
| 51 last_cutback_exited_slowstart_(false), | 50 last_cutback_exited_slowstart_(false), |
| 52 max_tcp_congestion_window_(max_tcp_congestion_window), | 51 max_tcp_congestion_window_(max_tcp_congestion_window) {} |
| 53 clock_(clock) {} | |
| 54 | 52 |
| 55 TcpCubicSender::~TcpCubicSender() { | 53 TcpCubicSender::~TcpCubicSender() { |
| 56 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); | 54 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); |
| 57 } | 55 } |
| 58 | 56 |
| 59 void TcpCubicSender::SetFromConfig(const QuicConfig& config, | 57 void TcpCubicSender::SetFromConfig(const QuicConfig& config, |
| 60 Perspective perspective) { | 58 Perspective perspective) { |
| 61 if (perspective == Perspective::IS_SERVER) { | 59 if (perspective == Perspective::IS_SERVER) { |
| 62 if (config.HasReceivedConnectionOptions() && | 60 if (config.HasReceivedConnectionOptions() && |
| 63 ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) { | 61 ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 bool max_bandwidth_resumption) { | 96 bool max_bandwidth_resumption) { |
| 99 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( | 97 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( |
| 100 max_bandwidth_resumption | 98 max_bandwidth_resumption |
| 101 ? cached_network_params.max_bandwidth_estimate_bytes_per_second() | 99 ? cached_network_params.max_bandwidth_estimate_bytes_per_second() |
| 102 : cached_network_params.bandwidth_estimate_bytes_per_second()); | 100 : cached_network_params.bandwidth_estimate_bytes_per_second()); |
| 103 QuicTime::Delta rtt_ms = | 101 QuicTime::Delta rtt_ms = |
| 104 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); | 102 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); |
| 105 | 103 |
| 106 // Make sure CWND is in appropriate range (in case of bad data). | 104 // Make sure CWND is in appropriate range (in case of bad data). |
| 107 QuicPacketCount new_congestion_window = | 105 QuicPacketCount new_congestion_window = |
| 108 bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize; | 106 bandwidth.ToBytesPerPeriod(rtt_ms) / kDefaultTCPMSS; |
| 109 congestion_window_ = max(min(new_congestion_window, kMaxCongestionWindow), | 107 congestion_window_ = max(min(new_congestion_window, kMaxCongestionWindow), |
| 110 kMinCongestionWindowForBandwidthResumption); | 108 kMinCongestionWindowForBandwidthResumption); |
| 111 } | 109 } |
| 112 | 110 |
| 113 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { | 111 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { |
| 114 num_connections_ = max(1, num_connections); | 112 num_connections_ = max(1, num_connections); |
| 115 cubic_.SetNumConnections(num_connections_); | 113 cubic_.SetNumConnections(num_connections_); |
| 116 } | 114 } |
| 117 | 115 |
| 118 void TcpCubicSender::SetMaxCongestionWindow( | 116 void TcpCubicSender::SetMaxCongestionWindow( |
| 119 QuicByteCount max_congestion_window) { | 117 QuicByteCount max_congestion_window) { |
| 120 max_tcp_congestion_window_ = max_congestion_window / kMaxPacketSize; | 118 max_tcp_congestion_window_ = max_congestion_window / kDefaultTCPMSS; |
| 121 } | 119 } |
| 122 | 120 |
| 123 float TcpCubicSender::RenoBeta() const { | 121 float TcpCubicSender::RenoBeta() const { |
| 124 // kNConnectionBeta is the backoff factor after loss for our N-connection | 122 // kNConnectionBeta is the backoff factor after loss for our N-connection |
| 125 // emulation, which emulates the effective backoff of an ensemble of N | 123 // emulation, which emulates the effective backoff of an ensemble of N |
| 126 // TCP-Reno connections on a single loss event. The effective multiplier is | 124 // TCP-Reno connections on a single loss event. The effective multiplier is |
| 127 // computed as: | 125 // computed as: |
| 128 return (num_connections_ - 1 + kRenoBeta) / num_connections_; | 126 return (num_connections_ - 1 + kRenoBeta) / num_connections_; |
| 129 } | 127 } |
| 130 | 128 |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 QuicTime /* now */, | 228 QuicTime /* now */, |
| 231 QuicByteCount bytes_in_flight, | 229 QuicByteCount bytes_in_flight, |
| 232 HasRetransmittableData has_retransmittable_data) const { | 230 HasRetransmittableData has_retransmittable_data) const { |
| 233 if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { | 231 if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { |
| 234 // For TCP we can always send an ACK immediately. | 232 // For TCP we can always send an ACK immediately. |
| 235 return QuicTime::Delta::Zero(); | 233 return QuicTime::Delta::Zero(); |
| 236 } | 234 } |
| 237 if (InRecovery()) { | 235 if (InRecovery()) { |
| 238 // PRR is used when in recovery. | 236 // PRR is used when in recovery. |
| 239 return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, | 237 return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, |
| 240 slowstart_threshold_ * kMaxSegmentSize); | 238 slowstart_threshold_ * kDefaultTCPMSS); |
| 241 } | 239 } |
| 242 if (GetCongestionWindow() > bytes_in_flight) { | 240 if (GetCongestionWindow() > bytes_in_flight) { |
| 243 return QuicTime::Delta::Zero(); | 241 return QuicTime::Delta::Zero(); |
| 244 } | 242 } |
| 245 if (min4_mode_ && bytes_in_flight < 4 * kMaxSegmentSize) { | 243 if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) { |
| 246 return QuicTime::Delta::Zero(); | 244 return QuicTime::Delta::Zero(); |
| 247 } | 245 } |
| 248 return QuicTime::Delta::Infinite(); | 246 return QuicTime::Delta::Infinite(); |
| 249 } | 247 } |
| 250 | 248 |
| 251 QuicBandwidth TcpCubicSender::PacingRate() const { | 249 QuicBandwidth TcpCubicSender::PacingRate() const { |
| 252 // We pace at twice the rate of the underlying sender's bandwidth estimate | 250 // We pace at twice the rate of the underlying sender's bandwidth estimate |
| 253 // during slow start and 1.25x during congestion avoidance to ensure pacing | 251 // during slow start and 1.25x during congestion avoidance to ensure pacing |
| 254 // doesn't prevent us from filling the window. | 252 // doesn't prevent us from filling the window. |
| 255 QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); | 253 QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 272 | 270 |
| 273 QuicTime::Delta TcpCubicSender::RetransmissionDelay() const { | 271 QuicTime::Delta TcpCubicSender::RetransmissionDelay() const { |
| 274 if (rtt_stats_->smoothed_rtt().IsZero()) { | 272 if (rtt_stats_->smoothed_rtt().IsZero()) { |
| 275 return QuicTime::Delta::Zero(); | 273 return QuicTime::Delta::Zero(); |
| 276 } | 274 } |
| 277 return rtt_stats_->smoothed_rtt().Add( | 275 return rtt_stats_->smoothed_rtt().Add( |
| 278 rtt_stats_->mean_deviation().Multiply(4)); | 276 rtt_stats_->mean_deviation().Multiply(4)); |
| 279 } | 277 } |
| 280 | 278 |
| 281 QuicByteCount TcpCubicSender::GetCongestionWindow() const { | 279 QuicByteCount TcpCubicSender::GetCongestionWindow() const { |
| 282 return congestion_window_ * kMaxSegmentSize; | 280 return congestion_window_ * kDefaultTCPMSS; |
| 283 } | 281 } |
| 284 | 282 |
| 285 bool TcpCubicSender::InSlowStart() const { | 283 bool TcpCubicSender::InSlowStart() const { |
| 286 return congestion_window_ < slowstart_threshold_; | 284 return congestion_window_ < slowstart_threshold_; |
| 287 } | 285 } |
| 288 | 286 |
| 289 QuicByteCount TcpCubicSender::GetSlowStartThreshold() const { | 287 QuicByteCount TcpCubicSender::GetSlowStartThreshold() const { |
| 290 return slowstart_threshold_ * kMaxSegmentSize; | 288 return slowstart_threshold_ * kDefaultTCPMSS; |
| 291 } | 289 } |
| 292 | 290 |
| 293 bool TcpCubicSender::IsCwndLimited(QuicByteCount bytes_in_flight) const { | 291 bool TcpCubicSender::IsCwndLimited(QuicByteCount bytes_in_flight) const { |
| 294 const QuicByteCount congestion_window_bytes = GetCongestionWindow(); | 292 const QuicByteCount congestion_window_bytes = GetCongestionWindow(); |
| 295 if (bytes_in_flight >= congestion_window_bytes) { | 293 if (bytes_in_flight >= congestion_window_bytes) { |
| 296 return true; | 294 return true; |
| 297 } | 295 } |
| 298 const QuicByteCount available_bytes = | 296 const QuicByteCount available_bytes = |
| 299 congestion_window_bytes - bytes_in_flight; | 297 congestion_window_bytes - bytes_in_flight; |
| 300 const bool slow_start_limited = InSlowStart() && | 298 const bool slow_start_limited = InSlowStart() && |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 hybrid_slow_start_.Restart(); | 361 hybrid_slow_start_.Restart(); |
| 364 slowstart_threshold_ = congestion_window_ / 2; | 362 slowstart_threshold_ = congestion_window_ / 2; |
| 365 congestion_window_ = min_congestion_window_; | 363 congestion_window_ = min_congestion_window_; |
| 366 } | 364 } |
| 367 | 365 |
| 368 CongestionControlType TcpCubicSender::GetCongestionControlType() const { | 366 CongestionControlType TcpCubicSender::GetCongestionControlType() const { |
| 369 return reno_ ? kReno : kCubic; | 367 return reno_ ? kReno : kCubic; |
| 370 } | 368 } |
| 371 | 369 |
| 372 } // namespace net | 370 } // namespace net |
| OLD | NEW |