Home | History | Annotate | Download | only in congestion_control
      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/hybrid_slow_start.h"
      6 
      7 namespace net {
      8 
      9 // Note(pwestin): the magic clamping numbers come from the original code in
     10 // tcp_cubic.c.
     11 // Number of delay samples for detecting the increase of delay.
     12 const int kHybridStartMinSamples = 8;
     13 const int kHybridStartDelayFactorExp = 4;  // 2^4 = 16
     14 const int kHybridStartDelayMinThresholdUs = 2000;
     15 const int kHybridStartDelayMaxThresholdUs = 16000;
     16 
     17 HybridSlowStart::HybridSlowStart(const QuicClock* clock)
     18     : clock_(clock),
     19       started_(false),
     20       found_ack_train_(false),
     21       found_delay_(false),
     22       round_start_(QuicTime::Zero()),
     23       end_sequence_number_(0),
     24       last_time_(QuicTime::Zero()),
     25       sample_count_(0),
     26       current_rtt_(QuicTime::Delta::Zero()) {
     27 }
     28 
     29 void HybridSlowStart::Restart() {
     30   found_ack_train_ = false;
     31   found_delay_  = false;
     32 }
     33 
     34 void HybridSlowStart::Reset(QuicPacketSequenceNumber end_sequence_number) {
     35   DLOG(INFO) << "Reset hybrid slow start @" << end_sequence_number;
     36   round_start_ = last_time_ = clock_->ApproximateNow();
     37   end_sequence_number_ = end_sequence_number;
     38   current_rtt_ = QuicTime::Delta::Zero();
     39   sample_count_ = 0;
     40   started_ = true;
     41 }
     42 
     43 bool HybridSlowStart::EndOfRound(QuicPacketSequenceNumber ack) {
     44   return end_sequence_number_ <= ack;
     45 }
     46 
     47 void HybridSlowStart::Update(QuicTime::Delta rtt, QuicTime::Delta delay_min) {
     48   // The original code doesn't invoke this until we hit 16 packet per burst.
     49   // Since the code handles lower than 16 grecefully and I removed that
     50   // limit.
     51   if (found_ack_train_ || found_delay_) {
     52     return;
     53   }
     54   QuicTime current_time = clock_->ApproximateNow();
     55 
     56   // First detection parameter - ack-train detection.
     57   // Since slow start burst out packets we can indirectly estimate the inter-
     58   // arrival time by looking at the arrival time of the ACKs if the ACKs are
     59   // spread out more then half the minimum RTT packets are beeing spread out
     60   // more than the capacity.
     61   // This first trigger will not come into play until we hit roughly 4.8 Mbit/s.
     62   // TODO(pwestin): we need to make sure our pacing don't trigger this detector.
     63   if (current_time.Subtract(last_time_).ToMicroseconds() <=
     64       kHybridStartDelayMinThresholdUs) {
     65     last_time_ = current_time;
     66     if (current_time.Subtract(round_start_).ToMicroseconds() >=
     67         (delay_min.ToMicroseconds() >> 1)) {
     68       found_ack_train_ = true;
     69     }
     70   }
     71   // Second detection parameter - delay increase detection.
     72   // Compare the minimum delay (current_rtt_) of the current
     73   // burst of packets relative to the minimum delay during the session.
     74   // Note: we only look at the first few(8) packets in each burst, since we
     75   // only want to compare the lowest RTT of the burst relative to previous
     76   // bursts.
     77   sample_count_++;
     78   if (sample_count_ <= kHybridStartMinSamples) {
     79     if (current_rtt_.IsZero() || current_rtt_ > rtt) {
     80       current_rtt_ = rtt;
     81     }
     82   }
     83   // We only need to check this once.
     84   if (sample_count_ == kHybridStartMinSamples) {
     85     int accepted_variance_us = delay_min.ToMicroseconds() >>
     86         kHybridStartDelayFactorExp;
     87     accepted_variance_us = std::min(accepted_variance_us,
     88                                     kHybridStartDelayMaxThresholdUs);
     89     QuicTime::Delta accepted_variance = QuicTime::Delta::FromMicroseconds(
     90         std::max(accepted_variance_us, kHybridStartDelayMinThresholdUs));
     91 
     92     if (current_rtt_ > delay_min.Add(accepted_variance)) {
     93       found_delay_ = true;
     94     }
     95   }
     96 }
     97 
     98 bool HybridSlowStart::Exit() {
     99   // If either one of the two conditions are met we exit from slow start
    100   // immediately.
    101   if (found_ack_train_ || found_delay_) {
    102     return true;
    103   }
    104   return false;
    105 }
    106 
    107 QuicTime::Delta HybridSlowStart::SmoothedRtt() {
    108   // TODO(satyamshekhar): Calculate and return smooth average of rtt over time.
    109   return current_rtt_;
    110 }
    111 
    112 }  // namespace net
    113