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