1 // Copyright 2014 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/rtt_stats.h"
6
7 namespace net {
8
9 namespace {
10
11 // Default initial rtt used before any samples are received.
12 const int kInitialRttMs = 100;
13 const float kAlpha = 0.125f;
14 const float kOneMinusAlpha = (1 - kAlpha);
15 const float kBeta = 0.25f;
16 const float kOneMinusBeta = (1 - kBeta);
17 const float kHalfWindow = 0.5f;
18 const float kQuarterWindow = 0.25f;
19
20 } // namespace
21
RttStats()22 RttStats::RttStats()
23 : latest_rtt_(QuicTime::Delta::Zero()),
24 min_rtt_(QuicTime::Delta::Zero()),
25 smoothed_rtt_(QuicTime::Delta::Zero()),
26 mean_deviation_(QuicTime::Delta::Zero()),
27 initial_rtt_us_(kInitialRttMs * base::Time::kMicrosecondsPerMillisecond),
28 num_min_rtt_samples_remaining_(0),
29 recent_min_rtt_window_(QuicTime::Delta::Infinite()) {}
30
HasUpdates() const31 bool RttStats::HasUpdates() const {
32 return !smoothed_rtt_.IsZero();
33 }
34
SampleNewRecentMinRtt(uint32 num_samples)35 void RttStats::SampleNewRecentMinRtt(uint32 num_samples) {
36 num_min_rtt_samples_remaining_ = num_samples;
37 new_min_rtt_ = RttSample();
38 }
39
40 // Updates the RTT based on a new sample.
UpdateRtt(QuicTime::Delta send_delta,QuicTime::Delta ack_delay,QuicTime now)41 void RttStats::UpdateRtt(QuicTime::Delta send_delta,
42 QuicTime::Delta ack_delay,
43 QuicTime now) {
44 QuicTime::Delta rtt_sample(QuicTime::Delta::Zero());
45 if (send_delta > ack_delay) {
46 rtt_sample = send_delta.Subtract(ack_delay);
47 } else if (!HasUpdates()) {
48 // Even though we received information from the peer suggesting
49 // an invalid (negative) RTT, we can use the send delta as an
50 // approximation until we get a better estimate.
51 rtt_sample = send_delta;
52 }
53
54 if (rtt_sample.IsInfinite() || rtt_sample.IsZero()) {
55 DVLOG(1) << "Ignoring rtt, because it's "
56 << (rtt_sample.IsZero() ? "Zero" : "Infinite");
57 return;
58 }
59 // RTT can't be negative.
60 DCHECK_LT(0, rtt_sample.ToMicroseconds());
61
62 latest_rtt_ = rtt_sample;
63 // First time call or link delay decreases.
64 if (min_rtt_.IsZero() || min_rtt_ > rtt_sample) {
65 min_rtt_ = rtt_sample;
66 }
67 UpdateRecentMinRtt(rtt_sample, now);
68 // First time call.
69 if (!HasUpdates()) {
70 smoothed_rtt_ = rtt_sample;
71 mean_deviation_ = QuicTime::Delta::FromMicroseconds(
72 rtt_sample.ToMicroseconds() / 2);
73 } else {
74 mean_deviation_ = QuicTime::Delta::FromMicroseconds(
75 kOneMinusBeta * mean_deviation_.ToMicroseconds() +
76 kBeta * std::abs(smoothed_rtt_.Subtract(rtt_sample).ToMicroseconds()));
77 smoothed_rtt_ = smoothed_rtt_.Multiply(kOneMinusAlpha).Add(
78 rtt_sample.Multiply(kAlpha));
79 DVLOG(1) << "Cubic; smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds()
80 << " mean_deviation(us):" << mean_deviation_.ToMicroseconds();
81 }
82 }
83
UpdateRecentMinRtt(QuicTime::Delta rtt_sample,QuicTime now)84 void RttStats::UpdateRecentMinRtt(QuicTime::Delta rtt_sample, QuicTime now) {
85 // Recent min_rtt update.
86 if (num_min_rtt_samples_remaining_ > 0) {
87 --num_min_rtt_samples_remaining_;
88 if (new_min_rtt_.rtt.IsZero() || rtt_sample <= new_min_rtt_.rtt) {
89 new_min_rtt_ = RttSample(rtt_sample, now);
90 }
91 if (num_min_rtt_samples_remaining_ == 0) {
92 quarter_window_rtt_ = half_window_rtt_ = recent_min_rtt_ = new_min_rtt_;
93 }
94 }
95
96 // Update the three recent rtt samples.
97 if (recent_min_rtt_.rtt.IsZero() || rtt_sample <= recent_min_rtt_.rtt) {
98 recent_min_rtt_ = RttSample(rtt_sample, now);
99 quarter_window_rtt_ = half_window_rtt_ = recent_min_rtt_;
100 } else if (rtt_sample <= half_window_rtt_.rtt) {
101 half_window_rtt_ = RttSample(rtt_sample, now);
102 quarter_window_rtt_ = half_window_rtt_;
103 } else if (rtt_sample <= quarter_window_rtt_.rtt) {
104 quarter_window_rtt_ = RttSample(rtt_sample, now);
105 }
106
107 // Expire old min rtt samples.
108 if (recent_min_rtt_.time < now.Subtract(recent_min_rtt_window_)) {
109 recent_min_rtt_ = half_window_rtt_;
110 half_window_rtt_ = quarter_window_rtt_;
111 quarter_window_rtt_ = RttSample(rtt_sample, now);
112 } else if (half_window_rtt_.time <
113 now.Subtract(recent_min_rtt_window_.Multiply(kHalfWindow))) {
114 half_window_rtt_ = quarter_window_rtt_;
115 quarter_window_rtt_ = RttSample(rtt_sample, now);
116 } else if (quarter_window_rtt_.time <
117 now.Subtract(recent_min_rtt_window_.Multiply(kQuarterWindow))) {
118 quarter_window_rtt_ = RttSample(rtt_sample, now);
119 }
120 }
121
SmoothedRtt() const122 QuicTime::Delta RttStats::SmoothedRtt() const {
123 if (!HasUpdates()) {
124 return QuicTime::Delta::FromMicroseconds(initial_rtt_us_);
125 }
126 return smoothed_rtt_;
127 }
128
129 } // namespace net
130