| 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/rtt_stats.h" | 11 #include "net/quic/congestion_control/rtt_stats.h" |
| 11 #include "net/quic/crypto/crypto_protocol.h" | 12 #include "net/quic/crypto/crypto_protocol.h" |
| 12 | 13 |
| 13 using std::max; | 14 using std::max; |
| 14 using std::min; | 15 using std::min; |
| 15 | 16 |
| 16 namespace net { | 17 namespace net { |
| 17 | 18 |
| 18 namespace { | 19 namespace { |
| 19 // Constants based on TCP defaults. | 20 // Constants based on TCP defaults. |
| 20 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a | 21 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a |
| 21 // fast retransmission. The cwnd after a timeout is still 1. | 22 // fast retransmission. The cwnd after a timeout is still 1. |
| 22 const QuicPacketCount kMinimumCongestionWindow = 2; | 23 const QuicPacketCount kMinimumCongestionWindow = 2; |
| 23 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; | 24 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; |
| 24 const int64 kInitialCongestionWindow = 10; | 25 const int64 kInitialCongestionWindow = 10; |
| 25 const int kMaxBurstLength = 3; | 26 const int kMaxBurstLength = 3; |
| 26 }; // namespace | 27 } // namespace |
| 27 | 28 |
| 28 TcpCubicSender::TcpCubicSender( | 29 TcpCubicSender::TcpCubicSender( |
| 29 const QuicClock* clock, | 30 const QuicClock* clock, |
| 30 const RttStats* rtt_stats, | 31 const RttStats* rtt_stats, |
| 31 bool reno, | 32 bool reno, |
| 32 QuicPacketCount max_tcp_congestion_window, | 33 QuicPacketCount max_tcp_congestion_window, |
| 33 QuicConnectionStats* stats) | 34 QuicConnectionStats* stats) |
| 34 : hybrid_slow_start_(clock), | 35 : hybrid_slow_start_(clock), |
| 35 cubic_(clock, stats), | 36 cubic_(clock, stats), |
| 36 rtt_stats_(rtt_stats), | 37 rtt_stats_(rtt_stats), |
| 37 stats_(stats), | 38 stats_(stats), |
| 38 reno_(reno), | 39 reno_(reno), |
| 39 num_connections_(2), | 40 num_connections_(2), |
| 40 congestion_window_count_(0), | 41 congestion_window_count_(0), |
| 41 receive_window_(kDefaultSocketReceiveBuffer), | |
| 42 prr_out_(0), | |
| 43 prr_delivered_(0), | |
| 44 ack_count_since_loss_(0), | |
| 45 bytes_in_flight_before_loss_(0), | |
| 46 largest_sent_sequence_number_(0), | 42 largest_sent_sequence_number_(0), |
| 47 largest_acked_sequence_number_(0), | 43 largest_acked_sequence_number_(0), |
| 48 largest_sent_at_last_cutback_(0), | 44 largest_sent_at_last_cutback_(0), |
| 49 congestion_window_(kInitialCongestionWindow), | 45 congestion_window_(kInitialCongestionWindow), |
| 50 previous_congestion_window_(0), | 46 previous_congestion_window_(0), |
| 51 slowstart_threshold_(max_tcp_congestion_window), | 47 slowstart_threshold_(max_tcp_congestion_window), |
| 52 previous_slowstart_threshold_(0), | 48 previous_slowstart_threshold_(0), |
| 53 last_cutback_exited_slowstart_(false), | 49 last_cutback_exited_slowstart_(false), |
| 54 max_tcp_congestion_window_(max_tcp_congestion_window) { | 50 max_tcp_congestion_window_(max_tcp_congestion_window) { |
| 55 } | 51 } |
| 56 | 52 |
| 57 TcpCubicSender::~TcpCubicSender() { | 53 TcpCubicSender::~TcpCubicSender() { |
| 58 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); | 54 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); |
| 59 } | 55 } |
| 60 | 56 |
| 61 void TcpCubicSender::SetFromConfig(const QuicConfig& config, bool is_server) { | 57 void TcpCubicSender::SetFromConfig(const QuicConfig& config, bool is_server) { |
| 62 if (is_server) { | 58 if (is_server) { |
| 63 if (config.HasReceivedConnectionOptions() && | 59 if (config.HasReceivedConnectionOptions() && |
| 64 ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { | 60 ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { |
| 65 // Initial window experiment. Ignore the initial congestion | 61 // Initial window experiment. Ignore the initial congestion |
| 66 // window suggested by the client and use the default ICWND of | 62 // window suggested by the client and use the default ICWND of |
| 67 // 10 instead. | 63 // 10 instead. |
| 68 congestion_window_ = kInitialCongestionWindow; | 64 congestion_window_ = kInitialCongestionWindow; |
| 69 } else if (config.HasReceivedInitialCongestionWindow()) { | 65 } else if (config.HasReceivedInitialCongestionWindow()) { |
| 70 // Set the initial window size. | 66 // Set the initial window size. |
| 71 congestion_window_ = min(kMaxInitialWindow, | 67 congestion_window_ = min(kMaxInitialWindow, |
| 72 config.ReceivedInitialCongestionWindow()); | 68 config.ReceivedInitialCongestionWindow()); |
| 73 } | 69 } |
| 74 } | 70 } |
| 75 if (config.HasReceivedSocketReceiveBuffer()) { | |
| 76 // Set the initial socket receive buffer size in bytes. | |
| 77 receive_window_ = config.ReceivedSocketReceiveBuffer(); | |
| 78 } | |
| 79 } | 71 } |
| 80 | 72 |
| 81 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { | 73 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { |
| 82 num_connections_ = max(1, num_connections); | 74 num_connections_ = max(1, num_connections); |
| 83 cubic_.SetNumConnections(num_connections_); | 75 cubic_.SetNumConnections(num_connections_); |
| 84 } | 76 } |
| 85 | 77 |
| 86 void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame( | |
| 87 const QuicCongestionFeedbackFrame& feedback, | |
| 88 QuicTime feedback_receive_time) { | |
| 89 if (feedback.type == kTCP) { | |
| 90 receive_window_ = feedback.tcp.receive_window; | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 void TcpCubicSender::OnCongestionEvent( | 78 void TcpCubicSender::OnCongestionEvent( |
| 95 bool rtt_updated, | 79 bool rtt_updated, |
| 96 QuicByteCount bytes_in_flight, | 80 QuicByteCount bytes_in_flight, |
| 97 const CongestionVector& acked_packets, | 81 const CongestionVector& acked_packets, |
| 98 const CongestionVector& lost_packets) { | 82 const CongestionVector& lost_packets) { |
| 99 if (rtt_updated && InSlowStart() && | 83 if (rtt_updated && InSlowStart() && |
| 100 hybrid_slow_start_.ShouldExitSlowStart(rtt_stats_->latest_rtt(), | 84 hybrid_slow_start_.ShouldExitSlowStart(rtt_stats_->latest_rtt(), |
| 101 rtt_stats_->MinRtt(), | 85 rtt_stats_->MinRtt(), |
| 102 congestion_window_)) { | 86 congestion_window_)) { |
| 103 slowstart_threshold_ = congestion_window_; | 87 slowstart_threshold_ = congestion_window_; |
| 104 } | 88 } |
| 105 for (CongestionVector::const_iterator it = lost_packets.begin(); | 89 for (CongestionVector::const_iterator it = lost_packets.begin(); |
| 106 it != lost_packets.end(); ++it) { | 90 it != lost_packets.end(); ++it) { |
| 107 OnPacketLost(it->first, bytes_in_flight); | 91 OnPacketLost(it->first, bytes_in_flight); |
| 108 } | 92 } |
| 109 for (CongestionVector::const_iterator it = acked_packets.begin(); | 93 for (CongestionVector::const_iterator it = acked_packets.begin(); |
| 110 it != acked_packets.end(); ++it) { | 94 it != acked_packets.end(); ++it) { |
| 111 OnPacketAcked(it->first, it->second.bytes_sent, bytes_in_flight); | 95 OnPacketAcked(it->first, it->second.bytes_sent, bytes_in_flight); |
| 112 } | 96 } |
| 113 } | 97 } |
| 114 | 98 |
| 115 void TcpCubicSender::OnPacketAcked( | 99 void TcpCubicSender::OnPacketAcked( |
| 116 QuicPacketSequenceNumber acked_sequence_number, | 100 QuicPacketSequenceNumber acked_sequence_number, |
| 117 QuicByteCount acked_bytes, | 101 QuicByteCount acked_bytes, |
| 118 QuicByteCount bytes_in_flight) { | 102 QuicByteCount bytes_in_flight) { |
| 119 largest_acked_sequence_number_ = max(acked_sequence_number, | 103 largest_acked_sequence_number_ = max(acked_sequence_number, |
| 120 largest_acked_sequence_number_); | 104 largest_acked_sequence_number_); |
| 121 if (InRecovery()) { | 105 if (InRecovery()) { |
| 122 PrrOnPacketAcked(acked_bytes); | 106 // PRR is used when in recovery. |
| 107 prr_.OnPacketAcked(acked_bytes); |
| 123 return; | 108 return; |
| 124 } | 109 } |
| 125 MaybeIncreaseCwnd(acked_sequence_number, bytes_in_flight); | 110 MaybeIncreaseCwnd(acked_sequence_number, bytes_in_flight); |
| 126 // TODO(ianswett): Should this even be called when not in slow start? | 111 // TODO(ianswett): Should this even be called when not in slow start? |
| 127 hybrid_slow_start_.OnPacketAcked(acked_sequence_number, InSlowStart()); | 112 hybrid_slow_start_.OnPacketAcked(acked_sequence_number, InSlowStart()); |
| 128 } | 113 } |
| 129 | 114 |
| 130 void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number, | 115 void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number, |
| 131 QuicByteCount bytes_in_flight) { | 116 QuicByteCount bytes_in_flight) { |
| 132 // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets | 117 // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets |
| 133 // already sent should be treated as a single loss event, since it's expected. | 118 // already sent should be treated as a single loss event, since it's expected. |
| 134 if (sequence_number <= largest_sent_at_last_cutback_) { | 119 if (sequence_number <= largest_sent_at_last_cutback_) { |
| 135 if (last_cutback_exited_slowstart_) { | 120 if (last_cutback_exited_slowstart_) { |
| 136 ++stats_->slowstart_packets_lost; | 121 ++stats_->slowstart_packets_lost; |
| 137 } | 122 } |
| 138 DVLOG(1) << "Ignoring loss for largest_missing:" << sequence_number | 123 DVLOG(1) << "Ignoring loss for largest_missing:" << sequence_number |
| 139 << " because it was sent prior to the last CWND cutback."; | 124 << " because it was sent prior to the last CWND cutback."; |
| 140 return; | 125 return; |
| 141 } | 126 } |
| 142 ++stats_->tcp_loss_events; | 127 ++stats_->tcp_loss_events; |
| 143 last_cutback_exited_slowstart_ = InSlowStart(); | 128 last_cutback_exited_slowstart_ = InSlowStart(); |
| 144 if (InSlowStart()) { | 129 if (InSlowStart()) { |
| 145 ++stats_->slowstart_packets_lost; | 130 ++stats_->slowstart_packets_lost; |
| 146 } | 131 } |
| 147 PrrOnPacketLost(bytes_in_flight); | 132 |
| 133 prr_.OnPacketLost(bytes_in_flight); |
| 148 | 134 |
| 149 if (reno_) { | 135 if (reno_) { |
| 150 congestion_window_ = congestion_window_ >> 1; | 136 congestion_window_ = congestion_window_ >> 1; |
| 151 } else { | 137 } else { |
| 152 congestion_window_ = | 138 congestion_window_ = |
| 153 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); | 139 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); |
| 154 } | 140 } |
| 155 slowstart_threshold_ = congestion_window_; | 141 slowstart_threshold_ = congestion_window_; |
| 156 // Enforce TCP's minimum congestion window of 2*MSS. | 142 // Enforce TCP's minimum congestion window of 2*MSS. |
| 157 if (congestion_window_ < kMinimumCongestionWindow) { | 143 if (congestion_window_ < kMinimumCongestionWindow) { |
| 158 congestion_window_ = kMinimumCongestionWindow; | 144 congestion_window_ = kMinimumCongestionWindow; |
| 159 } | 145 } |
| 160 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; | 146 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; |
| 161 // reset packet count from congestion avoidance mode. We start | 147 // reset packet count from congestion avoidance mode. We start |
| 162 // counting again when we're out of recovery. | 148 // counting again when we're out of recovery. |
| 163 congestion_window_count_ = 0; | 149 congestion_window_count_ = 0; |
| 164 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ | 150 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ |
| 165 << " slowstart threshold: " << slowstart_threshold_; | 151 << " slowstart threshold: " << slowstart_threshold_; |
| 166 } | 152 } |
| 167 | 153 |
| 168 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, | 154 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, |
| 169 QuicByteCount /*bytes_in_flight*/, | 155 QuicByteCount /*bytes_in_flight*/, |
| 170 QuicPacketSequenceNumber sequence_number, | 156 QuicPacketSequenceNumber sequence_number, |
| 171 QuicByteCount bytes, | 157 QuicByteCount bytes, |
| 172 HasRetransmittableData is_retransmittable) { | 158 HasRetransmittableData is_retransmittable) { |
| 173 // Only update bytes_in_flight_ for data packets. | 159 // Only update bytes_in_flight_ for data packets. |
| 174 if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { | 160 if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { |
| 175 return false; | 161 return false; |
| 176 } | 162 } |
| 177 | 163 if (InRecovery()) { |
| 178 prr_out_ += bytes; | 164 // PRR is used when in recovery. |
| 165 prr_.OnPacketSent(bytes); |
| 166 } |
| 179 DCHECK_LT(largest_sent_sequence_number_, sequence_number); | 167 DCHECK_LT(largest_sent_sequence_number_, sequence_number); |
| 180 largest_sent_sequence_number_ = sequence_number; | 168 largest_sent_sequence_number_ = sequence_number; |
| 181 hybrid_slow_start_.OnPacketSent(sequence_number); | 169 hybrid_slow_start_.OnPacketSent(sequence_number); |
| 182 return true; | 170 return true; |
| 183 } | 171 } |
| 184 | 172 |
| 185 QuicTime::Delta TcpCubicSender::TimeUntilSend( | 173 QuicTime::Delta TcpCubicSender::TimeUntilSend( |
| 186 QuicTime /* now */, | 174 QuicTime /* now */, |
| 187 QuicByteCount bytes_in_flight, | 175 QuicByteCount bytes_in_flight, |
| 188 HasRetransmittableData has_retransmittable_data) const { | 176 HasRetransmittableData has_retransmittable_data) const { |
| 189 if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { | 177 if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { |
| 190 // For TCP we can always send an ACK immediately. | 178 // For TCP we can always send an ACK immediately. |
| 191 return QuicTime::Delta::Zero(); | 179 return QuicTime::Delta::Zero(); |
| 192 } | 180 } |
| 193 if (InRecovery()) { | 181 if (InRecovery()) { |
| 194 return PrrTimeUntilSend(bytes_in_flight); | 182 // PRR is used when in recovery. |
| 183 return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, |
| 184 slowstart_threshold_); |
| 195 } | 185 } |
| 196 if (SendWindow() > bytes_in_flight) { | 186 if (GetCongestionWindow() > bytes_in_flight) { |
| 197 return QuicTime::Delta::Zero(); | 187 return QuicTime::Delta::Zero(); |
| 198 } | 188 } |
| 199 return QuicTime::Delta::Infinite(); | 189 return QuicTime::Delta::Infinite(); |
| 200 } | 190 } |
| 201 | 191 |
| 202 QuicByteCount TcpCubicSender::SendWindow() const { | |
| 203 // What's the current send window in bytes. | |
| 204 return min(receive_window_, GetCongestionWindow()); | |
| 205 } | |
| 206 | |
| 207 QuicBandwidth TcpCubicSender::PacingRate() const { | 192 QuicBandwidth TcpCubicSender::PacingRate() const { |
| 208 // We pace at twice the rate of the underlying sender's bandwidth estimate | 193 // We pace at twice the rate of the underlying sender's bandwidth estimate |
| 209 // during slow start and 1.25x during congestion avoidance to ensure pacing | 194 // during slow start and 1.25x during congestion avoidance to ensure pacing |
| 210 // doesn't prevent us from filling the window. | 195 // doesn't prevent us from filling the window. |
| 211 return BandwidthEstimate().Scale(InSlowStart() ? 2 : 1.25); | 196 return BandwidthEstimate().Scale(InSlowStart() ? 2 : 1.25); |
| 212 } | 197 } |
| 213 | 198 |
| 214 QuicBandwidth TcpCubicSender::BandwidthEstimate() const { | 199 QuicBandwidth TcpCubicSender::BandwidthEstimate() const { |
| 215 if (rtt_stats_->SmoothedRtt().IsZero()) { | 200 if (rtt_stats_->SmoothedRtt().IsZero()) { |
| 216 LOG(DFATAL) << "In BandwidthEstimate(), smoothed RTT is zero!"; | 201 LOG(DFATAL) << "In BandwidthEstimate(), smoothed RTT is zero!"; |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 void TcpCubicSender::RevertRetransmissionTimeout() { | 311 void TcpCubicSender::RevertRetransmissionTimeout() { |
| 327 if (previous_congestion_window_ == 0) { | 312 if (previous_congestion_window_ == 0) { |
| 328 LOG(DFATAL) << "No previous congestion window to revert to."; | 313 LOG(DFATAL) << "No previous congestion window to revert to."; |
| 329 return; | 314 return; |
| 330 } | 315 } |
| 331 congestion_window_ = previous_congestion_window_; | 316 congestion_window_ = previous_congestion_window_; |
| 332 slowstart_threshold_ = previous_slowstart_threshold_; | 317 slowstart_threshold_ = previous_slowstart_threshold_; |
| 333 previous_congestion_window_ = 0; | 318 previous_congestion_window_ = 0; |
| 334 } | 319 } |
| 335 | 320 |
| 336 void TcpCubicSender::PrrOnPacketLost(QuicByteCount bytes_in_flight) { | |
| 337 prr_out_ = 0; | |
| 338 bytes_in_flight_before_loss_ = bytes_in_flight; | |
| 339 prr_delivered_ = 0; | |
| 340 ack_count_since_loss_ = 0; | |
| 341 } | |
| 342 | |
| 343 void TcpCubicSender::PrrOnPacketAcked(QuicByteCount acked_bytes) { | |
| 344 prr_delivered_ += acked_bytes; | |
| 345 ++ack_count_since_loss_; | |
| 346 } | |
| 347 | |
| 348 QuicTime::Delta TcpCubicSender::PrrTimeUntilSend( | |
| 349 QuicByteCount bytes_in_flight) const { | |
| 350 DCHECK(InRecovery()); | |
| 351 // Return QuicTime::Zero In order to ensure limited transmit always works. | |
| 352 if (prr_out_ == 0 || bytes_in_flight < kMaxSegmentSize) { | |
| 353 return QuicTime::Delta::Zero(); | |
| 354 } | |
| 355 if (SendWindow() > bytes_in_flight) { | |
| 356 // During PRR-SSRB, limit outgoing packets to 1 extra MSS per ack, instead | |
| 357 // of sending the entire available window. This prevents burst retransmits | |
| 358 // when more packets are lost than the CWND reduction. | |
| 359 // limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS | |
| 360 if (prr_delivered_ + ack_count_since_loss_ * kMaxSegmentSize <= prr_out_) { | |
| 361 return QuicTime::Delta::Infinite(); | |
| 362 } | |
| 363 return QuicTime::Delta::Zero(); | |
| 364 } | |
| 365 // Implement Proportional Rate Reduction (RFC6937) | |
| 366 // Checks a simplified version of the PRR formula that doesn't use division: | |
| 367 // AvailableSendWindow = | |
| 368 // CEIL(prr_delivered * ssthresh / BytesInFlightAtLoss) - prr_sent | |
| 369 if (prr_delivered_ * slowstart_threshold_ * kMaxSegmentSize > | |
| 370 prr_out_ * bytes_in_flight_before_loss_) { | |
| 371 return QuicTime::Delta::Zero(); | |
| 372 } | |
| 373 return QuicTime::Delta::Infinite(); | |
| 374 } | |
| 375 | |
| 376 CongestionControlType TcpCubicSender::GetCongestionControlType() const { | 321 CongestionControlType TcpCubicSender::GetCongestionControlType() const { |
| 377 return reno_ ? kReno : kCubic; | 322 return reno_ ? kReno : kCubic; |
| 378 } | 323 } |
| 379 | 324 |
| 380 } // namespace net | 325 } // namespace net |
| OLD | NEW |