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