summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.cc
blob: 2be6fa44b2a4f5ffc2777a6efd1cac921aa45d91 (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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright 2014 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 "quic/core/congestion_control/rtt_stats.h"

#include <cstdlib>  // std::abs

#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"

namespace quic {

namespace {

const float kAlpha = 0.125f;
const float kOneMinusAlpha = (1 - kAlpha);
const float kBeta = 0.25f;
const float kOneMinusBeta = (1 - kBeta);

}  // namespace

RttStats::RttStats()
    : latest_rtt_(QuicTime::Delta::Zero()),
      min_rtt_(QuicTime::Delta::Zero()),
      smoothed_rtt_(QuicTime::Delta::Zero()),
      previous_srtt_(QuicTime::Delta::Zero()),
      mean_deviation_(QuicTime::Delta::Zero()),
      calculate_standard_deviation_(false),
      initial_rtt_(QuicTime::Delta::FromMilliseconds(kInitialRttMs)),
      last_update_time_(QuicTime::Zero()),
      ignore_max_ack_delay_(false) {}

void RttStats::ExpireSmoothedMetrics() {
  mean_deviation_ = std::max(
      mean_deviation_, QuicTime::Delta::FromMicroseconds(std::abs(
                           (smoothed_rtt_ - latest_rtt_).ToMicroseconds())));
  smoothed_rtt_ = std::max(smoothed_rtt_, latest_rtt_);
}

// Updates the RTT based on a new sample.
void RttStats::UpdateRtt(QuicTime::Delta send_delta,
                         QuicTime::Delta ack_delay,
                         QuicTime now) {
  if (send_delta.IsInfinite() || send_delta <= QuicTime::Delta::Zero()) {
    QUIC_LOG_FIRST_N(WARNING, 3)
        << "Ignoring measured send_delta, because it's is "
        << "either infinite, zero, or negative.  send_delta = "
        << send_delta.ToMicroseconds();
    return;
  }

  last_update_time_ = now;

  // Update min_rtt_ first. min_rtt_ does not use an rtt_sample corrected for
  // ack_delay but the raw observed send_delta, since poor clock granularity at
  // the client may cause a high ack_delay to result in underestimation of the
  // min_rtt_.
  if (min_rtt_.IsZero() || min_rtt_ > send_delta) {
    min_rtt_ = send_delta;
  }

  QuicTime::Delta rtt_sample(send_delta);
  previous_srtt_ = smoothed_rtt_;

  if (ignore_max_ack_delay_) {
    ack_delay = QuicTime::Delta::Zero();
  }
  // Correct for ack_delay if information received from the peer results in a
  // an RTT sample at least as large as min_rtt. Otherwise, only use the
  // send_delta.
  if (rtt_sample > ack_delay) {
    if (rtt_sample - min_rtt_ >= ack_delay) {
      rtt_sample = rtt_sample - ack_delay;
    }
  }
  latest_rtt_ = rtt_sample;
  if (calculate_standard_deviation_) {
    standard_deviation_calculator_.OnNewRttSample(rtt_sample, smoothed_rtt_);
  }
  // First time call.
  if (smoothed_rtt_.IsZero()) {
    smoothed_rtt_ = rtt_sample;
    mean_deviation_ =
        QuicTime::Delta::FromMicroseconds(rtt_sample.ToMicroseconds() / 2);
  } else {
    mean_deviation_ = QuicTime::Delta::FromMicroseconds(static_cast<int64_t>(
        kOneMinusBeta * mean_deviation_.ToMicroseconds() +
        kBeta * std::abs((smoothed_rtt_ - rtt_sample).ToMicroseconds())));
    smoothed_rtt_ = kOneMinusAlpha * smoothed_rtt_ + kAlpha * rtt_sample;
    QUIC_DVLOG(1) << " smoothed_rtt(us):" << smoothed_rtt_.ToMicroseconds()
                  << " mean_deviation(us):" << mean_deviation_.ToMicroseconds();
  }
}

void RttStats::OnConnectionMigration() {
  latest_rtt_ = QuicTime::Delta::Zero();
  min_rtt_ = QuicTime::Delta::Zero();
  smoothed_rtt_ = QuicTime::Delta::Zero();
  mean_deviation_ = QuicTime::Delta::Zero();
  initial_rtt_ = QuicTime::Delta::FromMilliseconds(kInitialRttMs);
}

QuicTime::Delta RttStats::GetStandardOrMeanDeviation() const {
  QUICHE_DCHECK(calculate_standard_deviation_);
  if (!standard_deviation_calculator_.has_valid_standard_deviation) {
    return mean_deviation_;
  }
  return standard_deviation_calculator_.CalculateStandardDeviation();
}

void RttStats::StandardDeviationCaculator::OnNewRttSample(
    QuicTime::Delta rtt_sample,
    QuicTime::Delta smoothed_rtt) {
  double new_value = rtt_sample.ToMicroseconds();
  if (smoothed_rtt.IsZero()) {
    return;
  }
  has_valid_standard_deviation = true;
  const double delta = new_value - smoothed_rtt.ToMicroseconds();
  m2 = kOneMinusBeta * m2 + kBeta * pow(delta, 2);
}

QuicTime::Delta
RttStats::StandardDeviationCaculator::CalculateStandardDeviation() const {
  QUICHE_DCHECK(has_valid_standard_deviation);
  return QuicTime::Delta::FromMicroseconds(sqrt(m2));
}

void RttStats::CloneFrom(const RttStats& stats) {
  latest_rtt_ = stats.latest_rtt_;
  min_rtt_ = stats.min_rtt_;
  smoothed_rtt_ = stats.smoothed_rtt_;
  previous_srtt_ = stats.previous_srtt_;
  mean_deviation_ = stats.mean_deviation_;
  standard_deviation_calculator_ = stats.standard_deviation_calculator_;
  calculate_standard_deviation_ = stats.calculate_standard_deviation_;
  initial_rtt_ = stats.initial_rtt_;
  last_update_time_ = stats.last_update_time_;
  ignore_max_ack_delay_ = stats.ignore_max_ack_delay_;
}

}  // namespace quic