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

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

Issue 1942893002: Split NQE to multiple files (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased 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
« no previous file with comments | « net/nqe/network_quality_observation_unittest.cc ('k') | net/nqe/weighted_observation.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_OBSERVATION_BUFFER_H_
6 #define NET_NQE_OBSERVATION_BUFFER_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 #include "net/nqe/weighted_observation.h"
20
21 namespace net {
22
23 namespace nqe {
24
25 namespace internal {
26
27 // Stores observations sorted by time.
28 template <typename ValueType>
29 class NET_EXPORT_PRIVATE ObservationBuffer {
30 public:
31 explicit ObservationBuffer(double weight_multiplier_per_second)
32 : weight_multiplier_per_second_(weight_multiplier_per_second) {
33 static_assert(kMaximumObservationsBufferSize > 0U,
34 "Minimum size of observation buffer must be > 0");
35 DCHECK_GE(weight_multiplier_per_second_, 0.0);
36 DCHECK_LE(weight_multiplier_per_second_, 1.0);
37 }
38
39 ~ObservationBuffer() {}
40
41 // Adds |observation| to the buffer. The oldest observation in the buffer
42 // will be evicted to make room if the buffer is already full.
43 void AddObservation(const Observation<ValueType>& observation) {
44 DCHECK_LE(observations_.size(),
45 static_cast<size_t>(kMaximumObservationsBufferSize));
46 // Evict the oldest element if the buffer is already full.
47 if (observations_.size() == kMaximumObservationsBufferSize)
48 observations_.pop_front();
49
50 observations_.push_back(observation);
51 DCHECK_LE(observations_.size(),
52 static_cast<size_t>(kMaximumObservationsBufferSize));
53 }
54
55 // Returns the number of observations in this buffer.
56 size_t Size() const { return static_cast<size_t>(observations_.size()); }
57
58 // Returns the capacity of this buffer.
59 size_t Capacity() const {
60 return static_cast<size_t>(kMaximumObservationsBufferSize);
61 }
62
63 // Clears the observations stored in this buffer.
64 void Clear() { observations_.clear(); }
65
66 // Returns true iff the |percentile| value of the observations in this
67 // buffer is available. Sets |result| to the computed |percentile|
68 // value among all observations since |begin_timestamp|. If the value is
69 // unavailable, false is returned and |result| is not modified. Percentile
70 // value is unavailable if all the values in observation buffer are older
71 // than |begin_timestamp|.
72 // |result| must not be null.
73 bool GetPercentile(const base::TimeTicks& begin_timestamp,
74 ValueType* result,
75 int percentile,
76 const std::vector<NetworkQualityObservationSource>&
77 disallowed_observation_sources) const {
78 DCHECK(result);
79 DCHECK_GE(Capacity(), Size());
80 // Stores WeightedObservation in increasing order of value.
81 std::vector<WeightedObservation<ValueType>> weighted_observations;
82
83 // Total weight of all observations in |weighted_observations|.
84 double total_weight = 0.0;
85
86 ComputeWeightedObservations(begin_timestamp, weighted_observations,
87 &total_weight, disallowed_observation_sources);
88 if (weighted_observations.empty())
89 return false;
90
91 DCHECK(!weighted_observations.empty());
92 DCHECK_GT(total_weight, 0.0);
93
94 // |weighted_observations| may have a smaller size than observations_ since
95 // the former contains only the observations later than begin_timestamp.
96 DCHECK_GE(observations_.size(), weighted_observations.size());
97
98 double desired_weight = percentile / 100.0 * total_weight;
99
100 double cumulative_weight_seen_so_far = 0.0;
101 for (const auto& weighted_observation : weighted_observations) {
102 cumulative_weight_seen_so_far += weighted_observation.weight;
103
104 if (cumulative_weight_seen_so_far >= desired_weight) {
105 *result = weighted_observation.value;
106 return true;
107 }
108 }
109
110 // Computation may reach here due to floating point errors. This may happen
111 // if |percentile| was 100 (or close to 100), and |desired_weight| was
112 // slightly larger than |total_weight| (due to floating point errors).
113 // In this case, we return the highest |value| among all observations.
114 // This is same as value of the last observation in the sorted vector.
115 *result = weighted_observations.at(weighted_observations.size() - 1).value;
116 return true;
117 }
118
119 private:
120 // Maximum number of observations that can be held in the ObservationBuffer.
121 static const size_t kMaximumObservationsBufferSize = 300;
122
123 // Computes the weighted observations and stores them in
124 // |weighted_observations| sorted by ascending |WeightedObservation.value|.
125 // Only the observations with timestamp later than |begin_timestamp| are
126 // considered. Also, sets |total_weight| to the total weight of all
127 // observations. Should be called only when there is at least one
128 // observation in the buffer.
129 void ComputeWeightedObservations(
130 const base::TimeTicks& begin_timestamp,
131 std::vector<WeightedObservation<ValueType>>& weighted_observations,
132 double* total_weight,
133 const std::vector<NetworkQualityObservationSource>&
134 disallowed_observation_sources) const {
135 DCHECK_GE(Capacity(), Size());
136
137 weighted_observations.clear();
138 double total_weight_observations = 0.0;
139 base::TimeTicks now = base::TimeTicks::Now();
140
141 for (const auto& observation : observations_) {
142 if (observation.timestamp < begin_timestamp)
143 continue;
144 bool disallowed = false;
145 for (const auto& disallowed_source : disallowed_observation_sources) {
146 if (disallowed_source == observation.source)
147 disallowed = true;
148 }
149 if (disallowed)
150 continue;
151 base::TimeDelta time_since_sample_taken = now - observation.timestamp;
152 double weight = pow(weight_multiplier_per_second_,
153 time_since_sample_taken.InSeconds());
154 weight = std::max(DBL_MIN, std::min(1.0, weight));
155
156 weighted_observations.push_back(
157 WeightedObservation<ValueType>(observation.value, weight));
158 total_weight_observations += weight;
159 }
160
161 // Sort the samples by value in ascending order.
162 std::sort(weighted_observations.begin(), weighted_observations.end());
163 *total_weight = total_weight_observations;
164 }
165
166 // Holds observations sorted by time, with the oldest observation at the
167 // front of the queue.
168 std::deque<Observation<ValueType>> observations_;
169
170 // The factor by which the weight of an observation reduces every second.
171 // For example, if an observation is 6 seconds old, its weight would be:
172 // weight_multiplier_per_second_ ^ 6
173 // Calculated from |kHalfLifeSeconds| by solving the following equation:
174 // weight_multiplier_per_second_ ^ kHalfLifeSeconds = 0.5
175 const double weight_multiplier_per_second_;
176
177 DISALLOW_COPY_AND_ASSIGN(ObservationBuffer);
178 };
179
180 } // namespace internal
181
182 } // namespace nqe
183
184 } // namespace net
185
186 #endif // NET_NQE_OBSERVATION_BUFFER_H_
OLDNEW
« no previous file with comments | « net/nqe/network_quality_observation_unittest.cc ('k') | net/nqe/weighted_observation.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698