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 3 // found in the LICENSE file. 4 5 #include "net/quic/congestion_control/tcp_cubic_sender.h" 6 7 #include <algorithm> 8 9 #include "base/metrics/histogram.h" 10 11 using std::max; 12 13 namespace net { 14 15 namespace { 16 // Constants based on TCP defaults. 17 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a 18 // fast retransmission. The cwnd after a timeout is still 1. 19 const QuicTcpCongestionWindow kMinimumCongestionWindow = 2; 20 const int64 kHybridStartLowWindow = 16; 21 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; 22 const QuicByteCount kDefaultReceiveWindow = 64000; 23 const int64 kInitialCongestionWindow = 10; 24 const int kMaxBurstLength = 3; 25 // Constants used for RTT calculation. 26 const int kInitialRttMs = 60; // At a typical RTT 60 ms. 27 const float kAlpha = 0.125f; 28 const float kOneMinusAlpha = (1 - kAlpha); 29 const float kBeta = 0.25f; 30 const float kOneMinusBeta = (1 - kBeta); 31 }; // namespace 32 33 TcpCubicSender::TcpCubicSender( 34 const QuicClock* clock, 35 bool reno, 36 QuicTcpCongestionWindow max_tcp_congestion_window) 37 : hybrid_slow_start_(clock), 38 cubic_(clock), 39 reno_(reno), 40 congestion_window_count_(0), 41 receive_window_(kDefaultReceiveWindow), 42 last_received_accumulated_number_of_lost_packets_(0), 43 bytes_in_flight_(0), 44 update_end_sequence_number_(true), 45 end_sequence_number_(0), 46 largest_sent_sequence_number_(0), 47 largest_acked_sequence_number_(0), 48 largest_sent_at_last_cutback_(0), 49 congestion_window_(kInitialCongestionWindow), 50 slowstart_threshold_(max_tcp_congestion_window), 51 max_tcp_congestion_window_(max_tcp_congestion_window), 52 delay_min_(QuicTime::Delta::Zero()), 53 smoothed_rtt_(QuicTime::Delta::Zero()), 54 mean_deviation_(QuicTime::Delta::Zero()) { 55 } 56 57 TcpCubicSender::~TcpCubicSender() { 58 UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); 59 } 60 61 void TcpCubicSender::SetMaxPacketSize(QuicByteCount /*max_packet_size*/) { 62 } 63 64 void TcpCubicSender::SetFromConfig(const QuicConfig& config, bool is_server) { 65 if (is_server) { 66 // Set the initial window size. 67 congestion_window_ = config.server_initial_congestion_window(); 68 } 69 } 70 71 void TcpCubicSender::OnIncomingQuicCongestionFeedbackFrame( 72 const QuicCongestionFeedbackFrame& feedback, 73 QuicTime feedback_receive_time, 74 const SentPacketsMap& /*sent_packets*/) { 75 if (last_received_accumulated_number_of_lost_packets_ != 76 feedback.tcp.accumulated_number_of_lost_packets) { 77 int recovered_lost_packets = 78 last_received_accumulated_number_of_lost_packets_ - 79 feedback.tcp.accumulated_number_of_lost_packets; 80 last_received_accumulated_number_of_lost_packets_ = 81 feedback.tcp.accumulated_number_of_lost_packets; 82 if (recovered_lost_packets > 0) { 83 // Assume the loss could be as late as the last acked packet. 84 OnPacketLost(largest_acked_sequence_number_, feedback_receive_time); 85 } 86 } 87 receive_window_ = feedback.tcp.receive_window; 88 } 89 90 void TcpCubicSender::OnPacketAcked( 91 QuicPacketSequenceNumber acked_sequence_number, 92 QuicByteCount acked_bytes, 93 QuicTime::Delta rtt) { 94 DCHECK_GE(bytes_in_flight_, acked_bytes); 95 bytes_in_flight_ -= acked_bytes; 96 largest_acked_sequence_number_ = max(acked_sequence_number, 97 largest_acked_sequence_number_); 98 CongestionAvoidance(acked_sequence_number); 99 AckAccounting(rtt); 100 if (end_sequence_number_ == acked_sequence_number) { 101 DVLOG(1) << "Start update end sequence number @" << acked_sequence_number; 102 update_end_sequence_number_ = true; 103 } 104 } 105 106 void TcpCubicSender::OnPacketLost(QuicPacketSequenceNumber sequence_number, 107 QuicTime /*ack_receive_time*/) { 108 // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets 109 // already sent should be treated as a single loss event, since it's expected. 110 if (sequence_number <= largest_sent_at_last_cutback_) { 111 DVLOG(1) << "Ignoring loss for largest_missing:" << sequence_number 112 << " because it was sent prior to the last CWND cutback."; 113 return; 114 } 115 116 // In a normal TCP we would need to know the lowest missing packet to detect 117 // if we receive 3 missing packets. Here we get a missing packet for which we 118 // enter TCP Fast Retransmit immediately. 119 if (reno_) { 120 congestion_window_ = congestion_window_ >> 1; 121 slowstart_threshold_ = congestion_window_; 122 } else { 123 congestion_window_ = 124 cubic_.CongestionWindowAfterPacketLoss(congestion_window_); 125 slowstart_threshold_ = congestion_window_; 126 } 127 // Enforce TCP's minimimum congestion window of 2*MSS. 128 if (congestion_window_ < kMinimumCongestionWindow) { 129 congestion_window_ = kMinimumCongestionWindow; 130 } 131 largest_sent_at_last_cutback_ = largest_sent_sequence_number_; 132 DVLOG(1) << "Incoming loss; congestion window:" << congestion_window_; 133 } 134 135 bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, 136 QuicPacketSequenceNumber sequence_number, 137 QuicByteCount bytes, 138 TransmissionType transmission_type, 139 HasRetransmittableData is_retransmittable) { 140 // Only update bytes_in_flight_ for data packets. 141 if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { 142 return false; 143 } 144 145 bytes_in_flight_ += bytes; 146 if (largest_sent_sequence_number_ < sequence_number) { 147 // TODO(rch): Ensure that packets are really sent in order. 148 // DCHECK_LT(largest_sent_sequence_number_, sequence_number); 149 largest_sent_sequence_number_ = sequence_number; 150 } 151 if (transmission_type == NOT_RETRANSMISSION && update_end_sequence_number_) { 152 end_sequence_number_ = sequence_number; 153 if (AvailableSendWindow() == 0) { 154 update_end_sequence_number_ = false; 155 DVLOG(1) << "Stop update end sequence number @" << sequence_number; 156 } 157 } 158 return true; 159 } 160 161 void TcpCubicSender::OnPacketAbandoned(QuicPacketSequenceNumber sequence_number, 162 QuicByteCount abandoned_bytes) { 163 DCHECK_GE(bytes_in_flight_, abandoned_bytes); 164 bytes_in_flight_ -= abandoned_bytes; 165 } 166 167 QuicTime::Delta TcpCubicSender::TimeUntilSend( 168 QuicTime /* now */, 169 TransmissionType transmission_type, 170 HasRetransmittableData has_retransmittable_data, 171 IsHandshake handshake) { 172 if (transmission_type == NACK_RETRANSMISSION || 173 has_retransmittable_data == NO_RETRANSMITTABLE_DATA || 174 handshake == IS_HANDSHAKE) { 175 // For TCP we can always send an ACK immediately. 176 // We also immediately send any handshake packet (CHLO, etc.). We provide 177 // this special dispensation for handshake messages in QUIC, although the 178 // concept is not present in TCP. 179 return QuicTime::Delta::Zero(); 180 } 181 if (AvailableSendWindow() == 0) { 182 return QuicTime::Delta::Infinite(); 183 } 184 return QuicTime::Delta::Zero(); 185 } 186 187 QuicByteCount TcpCubicSender::AvailableSendWindow() { 188 if (bytes_in_flight_ > SendWindow()) { 189 return 0; 190 } 191 return SendWindow() - bytes_in_flight_; 192 } 193 194 QuicByteCount TcpCubicSender::SendWindow() { 195 // What's the current send window in bytes. 196 return std::min(receive_window_, GetCongestionWindow()); 197 } 198 199 QuicBandwidth TcpCubicSender::BandwidthEstimate() const { 200 return QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), 201 SmoothedRtt()); 202 } 203 204 QuicTime::Delta TcpCubicSender::SmoothedRtt() const { 205 if (smoothed_rtt_.IsZero()) { 206 return QuicTime::Delta::FromMilliseconds(kInitialRttMs); 207 } 208 return smoothed_rtt_; 209 } 210 211 QuicTime::Delta TcpCubicSender::RetransmissionDelay() const { 212 return QuicTime::Delta::FromMicroseconds( 213 smoothed_rtt_.ToMicroseconds() + 4 * mean_deviation_.ToMicroseconds()); 214 } 215 216 QuicByteCount TcpCubicSender::GetCongestionWindow() const { 217 return congestion_window_ * kMaxSegmentSize; 218 } 219 220 void TcpCubicSender::Reset() { 221 delay_min_ = QuicTime::Delta::Zero(); 222 hybrid_slow_start_.Restart(); 223 } 224 225 bool TcpCubicSender::IsCwndLimited() const { 226 const QuicByteCount congestion_window_bytes = congestion_window_ * 227 kMaxSegmentSize; 228 if (bytes_in_flight_ >= congestion_window_bytes) { 229 return true; 230 } 231 const QuicByteCount tcp_max_burst = kMaxBurstLength * kMaxSegmentSize; 232 const QuicByteCount left = congestion_window_bytes - bytes_in_flight_; 233 return left <= tcp_max_burst; 234 } 235 236 // Called when we receive an ack. Normal TCP tracks how many packets one ack 237 // represents, but quic has a separate ack for each packet. 238 void TcpCubicSender::CongestionAvoidance(QuicPacketSequenceNumber ack) { 239 if (!IsCwndLimited()) { 240 // We don't update the congestion window unless we are close to using the 241 // window we have available. 242 return; 243 } 244 if (congestion_window_ < slowstart_threshold_) { 245 // Slow start. 246 if (hybrid_slow_start_.EndOfRound(ack)) { 247 hybrid_slow_start_.Reset(end_sequence_number_); 248 } 249 // congestion_window_cnt is the number of acks since last change of snd_cwnd 250 if (congestion_window_ < max_tcp_congestion_window_) { 251 // TCP slow start, exponential growth, increase by one for each ACK. 252 congestion_window_++; 253 } 254 DVLOG(1) << "Slow start; congestion window:" << congestion_window_; 255 } else { 256 if (congestion_window_ < max_tcp_congestion_window_) { 257 if (reno_) { 258 // Classic Reno congestion avoidance provided for testing. 259 if (congestion_window_count_ >= congestion_window_) { 260 congestion_window_++; 261 congestion_window_count_ = 0; 262 } else { 263 congestion_window_count_++; 264 } 265 DVLOG(1) << "Reno; congestion window:" << congestion_window_; 266 } else { 267 congestion_window_ = std::min( 268 max_tcp_congestion_window_, 269 cubic_.CongestionWindowAfterAck(congestion_window_, delay_min_)); 270 DVLOG(1) << "Cubic; congestion window:" << congestion_window_; 271 } 272 } 273 } 274 } 275 276 void TcpCubicSender::OnRetransmissionTimeout() { 277 cubic_.Reset(); 278 congestion_window_ = kMinimumCongestionWindow; 279 } 280 281 void TcpCubicSender::AckAccounting(QuicTime::Delta rtt) { 282 if (rtt.IsInfinite() || rtt.IsZero()) { 283 DVLOG(1) << "Ignoring rtt, because it's " 284 << (rtt.IsZero() ? "Zero" : "Infinite"); 285 return; 286 } 287 // RTT can't be negative. 288 DCHECK_LT(0, rtt.ToMicroseconds()); 289 290 // TODO(pwestin): Discard delay samples right after fast recovery, 291 // during 1 second?. 292 293 // First time call or link delay decreases. 294 if (delay_min_.IsZero() || delay_min_ > rtt) { 295 delay_min_ = rtt; 296 } 297 // First time call. 298 if (smoothed_rtt_.IsZero()) { 299 smoothed_rtt_ = rtt; 300 mean_deviation_ = QuicTime::Delta::FromMicroseconds( 301 rtt.ToMicroseconds() / 2); 302 } else { 303 mean_deviation_ = QuicTime::Delta::FromMicroseconds( 304 kOneMinusBeta * mean_deviation_.ToMicroseconds() + 305 kBeta * abs(smoothed_rtt_.ToMicroseconds() - rtt.ToMicroseconds())); 306 smoothed_rtt_ = QuicTime::Delta::FromMicroseconds( 307 kOneMinusAlpha * smoothed_rtt_.ToMicroseconds() + 308 kAlpha * rtt.ToMicroseconds()); 309 DVLOG(1) << "Cubic; smoothed_rtt_:" << smoothed_rtt_.ToMicroseconds() 310 << " mean_deviation_:" << mean_deviation_.ToMicroseconds(); 311 } 312 313 // Hybrid start triggers when cwnd is larger than some threshold. 314 if (congestion_window_ <= slowstart_threshold_ && 315 congestion_window_ >= kHybridStartLowWindow) { 316 if (!hybrid_slow_start_.started()) { 317 // Time to start the hybrid slow start. 318 hybrid_slow_start_.Reset(end_sequence_number_); 319 } 320 hybrid_slow_start_.Update(rtt, delay_min_); 321 if (hybrid_slow_start_.Exit()) { 322 slowstart_threshold_ = congestion_window_; 323 } 324 } 325 } 326 327 } // namespace net 328