summaryrefslogtreecommitdiff
path: root/chromium/net/quic/congestion_control/hybrid_slow_start.cc
blob: 8968dc94775841582f1d5276fbcfa19dab6efb3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// 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),
      round_start_(QuicTime::Zero()),
      end_sequence_number_(0),
      last_time_(QuicTime::Zero()),
      sample_count_(0),
      current_rtt_(QuicTime::Delta::Zero()) {
}

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_->ApproximateNow();
  end_sequence_number_ = end_sequence_number;
  current_rtt_ = QuicTime::Delta::Zero();
  sample_count_ = 0;
  started_ = true;
}

bool HybridSlowStart::EndOfRound(QuicPacketSequenceNumber ack) {
  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_->ApproximateNow();

  // 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;
}

QuicTime::Delta HybridSlowStart::SmoothedRtt() {
  // TODO(satyamshekhar): Calculate and return smooth average of rtt over time.
  return current_rtt_;
}

}  // namespace net