Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: net/nqe/network_quality_observation.h

Issue 1942893002: Split NQE to multiple files (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 #ifndef NET_NQE_NETWORK_QUALITY_OBSERVATION_H_
6 #define NET_NQE_NETWORK_QUALITY_OBSERVATION_H_
7
8 #include <float.h>
9
10 #include <algorithm>
11 #include <deque>
12 #include <vector>
13
14 #include "base/gtest_prod_util.h"
15 #include "base/macros.h"
16 #include "base/time/time.h"
17 #include "net/base/net_export.h"
18 #include "net/nqe/network_quality_observation_source.h"
19
20 namespace net {
21
22 namespace nqe {
23
24 namespace internal {
25
26 // Records observations of network quality metrics (such as round trip time
27 // or throughput), along with the time the observation was made. Observations
28 // can be made at several places in the network stack, thus the observation
29 // source is provided as well. ValueType must be numerical so that statistics
30 // such as median, average can be computed.
31 template <typename ValueType>
32 struct NET_EXPORT_PRIVATE Observation {
33 Observation(const ValueType& value,
34 base::TimeTicks timestamp,
35 NetworkQualityObservationSource source)
36 : value(value), timestamp(timestamp), source(source) {
37 DCHECK(!timestamp.is_null());
38 }
39 ~Observation() {}
40
41 // Value of the observation.
42 const ValueType value;
43
44 // Time when the observation was taken.
45 const base::TimeTicks timestamp;
46
47 // The source of the observation.
48 const NetworkQualityObservationSource source;
49 };
50
51 // Holds an observation and its weight.
52 template <typename ValueType>
53 struct NET_EXPORT_PRIVATE WeightedObservation {
54 WeightedObservation(ValueType value, double weight)
55 : value(value), weight(weight) {}
56 WeightedObservation(const WeightedObservation& other)
57 : WeightedObservation(other.value, other.weight) {}
58
59 WeightedObservation& operator=(const WeightedObservation& other) {
60 value = other.value;
61 weight = other.weight;
62 return *this;
63 }
64
65 // Required for sorting the samples in the ascending order of values.
66 bool operator<(const WeightedObservation& other) const {
67 return (value < other.value);
68 }
69
70 // Value of the sample.
71 ValueType value;
72
73 // Weight of the sample. This is computed based on how much time has passed
74 // since the sample was taken.
75 double weight;
76 };
77
78 // Stores observations sorted by time.
79 template <typename ValueType>
80 class NET_EXPORT ObservationBuffer {
bengr 2016/05/03 21:59:45 Why not move each of these structs/class to a sepa
tbansal1 2016/05/04 22:07:24 Done.
81 public:
82 explicit ObservationBuffer(double weight_multiplier_per_second)
83 : weight_multiplier_per_second_(weight_multiplier_per_second) {
84 static_assert(kMaximumObservationsBufferSize > 0U,
85 "Minimum size of observation buffer must be > 0");
86 DCHECK_GE(weight_multiplier_per_second_, 0.0);
87 DCHECK_LE(weight_multiplier_per_second_, 1.0);
88 }
89
90 ~ObservationBuffer() {}
91
92 // Adds |observation| to the buffer. The oldest observation in the buffer
93 // will be evicted to make room if the buffer is already full.
94 void AddObservation(const Observation<ValueType>& observation) {
95 DCHECK_LE(observations_.size(),
96 static_cast<size_t>(kMaximumObservationsBufferSize));
97 // Evict the oldest element if the buffer is already full.
98 if (observations_.size() == kMaximumObservationsBufferSize)
99 observations_.pop_front();
100
101 observations_.push_back(observation);
102 DCHECK_LE(observations_.size(),
103 static_cast<size_t>(kMaximumObservationsBufferSize));
104 }
105
106 // Returns the number of observations in this buffer.
107 size_t Size() const { return observations_.size(); }
108
109 // Returns the capacity of this buffer.
110 size_t Capacity() const { return kMaximumObservationsBufferSize; }
111
112 // Clears the observations stored in this buffer.
113 void Clear() { observations_.clear(); }
114
115 // Returns true iff the |percentile| value of the observations in this
116 // buffer is available. Sets |result| to the computed |percentile|
117 // value among all observations since |begin_timestamp|. If the value is
118 // unavailable, false is returned and |result| is not modified. Percentile
119 // value is unavailable if all the values in observation buffer are older
120 // than |begin_timestamp|.
121 // |result| must not be null.
122 bool GetPercentile(const base::TimeTicks& begin_timestamp,
123 ValueType* result,
124 int percentile,
125 const std::vector<NetworkQualityObservationSource>&
126 disallowed_observation_sources) const {
127 DCHECK(result);
128 DCHECK_GE(static_cast<size_t>(kMaximumObservationsBufferSize), Size());
129 // Stores WeightedObservation in increasing order of value.
130 std::vector<WeightedObservation<ValueType>> weighted_observations;
131
132 // Total weight of all observations in |weighted_observations|.
133 double total_weight = 0.0;
134
135 ComputeWeightedObservations(begin_timestamp, weighted_observations,
136 &total_weight, disallowed_observation_sources);
137 if (weighted_observations.empty())
138 return false;
139
140 DCHECK(!weighted_observations.empty());
141 DCHECK_GT(total_weight, 0.0);
142
143 // |weighted_observations| may have a smaller size than observations_ since
144 // the former contains only the observations later than begin_timestamp.
145 DCHECK_GE(observations_.size(), weighted_observations.size());
146
147 double desired_weight = percentile / 100.0 * total_weight;
148
149 double cumulative_weight_seen_so_far = 0.0;
150 for (const auto& weighted_observation : weighted_observations) {
151 cumulative_weight_seen_so_far += weighted_observation.weight;
152
153 if (cumulative_weight_seen_so_far >= desired_weight) {
154 *result = weighted_observation.value;
155 return true;
156 }
157 }
158
159 // Computation may reach here due to floating point errors. This may happen
160 // if |percentile| was 100 (or close to 100), and |desired_weight| was
161 // slightly larger than |total_weight| (due to floating point errors).
162 // In this case, we return the highest |value| among all observations.
163 // This is same as value of the last observation in the sorted vector.
164 *result = weighted_observations.at(weighted_observations.size() - 1).value;
165 return true;
166 }
167
168 private:
169 // Maximum number of observations that can be held in the ObservationBuffer.
170 static const size_t kMaximumObservationsBufferSize = 300;
171
172 // Computes the weighted observations and stores them in
173 // |weighted_observations| sorted by ascending |WeightedObservation.value|.
174 // Only the observations with timestamp later than |begin_timestamp| are
175 // considered. Also, sets |total_weight| to the total weight of all
176 // observations. Should be called only when there is at least one
177 // observation in the buffer.
178 void ComputeWeightedObservations(
179 const base::TimeTicks& begin_timestamp,
180 std::vector<WeightedObservation<ValueType>>& weighted_observations,
181 double* total_weight,
182 const std::vector<NetworkQualityObservationSource>&
183 disallowed_observation_sources) const {
184 DCHECK_GE(static_cast<size_t>(kMaximumObservationsBufferSize), Size());
185
186 weighted_observations.clear();
187 double total_weight_observations = 0.0;
188 base::TimeTicks now = base::TimeTicks::Now();
189
190 for (const auto& observation : observations_) {
191 if (observation.timestamp < begin_timestamp)
192 continue;
193 bool disallowed = false;
194 for (const auto& disallowed_source : disallowed_observation_sources) {
195 if (disallowed_source == observation.source)
196 disallowed = true;
197 }
198 if (disallowed)
199 continue;
200 base::TimeDelta time_since_sample_taken = now - observation.timestamp;
201 double weight = pow(weight_multiplier_per_second_,
202 time_since_sample_taken.InSeconds());
203 weight = std::max(DBL_MIN, std::min(1.0, weight));
204
205 weighted_observations.push_back(
206 WeightedObservation<ValueType>(observation.value, weight));
207 total_weight_observations += weight;
208 }
209
210 // Sort the samples by value in ascending order.
211 std::sort(weighted_observations.begin(), weighted_observations.end());
212 *total_weight = total_weight_observations;
213 }
214
215 // Holds observations sorted by time, with the oldest observation at the
216 // front of the queue.
217 std::deque<Observation<ValueType>> observations_;
218
219 // The factor by which the weight of an observation reduces every second.
220 // For example, if an observation is 6 seconds old, its weight would be:
221 // weight_multiplier_per_second_ ^ 6
222 // Calculated from |kHalfLifeSeconds| by solving the following equation:
223 // weight_multiplier_per_second_ ^ kHalfLifeSeconds = 0.5
224 const double weight_multiplier_per_second_;
225
226 DISALLOW_COPY_AND_ASSIGN(ObservationBuffer);
227 };
228
229 } // namespace internal
230
231 } // namespace nqe
232
233 } // namespace net
234
235 #endif // NET_NQE_NETWORK_QUALITY_OBSERVATION_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698