| OLD | NEW |
| 1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 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 | 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_bytes_sender.h" | 5 #include "net/quic/congestion_control/tcp_cubic_bytes_sender.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "net/quic/congestion_control/prr_sender.h" | 9 #include "net/quic/congestion_control/prr_sender.h" |
| 10 #include "net/quic/congestion_control/rtt_stats.h" | 10 #include "net/quic/congestion_control/rtt_stats.h" |
| 11 #include "net/quic/crypto/crypto_protocol.h" | 11 #include "net/quic/crypto/crypto_protocol.h" |
| 12 #include "net/quic/proto/cached_network_parameters.pb.h" | 12 #include "net/quic/proto/cached_network_parameters.pb.h" |
| 13 #include "net/quic/quic_flags.h" | 13 #include "net/quic/quic_flags.h" |
| 14 | 14 |
| 15 using std::max; | 15 using std::max; |
| 16 using std::min; | 16 using std::min; |
| 17 | 17 |
| 18 namespace net { | 18 namespace net { |
| 19 | 19 |
| 20 namespace { | 20 namespace { |
| 21 // Constants based on TCP defaults. | 21 // Constants based on TCP defaults. |
| 22 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a | 22 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a |
| 23 // fast retransmission. | 23 // fast retransmission. |
| 24 const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS; | 24 const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS; |
| 25 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; | 25 const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS; |
| 26 const QuicByteCount kMaxBurstBytes = 3 * kMaxSegmentSize; | |
| 27 const float kRenoBeta = 0.7f; // Reno backoff factor. | 26 const float kRenoBeta = 0.7f; // Reno backoff factor. |
| 28 const uint32 kDefaultNumConnections = 2; // N-connection emulation. | 27 const uint32 kDefaultNumConnections = 2; // N-connection emulation. |
| 29 } // namespace | 28 } // namespace |
| 30 | 29 |
| 31 TcpCubicBytesSender::TcpCubicBytesSender( | 30 TcpCubicBytesSender::TcpCubicBytesSender( |
| 32 const QuicClock* clock, | 31 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_congestion_window, | 35 QuicPacketCount max_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 num_acked_packets_(0), | 42 num_acked_packets_(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 * kMaxSegmentSize), | 46 congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), |
| 48 min_congestion_window_(kDefaultMinimumCongestionWindow), | 47 min_congestion_window_(kDefaultMinimumCongestionWindow), |
| 49 min4_mode_(false), | 48 min4_mode_(false), |
| 50 max_congestion_window_(max_congestion_window * kMaxSegmentSize), | 49 max_congestion_window_(max_congestion_window * kDefaultTCPMSS), |
| 51 slowstart_threshold_(max_congestion_window * kMaxSegmentSize), | 50 slowstart_threshold_(max_congestion_window * kDefaultTCPMSS), |
| 52 last_cutback_exited_slowstart_(false), | 51 last_cutback_exited_slowstart_(false), |
| 53 clock_(clock) {} | 52 clock_(clock) {} |
| 54 | 53 |
| 55 TcpCubicBytesSender::~TcpCubicBytesSender() { | 54 TcpCubicBytesSender::~TcpCubicBytesSender() { |
| 56 } | 55 } |
| 57 | 56 |
| 58 void TcpCubicBytesSender::SetFromConfig(const QuicConfig& config, | 57 void TcpCubicBytesSender::SetFromConfig(const QuicConfig& config, |
| 59 Perspective perspective) { | 58 Perspective perspective) { |
| 60 if (perspective == Perspective::IS_SERVER) { | 59 if (perspective == Perspective::IS_SERVER) { |
| 61 if (config.HasReceivedConnectionOptions() && | 60 if (config.HasReceivedConnectionOptions() && |
| 62 ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { | 61 ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { |
| 63 // Initial window experiment. | 62 // Initial window experiment. |
| 64 congestion_window_ = 10 * kMaxSegmentSize; | 63 congestion_window_ = 10 * kDefaultTCPMSS; |
| 65 } | 64 } |
| 66 if (config.HasReceivedConnectionOptions() && | 65 if (config.HasReceivedConnectionOptions() && |
| 67 ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { | 66 ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { |
| 68 // Min CWND experiment. | 67 // Min CWND experiment. |
| 69 min_congestion_window_ = kMaxSegmentSize; | 68 min_congestion_window_ = kDefaultTCPMSS; |
| 70 } | 69 } |
| 71 if (config.HasReceivedConnectionOptions() && | 70 if (config.HasReceivedConnectionOptions() && |
| 72 ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { | 71 ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { |
| 73 // Min CWND of 4 experiment. | 72 // Min CWND of 4 experiment. |
| 74 min4_mode_ = true; | 73 min4_mode_ = true; |
| 75 min_congestion_window_ = kMaxSegmentSize; | 74 min_congestion_window_ = kDefaultTCPMSS; |
| 76 } | 75 } |
| 77 } | 76 } |
| 78 } | 77 } |
| 79 | 78 |
| 80 void TcpCubicBytesSender::ResumeConnectionState( | 79 void TcpCubicBytesSender::ResumeConnectionState( |
| 81 const CachedNetworkParameters& cached_network_params, | 80 const CachedNetworkParameters& cached_network_params, |
| 82 bool max_bandwidth_resumption) { | 81 bool max_bandwidth_resumption) { |
| 83 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( | 82 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( |
| 84 max_bandwidth_resumption | 83 max_bandwidth_resumption |
| 85 ? cached_network_params.max_bandwidth_estimate_bytes_per_second() | 84 ? cached_network_params.max_bandwidth_estimate_bytes_per_second() |
| 86 : cached_network_params.bandwidth_estimate_bytes_per_second()); | 85 : cached_network_params.bandwidth_estimate_bytes_per_second()); |
| 87 QuicTime::Delta rtt_ms = | 86 QuicTime::Delta rtt_ms = |
| 88 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); | 87 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); |
| 89 | 88 |
| 90 // Make sure CWND is in appropriate range (in case of bad data). | 89 // Make sure CWND is in appropriate range (in case of bad data). |
| 91 QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt_ms); | 90 QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt_ms); |
| 92 congestion_window_ = | 91 congestion_window_ = |
| 93 max(min(new_congestion_window, kMaxCongestionWindow * kMaxSegmentSize), | 92 max(min(new_congestion_window, kMaxCongestionWindow * kDefaultTCPMSS), |
| 94 kMinCongestionWindowForBandwidthResumption * kMaxSegmentSize); | 93 kMinCongestionWindowForBandwidthResumption * kDefaultTCPMSS); |
| 95 } | 94 } |
| 96 | 95 |
| 97 void TcpCubicBytesSender::SetNumEmulatedConnections(int num_connections) { | 96 void TcpCubicBytesSender::SetNumEmulatedConnections(int num_connections) { |
| 98 num_connections_ = max(1, num_connections); | 97 num_connections_ = max(1, num_connections); |
| 99 cubic_.SetNumConnections(num_connections_); | 98 cubic_.SetNumConnections(num_connections_); |
| 100 } | 99 } |
| 101 | 100 |
| 102 void TcpCubicBytesSender::SetMaxCongestionWindow( | 101 void TcpCubicBytesSender::SetMaxCongestionWindow( |
| 103 QuicByteCount max_congestion_window) { | 102 QuicByteCount max_congestion_window) { |
| 104 max_congestion_window_ = max_congestion_window; | 103 max_congestion_window_ = max_congestion_window; |
| 105 } | 104 } |
| 106 | 105 |
| 107 float TcpCubicBytesSender::RenoBeta() const { | 106 float TcpCubicBytesSender::RenoBeta() const { |
| 108 // kNConnectionBeta is the backoff factor after loss for our N-connection | 107 // kNConnectionBeta is the backoff factor after loss for our N-connection |
| 109 // emulation, which emulates the effective backoff of an ensemble of N | 108 // emulation, which emulates the effective backoff of an ensemble of N |
| 110 // TCP-Reno connections on a single loss event. The effective multiplier is | 109 // TCP-Reno connections on a single loss event. The effective multiplier is |
| 111 // computed as: | 110 // computed as: |
| 112 return (num_connections_ - 1 + kRenoBeta) / num_connections_; | 111 return (num_connections_ - 1 + kRenoBeta) / num_connections_; |
| 113 } | 112 } |
| 114 | 113 |
| 115 void TcpCubicBytesSender::OnCongestionEvent( | 114 void TcpCubicBytesSender::OnCongestionEvent( |
| 116 bool rtt_updated, | 115 bool rtt_updated, |
| 117 QuicByteCount bytes_in_flight, | 116 QuicByteCount bytes_in_flight, |
| 118 const CongestionVector& acked_packets, | 117 const CongestionVector& acked_packets, |
| 119 const CongestionVector& lost_packets) { | 118 const CongestionVector& lost_packets) { |
| 120 if (rtt_updated && InSlowStart() && | 119 if (rtt_updated && InSlowStart() && |
| 121 hybrid_slow_start_.ShouldExitSlowStart( | 120 hybrid_slow_start_.ShouldExitSlowStart( |
| 122 rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(), | 121 rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(), |
| 123 congestion_window_ / kMaxSegmentSize)) { | 122 congestion_window_ / kDefaultTCPMSS)) { |
| 124 slowstart_threshold_ = congestion_window_; | 123 slowstart_threshold_ = congestion_window_; |
| 125 } | 124 } |
| 126 for (CongestionVector::const_iterator it = lost_packets.begin(); | 125 for (CongestionVector::const_iterator it = lost_packets.begin(); |
| 127 it != lost_packets.end(); ++it) { | 126 it != lost_packets.end(); ++it) { |
| 128 OnPacketLost(it->first, bytes_in_flight); | 127 OnPacketLost(it->first, bytes_in_flight); |
| 129 } | 128 } |
| 130 for (CongestionVector::const_iterator it = acked_packets.begin(); | 129 for (CongestionVector::const_iterator it = acked_packets.begin(); |
| 131 it != acked_packets.end(); ++it) { | 130 it != acked_packets.end(); ++it) { |
| 132 OnPacketAcked(it->first, it->second, bytes_in_flight); | 131 OnPacketAcked(it->first, it->second, bytes_in_flight); |
| 133 } | 132 } |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 return QuicTime::Delta::Zero(); | 219 return QuicTime::Delta::Zero(); |
| 221 } | 220 } |
| 222 if (InRecovery()) { | 221 if (InRecovery()) { |
| 223 // PRR is used when in recovery. | 222 // PRR is used when in recovery. |
| 224 return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, | 223 return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, |
| 225 slowstart_threshold_); | 224 slowstart_threshold_); |
| 226 } | 225 } |
| 227 if (GetCongestionWindow() > bytes_in_flight) { | 226 if (GetCongestionWindow() > bytes_in_flight) { |
| 228 return QuicTime::Delta::Zero(); | 227 return QuicTime::Delta::Zero(); |
| 229 } | 228 } |
| 230 if (min4_mode_ && bytes_in_flight < 4 * kMaxSegmentSize) { | 229 if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) { |
| 231 return QuicTime::Delta::Zero(); | 230 return QuicTime::Delta::Zero(); |
| 232 } | 231 } |
| 233 return QuicTime::Delta::Infinite(); | 232 return QuicTime::Delta::Infinite(); |
| 234 } | 233 } |
| 235 | 234 |
| 236 QuicBandwidth TcpCubicBytesSender::PacingRate() const { | 235 QuicBandwidth TcpCubicBytesSender::PacingRate() const { |
| 237 // We pace at twice the rate of the underlying sender's bandwidth estimate | 236 // We pace at twice the rate of the underlying sender's bandwidth estimate |
| 238 // during slow start and 1.25x during congestion avoidance to ensure pacing | 237 // during slow start and 1.25x during congestion avoidance to ensure pacing |
| 239 // doesn't prevent us from filling the window. | 238 // doesn't prevent us from filling the window. |
| 240 QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); | 239 QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 if (FLAGS_reset_cubic_epoch_when_app_limited) { | 302 if (FLAGS_reset_cubic_epoch_when_app_limited) { |
| 304 cubic_.OnApplicationLimited(); | 303 cubic_.OnApplicationLimited(); |
| 305 } | 304 } |
| 306 return; | 305 return; |
| 307 } | 306 } |
| 308 if (congestion_window_ >= max_congestion_window_) { | 307 if (congestion_window_ >= max_congestion_window_) { |
| 309 return; | 308 return; |
| 310 } | 309 } |
| 311 if (InSlowStart()) { | 310 if (InSlowStart()) { |
| 312 // TCP slow start, exponential growth, increase by one for each ACK. | 311 // TCP slow start, exponential growth, increase by one for each ACK. |
| 313 congestion_window_ += kMaxSegmentSize; | 312 congestion_window_ += kDefaultTCPMSS; |
| 314 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ | 313 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ |
| 315 << " slowstart threshold: " << slowstart_threshold_; | 314 << " slowstart threshold: " << slowstart_threshold_; |
| 316 return; | 315 return; |
| 317 } | 316 } |
| 318 // Congestion avoidance. | 317 // Congestion avoidance. |
| 319 if (reno_) { | 318 if (reno_) { |
| 320 // Classic Reno congestion avoidance. | 319 // Classic Reno congestion avoidance. |
| 321 ++num_acked_packets_; | 320 ++num_acked_packets_; |
| 322 // Divide by num_connections to smoothly increase the CWND at a faster rate | 321 // Divide by num_connections to smoothly increase the CWND at a faster rate |
| 323 // than conventional Reno. | 322 // than conventional Reno. |
| 324 if (num_acked_packets_ * num_connections_ >= | 323 if (num_acked_packets_ * num_connections_ >= |
| 325 congestion_window_ / kMaxSegmentSize) { | 324 congestion_window_ / kDefaultTCPMSS) { |
| 326 congestion_window_ += kMaxSegmentSize; | 325 congestion_window_ += kDefaultTCPMSS; |
| 327 num_acked_packets_ = 0; | 326 num_acked_packets_ = 0; |
| 328 } | 327 } |
| 329 | 328 |
| 330 DVLOG(1) << "Reno; congestion window: " << congestion_window_ | 329 DVLOG(1) << "Reno; congestion window: " << congestion_window_ |
| 331 << " slowstart threshold: " << slowstart_threshold_ | 330 << " slowstart threshold: " << slowstart_threshold_ |
| 332 << " congestion window count: " << num_acked_packets_; | 331 << " congestion window count: " << num_acked_packets_; |
| 333 } else { | 332 } else { |
| 334 congestion_window_ = | 333 congestion_window_ = |
| 335 min(max_congestion_window_, | 334 min(max_congestion_window_, |
| 336 cubic_.CongestionWindowAfterAck(acked_bytes, congestion_window_, | 335 cubic_.CongestionWindowAfterAck(acked_bytes, congestion_window_, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 349 hybrid_slow_start_.Restart(); | 348 hybrid_slow_start_.Restart(); |
| 350 slowstart_threshold_ = congestion_window_ / 2; | 349 slowstart_threshold_ = congestion_window_ / 2; |
| 351 congestion_window_ = min_congestion_window_; | 350 congestion_window_ = min_congestion_window_; |
| 352 } | 351 } |
| 353 | 352 |
| 354 CongestionControlType TcpCubicBytesSender::GetCongestionControlType() const { | 353 CongestionControlType TcpCubicBytesSender::GetCongestionControlType() const { |
| 355 return reno_ ? kRenoBytes : kCubicBytes; | 354 return reno_ ? kRenoBytes : kCubicBytes; |
| 356 } | 355 } |
| 357 | 356 |
| 358 } // namespace net | 357 } // namespace net |
| OLD | NEW |