| 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 prr_out_(0), | |
| 42 prr_delivered_(0), | |
| 43 ack_count_since_loss_(0), | |
| 44 bytes_in_flight_before_loss_(0), | |
| 45 largest_sent_sequence_number_(0), | 42 largest_sent_sequence_number_(0), |
| 46 largest_acked_sequence_number_(0), | 43 largest_acked_sequence_number_(0), |
| 47 largest_sent_at_last_cutback_(0), | 44 largest_sent_at_last_cutback_(0), |
| 48 congestion_window_(kInitialCongestionWindow), | 45 congestion_window_(kInitialCongestionWindow), |
| 49 previous_congestion_window_(0), | 46 previous_congestion_window_(0), |
| 50 slowstart_threshold_(max_tcp_congestion_window), | 47 slowstart_threshold_(max_tcp_congestion_window), |
| 51 previous_slowstart_threshold_(0), | 48 previous_slowstart_threshold_(0), |
| 52 last_cutback_exited_slowstart_(false), | 49 last_cutback_exited_slowstart_(false), |
| 53 max_tcp_congestion_window_(max_tcp_congestion_window) { | 50 max_tcp_congestion_window_(max_tcp_congestion_window) { |
| 54 } | 51 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 } | 96 } |
| 100 } | 97 } |
| 101 | 98 |
| 102 void TcpCubicSender::OnPacketAcked( | 99 void TcpCubicSender::OnPacketAcked( |
| 103 QuicPacketSequenceNumber acked_sequence_number, | 100 QuicPacketSequenceNumber acked_sequence_number, |
| 104 QuicByteCount acked_bytes, | 101 QuicByteCount acked_bytes, |
| 105 QuicByteCount bytes_in_flight) { | 102 QuicByteCount bytes_in_flight) { |
| 106 largest_acked_sequence_number_ = max(acked_sequence_number, | 103 largest_acked_sequence_number_ = max(acked_sequence_number, |
| 107 largest_acked_sequence_number_); | 104 largest_acked_sequence_number_); |
| 108 if (InRecovery()) { | 105 if (InRecovery()) { |
| 109 PrrOnPacketAcked(acked_bytes); | 106 // PRR is used when in recovery. |
| 107 prr_.OnPacketAcked(acked_bytes); |
| 110 return; | 108 return; |
| 111 } | 109 } |
| 112 MaybeIncreaseCwnd(acked_sequence_number, bytes_in_flight); | 110 MaybeIncreaseCwnd(acked_sequence_number, bytes_in_flight); |
| 113 // 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? |
| 114 hybrid_slow_start_.OnPacketAcked(acked_sequence_number, InSlowStart()); | 112 hybrid_slow_start_.OnPacketAcked(acked_sequence_number, InSlowStart()); |
| 115 } | 113 } |
| 116 | 114 |
| 117 void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number, | 115 void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number, |
| 118 QuicByteCount bytes_in_flight) { | 116 QuicByteCount bytes_in_flight) { |
| 119 // 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 |
| 120 // 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. |
| 121 if (sequence_number <= largest_sent_at_last_cutback_) { | 119 if (sequence_number <= largest_sent_at_last_cutback_) { |
| 122 if (last_cutback_exited_slowstart_) { | 120 if (last_cutback_exited_slowstart_) { |
| 123 ++stats_->slowstart_packets_lost; | 121 ++stats_->slowstart_packets_lost; |
| 124 } | 122 } |
| 125 DVLOG(1) << "Ignoring loss for largest_missing:" << sequence_number | 123 DVLOG(1) << "Ignoring loss for largest_missing:" << sequence_number |
| 126 << " because it was sent prior to the last CWND cutback."; | 124 << " because it was sent prior to the last CWND cutback."; |
| 127 return; | 125 return; |
| 128 } | 126 } |
| 129 ++stats_->tcp_loss_events; | 127 ++stats_->tcp_loss_events; |
| 130 last_cutback_exited_slowstart_ = InSlowStart(); | 128 last_cutback_exited_slowstart_ = InSlowStart(); |
| 131 if (InSlowStart()) { | 129 if (InSlowStart()) { |
| 132 ++stats_->slowstart_packets_lost; | 130 ++stats_->slowstart_packets_lost; |
| 133 } | 131 } |
| 134 PrrOnPacketLost(bytes_in_flight); | 132 |
| 133 prr_.OnPacketLost(bytes_in_flight); |
| 135 | 134 |
| 136 if (reno_) { | 135 if (reno_) { |
| 137 congestion_window_ = congestion_window_ >> 1; | 136 congestion_window_ = congestion_window_ >> 1; |
| 138 } else { | 137 } else { |
| 139 congestion_window_ = | 138 congestion_window_ = |
| 140 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); | 139 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); |
| 141 } | 140 } |
| 142 slowstart_threshold_ = congestion_window_; | 141 slowstart_threshold_ = congestion_window_; |
| 143 // Enforce TCP's minimum congestion window of 2*MSS. | 142 // Enforce TCP's minimum congestion window of 2*MSS. |
| 144 if (congestion_window_ < kMinimumCongestionWindow) { | 143 if (congestion_window_ < kMinimumCongestionWindow) { |
| 145 congestion_window_ = kMinimumCongestionWindow; | 144 congestion_window_ = kMinimumCongestionWindow; |
| 146 } | 145 } |
| 147 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; | 146 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; |
| 148 // reset packet count from congestion avoidance mode. We start | 147 // reset packet count from congestion avoidance mode. We start |
| 149 // counting again when we're out of recovery. | 148 // counting again when we're out of recovery. |
| 150 congestion_window_count_ = 0; | 149 congestion_window_count_ = 0; |
| 151 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ | 150 DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ |
| 152 << " slowstart threshold: " << slowstart_threshold_; | 151 << " slowstart threshold: " << slowstart_threshold_; |
| 153 } | 152 } |
| 154 | 153 |
| 155 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, | 154 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, |
| 156 QuicByteCount /*bytes_in_flight*/, | 155 QuicByteCount /*bytes_in_flight*/, |
| 157 QuicPacketSequenceNumber sequence_number, | 156 QuicPacketSequenceNumber sequence_number, |
| 158 QuicByteCount bytes, | 157 QuicByteCount bytes, |
| 159 HasRetransmittableData is_retransmittable) { | 158 HasRetransmittableData is_retransmittable) { |
| 160 // Only update bytes_in_flight_ for data packets. | 159 // Only update bytes_in_flight_ for data packets. |
| 161 if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { | 160 if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { |
| 162 return false; | 161 return false; |
| 163 } | 162 } |
| 164 | 163 if (InRecovery()) { |
| 165 prr_out_ += bytes; | 164 // PRR is used when in recovery. |
| 165 prr_.OnPacketSent(bytes); |
| 166 } |
| 166 DCHECK_LT(largest_sent_sequence_number_, sequence_number); | 167 DCHECK_LT(largest_sent_sequence_number_, sequence_number); |
| 167 largest_sent_sequence_number_ = sequence_number; | 168 largest_sent_sequence_number_ = sequence_number; |
| 168 hybrid_slow_start_.OnPacketSent(sequence_number); | 169 hybrid_slow_start_.OnPacketSent(sequence_number); |
| 169 return true; | 170 return true; |
| 170 } | 171 } |
| 171 | 172 |
| 172 QuicTime::Delta TcpCubicSender::TimeUntilSend( | 173 QuicTime::Delta TcpCubicSender::TimeUntilSend( |
| 173 QuicTime /* now */, | 174 QuicTime /* now */, |
| 174 QuicByteCount bytes_in_flight, | 175 QuicByteCount bytes_in_flight, |
| 175 HasRetransmittableData has_retransmittable_data) const { | 176 HasRetransmittableData has_retransmittable_data) const { |
| 176 if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { | 177 if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { |
| 177 // For TCP we can always send an ACK immediately. | 178 // For TCP we can always send an ACK immediately. |
| 178 return QuicTime::Delta::Zero(); | 179 return QuicTime::Delta::Zero(); |
| 179 } | 180 } |
| 180 if (InRecovery()) { | 181 if (InRecovery()) { |
| 181 return PrrTimeUntilSend(bytes_in_flight); | 182 // PRR is used when in recovery. |
| 183 return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, |
| 184 slowstart_threshold_); |
| 182 } | 185 } |
| 183 if (GetCongestionWindow() > bytes_in_flight) { | 186 if (GetCongestionWindow() > bytes_in_flight) { |
| 184 return QuicTime::Delta::Zero(); | 187 return QuicTime::Delta::Zero(); |
| 185 } | 188 } |
| 186 return QuicTime::Delta::Infinite(); | 189 return QuicTime::Delta::Infinite(); |
| 187 } | 190 } |
| 188 | 191 |
| 189 QuicBandwidth TcpCubicSender::PacingRate() const { | 192 QuicBandwidth TcpCubicSender::PacingRate() const { |
| 190 // 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 |
| 191 // 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 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 void TcpCubicSender::RevertRetransmissionTimeout() { | 311 void TcpCubicSender::RevertRetransmissionTimeout() { |
| 309 if (previous_congestion_window_ == 0) { | 312 if (previous_congestion_window_ == 0) { |
| 310 LOG(DFATAL) << "No previous congestion window to revert to."; | 313 LOG(DFATAL) << "No previous congestion window to revert to."; |
| 311 return; | 314 return; |
| 312 } | 315 } |
| 313 congestion_window_ = previous_congestion_window_; | 316 congestion_window_ = previous_congestion_window_; |
| 314 slowstart_threshold_ = previous_slowstart_threshold_; | 317 slowstart_threshold_ = previous_slowstart_threshold_; |
| 315 previous_congestion_window_ = 0; | 318 previous_congestion_window_ = 0; |
| 316 } | 319 } |
| 317 | 320 |
| 318 void TcpCubicSender::PrrOnPacketLost(QuicByteCount bytes_in_flight) { | |
| 319 prr_out_ = 0; | |
| 320 bytes_in_flight_before_loss_ = bytes_in_flight; | |
| 321 prr_delivered_ = 0; | |
| 322 ack_count_since_loss_ = 0; | |
| 323 } | |
| 324 | |
| 325 void TcpCubicSender::PrrOnPacketAcked(QuicByteCount acked_bytes) { | |
| 326 prr_delivered_ += acked_bytes; | |
| 327 ++ack_count_since_loss_; | |
| 328 } | |
| 329 | |
| 330 QuicTime::Delta TcpCubicSender::PrrTimeUntilSend( | |
| 331 QuicByteCount bytes_in_flight) const { | |
| 332 DCHECK(InRecovery()); | |
| 333 // Return QuicTime::Zero In order to ensure limited transmit always works. | |
| 334 if (prr_out_ == 0 || bytes_in_flight < kMaxSegmentSize) { | |
| 335 return QuicTime::Delta::Zero(); | |
| 336 } | |
| 337 if (GetCongestionWindow() > bytes_in_flight) { | |
| 338 // During PRR-SSRB, limit outgoing packets to 1 extra MSS per ack, instead | |
| 339 // of sending the entire available window. This prevents burst retransmits | |
| 340 // when more packets are lost than the CWND reduction. | |
| 341 // limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS | |
| 342 if (prr_delivered_ + ack_count_since_loss_ * kMaxSegmentSize <= prr_out_) { | |
| 343 return QuicTime::Delta::Infinite(); | |
| 344 } | |
| 345 return QuicTime::Delta::Zero(); | |
| 346 } | |
| 347 // Implement Proportional Rate Reduction (RFC6937) | |
| 348 // Checks a simplified version of the PRR formula that doesn't use division: | |
| 349 // AvailableSendWindow = | |
| 350 // CEIL(prr_delivered * ssthresh / BytesInFlightAtLoss) - prr_sent | |
| 351 if (prr_delivered_ * slowstart_threshold_ * kMaxSegmentSize > | |
| 352 prr_out_ * bytes_in_flight_before_loss_) { | |
| 353 return QuicTime::Delta::Zero(); | |
| 354 } | |
| 355 return QuicTime::Delta::Infinite(); | |
| 356 } | |
| 357 | |
| 358 CongestionControlType TcpCubicSender::GetCongestionControlType() const { | 321 CongestionControlType TcpCubicSender::GetCongestionControlType() const { |
| 359 return reno_ ? kReno : kCubic; | 322 return reno_ ? kReno : kCubic; |
| 360 } | 323 } |
| 361 | 324 |
| 362 } // namespace net | 325 } // namespace net |
| OLD | NEW |