blob: dcd2e4a5bb2a6c0ab9a6bf7f4c1e2b0820ccc3cc [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/congestion_control/hybrid_slow_start.h"
namespace net {
// Note(pwestin): the magic clamping numbers come from the original code in
// tcp_cubic.c.
// Number of delay samples for detecting the increase of delay.
const int kHybridStartMinSamples = 8;
const int kHybridStartDelayFactorExp = 4; // 2^4 = 16
const int kHybridStartDelayMinThresholdUs = 2000;
const int kHybridStartDelayMaxThresholdUs = 16000;
HybridSlowStart::HybridSlowStart(const QuicClock* clock)
: clock_(clock),
started_(false),
found_ack_train_(false),
found_delay_(false),
end_sequence_number_(0),
sample_count_(0) {
}
void HybridSlowStart::Restart() {
found_ack_train_ = false;
found_delay_ = false;
}
void HybridSlowStart::Reset(QuicPacketSequenceNumber end_sequence_number) {
DLOG(INFO) << "Reset hybrid slow start @" << end_sequence_number;
round_start_ = last_time_ = clock_->Now();
end_sequence_number_ = end_sequence_number;
current_rtt_ = QuicTime::Delta(); // Reset to 0.
sample_count_ = 0;
started_ = true;
}
bool HybridSlowStart::EndOfRound(QuicPacketSequenceNumber ack) {
// TODO(pwestin): do we need to handle wraparound?
return end_sequence_number_ <= ack;
}
void HybridSlowStart::Update(QuicTime::Delta rtt, QuicTime::Delta delay_min) {
// The original code doesn't invoke this until we hit 16 packet per burst.
// Since the code handles lower than 16 grecefully and I removed that
// limit.
if (found_ack_train_ || found_delay_) {
return;
}
QuicTime current_time = clock_->Now();
// First detection parameter - ack-train detection.
// Since slow start burst out packets we can indirectly estimate the inter-
// arrival time by looking at the arrival time of the ACKs if the ACKs are
// spread out more then half the minimum RTT packets are beeing spread out
// more than the capacity.
// This first trigger will not come into play until we hit roughly 4.8 Mbit/s.
// TODO(pwestin): we need to make sure our pacing don't trigger this detector.
if (current_time.Subtract(last_time_).ToMicroseconds() <=
kHybridStartDelayMinThresholdUs) {
last_time_ = current_time;
if (current_time.Subtract(round_start_).ToMicroseconds() >=
(delay_min.ToMicroseconds() >> 1)) {
found_ack_train_ = true;
}
}
// Second detection parameter - delay increase detection.
// Compare the minimum delay (current_rtt_) of the current
// burst of packets relative to the minimum delay during the session.
// Note: we only look at the first few(8) packets in each burst, since we
// only want to compare the lowest RTT of the burst relative to previous
// bursts.
sample_count_++;
if (sample_count_ <= kHybridStartMinSamples) {
if (current_rtt_.IsZero() || current_rtt_ > rtt) {
current_rtt_ = rtt;
}
}
// We only need to check this once.
if (sample_count_ == kHybridStartMinSamples) {
int accepted_variance_us = delay_min.ToMicroseconds() >>
kHybridStartDelayFactorExp;
accepted_variance_us = std::min(accepted_variance_us,
kHybridStartDelayMaxThresholdUs);
QuicTime::Delta accepted_variance = QuicTime::Delta::FromMicroseconds(
std::max(accepted_variance_us, kHybridStartDelayMinThresholdUs));
if (current_rtt_ > delay_min.Add(accepted_variance)) {
found_delay_ = true;
}
}
}
bool HybridSlowStart::Exit() {
// If either one of the two conditions are met we exit from slow start
// immediately.
if (found_ack_train_ || found_delay_) {
return true;
}
return false;
}
} // namespace net