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

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

Issue 2411833003: NQE: Add more statistics to ObservationBuffer class (Closed)
Patch Set: Addressed bengr comments Created 4 years, 2 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 | « no previous file | net/nqe/observation_buffer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef NET_NQE_OBSERVATION_BUFFER_H_ 5 #ifndef NET_NQE_OBSERVATION_BUFFER_H_
6 #define NET_NQE_OBSERVATION_BUFFER_H_ 6 #define NET_NQE_OBSERVATION_BUFFER_H_
7 7
8 #include <float.h> 8 #include <float.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 // Returns the capacity of this buffer. 63 // Returns the capacity of this buffer.
64 size_t Capacity() const { 64 size_t Capacity() const {
65 return static_cast<size_t>(kMaximumObservationsBufferSize); 65 return static_cast<size_t>(kMaximumObservationsBufferSize);
66 } 66 }
67 67
68 // Clears the observations stored in this buffer. 68 // Clears the observations stored in this buffer.
69 void Clear() { observations_.clear(); } 69 void Clear() { observations_.clear(); }
70 70
71 // Returns true iff the |percentile| value of the observations in this 71 // Returns true iff the |percentile| value of the observations in this
72 // buffer is available. Sets |result| to the computed |percentile| 72 // buffer is available. Sets |result| to the computed |percentile|
73 // value among all observations since |begin_timestamp|. If the value is 73 // value of all observations made on or after |begin_timestamp|. If the
74 // unavailable, false is returned and |result| is not modified. Percentile 74 // value is unavailable, false is returned and |result| is not modified.
75 // value is unavailable if all the values in observation buffer are older 75 // Percentile value is unavailable if all the values in observation buffer are
76 // than |begin_timestamp|. 76 // older than |begin_timestamp|.
77 // |result| must not be null. 77 // |result| must not be null.
78 // TODO(tbansal): Move out param |result| as the last param of the function. 78 // TODO(tbansal): Move out param |result| as the last param of the function.
79 bool GetPercentile(const base::TimeTicks& begin_timestamp, 79 bool GetPercentile(base::TimeTicks begin_timestamp,
80 ValueType* result, 80 ValueType* result,
81 int percentile, 81 int percentile,
82 const std::vector<NetworkQualityObservationSource>& 82 const std::vector<NetworkQualityObservationSource>&
83 disallowed_observation_sources) const { 83 disallowed_observation_sources) const {
84 DCHECK(result); 84 // Stores weighted observations in increasing order by value.
85 DCHECK_GE(Capacity(), Size());
86 // Stores WeightedObservation in increasing order of value.
87 std::vector<WeightedObservation<ValueType>> weighted_observations; 85 std::vector<WeightedObservation<ValueType>> weighted_observations;
88 86
89 // Total weight of all observations in |weighted_observations|. 87 // Total weight of all observations in |weighted_observations|.
90 double total_weight = 0.0; 88 double total_weight = 0.0;
91 89
92 ComputeWeightedObservations(begin_timestamp, weighted_observations, 90 ComputeWeightedObservations(begin_timestamp, weighted_observations,
93 &total_weight, disallowed_observation_sources); 91 &total_weight, disallowed_observation_sources);
94 if (weighted_observations.empty()) 92 if (weighted_observations.empty())
95 return false; 93 return false;
96 94
97 DCHECK(!weighted_observations.empty());
98 DCHECK_GT(total_weight, 0.0);
99
100 // |weighted_observations| may have a smaller size than observations_ since
101 // the former contains only the observations later than begin_timestamp.
102 DCHECK_GE(observations_.size(), weighted_observations.size());
103
104 double desired_weight = percentile / 100.0 * total_weight; 95 double desired_weight = percentile / 100.0 * total_weight;
105 96
106 double cumulative_weight_seen_so_far = 0.0; 97 double cumulative_weight_seen_so_far = 0.0;
107 for (const auto& weighted_observation : weighted_observations) { 98 for (const auto& weighted_observation : weighted_observations) {
108 cumulative_weight_seen_so_far += weighted_observation.weight; 99 cumulative_weight_seen_so_far += weighted_observation.weight;
109 100
110 if (cumulative_weight_seen_so_far >= desired_weight) { 101 if (cumulative_weight_seen_so_far >= desired_weight) {
111 *result = weighted_observation.value; 102 *result = weighted_observation.value;
112 return true; 103 return true;
113 } 104 }
114 } 105 }
115 106
116 // Computation may reach here due to floating point errors. This may happen 107 // Computation may reach here due to floating point errors. This may happen
117 // if |percentile| was 100 (or close to 100), and |desired_weight| was 108 // if |percentile| was 100 (or close to 100), and |desired_weight| was
118 // slightly larger than |total_weight| (due to floating point errors). 109 // slightly larger than |total_weight| (due to floating point errors).
119 // In this case, we return the highest |value| among all observations. 110 // In this case, we return the highest |value| among all observations.
120 // This is same as value of the last observation in the sorted vector. 111 // This is same as value of the last observation in the sorted vector.
121 *result = weighted_observations.at(weighted_observations.size() - 1).value; 112 *result = weighted_observations.at(weighted_observations.size() - 1).value;
122 return true; 113 return true;
123 } 114 }
124 115
116 // Returns true iff the weighted average of the observations in this
117 // buffer is available. Sets |result| to the computed weighted average value
118 // of all observations made on or after |begin_timestamp|. If the value is
119 // unavailable, false is returned and |result| is not modified. The unweighted
120 // average value is unavailable if all the values in the observation buffer
121 // are older than |begin_timestamp|. |result| must not be null.
122 bool GetWeightedAverage(base::TimeTicks begin_timestamp,
123 const std::vector<NetworkQualityObservationSource>&
124 disallowed_observation_sources,
125 ValueType* result) const {
126 // Stores weighted observations in increasing order by value.
127 std::vector<WeightedObservation<ValueType>> weighted_observations;
128
129 // Total weight of all observations in |weighted_observations|.
130 double total_weight = 0.0;
131
132 ComputeWeightedObservations(begin_timestamp, weighted_observations,
133 &total_weight, disallowed_observation_sources);
134 if (weighted_observations.empty())
135 return false;
136
137 // Weighted average is the sum of observations times their respective
138 // weights, divided by the sum of the weights of all observations.
139 double total_weight_times_value = 0.0;
140 for (const auto& weighted_observation : weighted_observations) {
141 total_weight_times_value +=
142 (weighted_observation.weight *
143 ConvertValueTypeToDouble(weighted_observation.value));
144 }
145
146 ConvertDoubleToValueType(total_weight_times_value / total_weight, result);
147 return true;
148 }
149
150 // Returns true iff the unweighted average of the observations in this buffer
151 // is available. Sets |result| to the computed unweighted average value of
152 // all observations made on or after |begin_timestamp|. If the value is
153 // unavailable, false is returned and |result| is not modified. The weighted
154 // average value is unavailable if all the values in the observation buffer
155 // are older than |begin_timestamp|. |result| must not be null.
156 bool GetUnweightedAverage(base::TimeTicks begin_timestamp,
157 const std::vector<NetworkQualityObservationSource>&
158 disallowed_observation_sources,
159 ValueType* result) const {
160 // Stores weighted observations in increasing order by value.
161 std::vector<WeightedObservation<ValueType>> weighted_observations;
162
163 // Total weight of all observations in |weighted_observations|.
164 double total_weight = 0.0;
165
166 ComputeWeightedObservations(begin_timestamp, weighted_observations,
167 &total_weight, disallowed_observation_sources);
168 if (weighted_observations.empty())
169 return false;
170
171 // The unweighted average is the sum of all observations divided by the
172 // number of observations.
173 double total_value = 0.0;
174 for (const auto& weighted_observation : weighted_observations)
175 total_value += ConvertValueTypeToDouble(weighted_observation.value);
176
177 ConvertDoubleToValueType(total_value / weighted_observations.size(),
178 result);
179 return true;
180 }
181
125 void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock) { 182 void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock) {
126 tick_clock_ = std::move(tick_clock); 183 tick_clock_ = std::move(tick_clock);
127 } 184 }
128 185
129 private: 186 private:
130 // Maximum number of observations that can be held in the ObservationBuffer. 187 // Maximum number of observations that can be held in the ObservationBuffer.
131 static const size_t kMaximumObservationsBufferSize = 300; 188 static const size_t kMaximumObservationsBufferSize = 300;
132 189
190 // Convert different ValueTypes to double to make it possible to perform
191 // arithmetic operations on them.
192 double ConvertValueTypeToDouble(base::TimeDelta input) const {
193 return input.InMilliseconds();
194 }
195 double ConvertValueTypeToDouble(int32_t input) const { return input; }
196
197 // Convert double to different ValueTypes.
198 void ConvertDoubleToValueType(double input, base::TimeDelta* output) const {
199 *output = base::TimeDelta::FromMilliseconds(input);
200 }
201 void ConvertDoubleToValueType(double input, int32_t* output) const {
202 *output = input;
203 }
204
133 // Computes the weighted observations and stores them in 205 // Computes the weighted observations and stores them in
134 // |weighted_observations| sorted by ascending |WeightedObservation.value|. 206 // |weighted_observations| sorted by ascending |WeightedObservation.value|.
135 // Only the observations with timestamp later than |begin_timestamp| are 207 // Only the observations with timestamp later than |begin_timestamp| are
136 // considered. Also, sets |total_weight| to the total weight of all 208 // considered. Also, sets |total_weight| to the total weight of all
137 // observations. Should be called only when there is at least one 209 // observations. Should be called only when there is at least one
138 // observation in the buffer. 210 // observation in the buffer.
139 void ComputeWeightedObservations( 211 void ComputeWeightedObservations(
140 const base::TimeTicks& begin_timestamp, 212 const base::TimeTicks& begin_timestamp,
141 std::vector<WeightedObservation<ValueType>>& weighted_observations, 213 std::vector<WeightedObservation<ValueType>>& weighted_observations,
142 double* total_weight, 214 double* total_weight,
(...skipping 21 matching lines...) Expand all
164 weight = std::max(DBL_MIN, std::min(1.0, weight)); 236 weight = std::max(DBL_MIN, std::min(1.0, weight));
165 237
166 weighted_observations.push_back( 238 weighted_observations.push_back(
167 WeightedObservation<ValueType>(observation.value, weight)); 239 WeightedObservation<ValueType>(observation.value, weight));
168 total_weight_observations += weight; 240 total_weight_observations += weight;
169 } 241 }
170 242
171 // Sort the samples by value in ascending order. 243 // Sort the samples by value in ascending order.
172 std::sort(weighted_observations.begin(), weighted_observations.end()); 244 std::sort(weighted_observations.begin(), weighted_observations.end());
173 *total_weight = total_weight_observations; 245 *total_weight = total_weight_observations;
246
247 DCHECK_LE(0.0, *total_weight);
248 DCHECK(weighted_observations.empty() || 0.0 < *total_weight);
249
250 // |weighted_observations| may have a smaller size than |observations_|
251 // since the former contains only the observations later than
252 // |begin_timestamp|.
253 DCHECK_GE(observations_.size(), weighted_observations.size());
174 } 254 }
175 255
176 // Holds observations sorted by time, with the oldest observation at the 256 // Holds observations sorted by time, with the oldest observation at the
177 // front of the queue. 257 // front of the queue.
178 std::deque<Observation<ValueType>> observations_; 258 std::deque<Observation<ValueType>> observations_;
179 259
180 // The factor by which the weight of an observation reduces every second. 260 // The factor by which the weight of an observation reduces every second.
181 // For example, if an observation is 6 seconds old, its weight would be: 261 // For example, if an observation is 6 seconds old, its weight would be:
182 // weight_multiplier_per_second_ ^ 6 262 // weight_multiplier_per_second_ ^ 6
183 // Calculated from |kHalfLifeSeconds| by solving the following equation: 263 // Calculated from |kHalfLifeSeconds| by solving the following equation:
184 // weight_multiplier_per_second_ ^ kHalfLifeSeconds = 0.5 264 // weight_multiplier_per_second_ ^ kHalfLifeSeconds = 0.5
185 const double weight_multiplier_per_second_; 265 const double weight_multiplier_per_second_;
186 266
187 std::unique_ptr<base::TickClock> tick_clock_; 267 std::unique_ptr<base::TickClock> tick_clock_;
188 268
189 DISALLOW_COPY_AND_ASSIGN(ObservationBuffer); 269 DISALLOW_COPY_AND_ASSIGN(ObservationBuffer);
190 }; 270 };
191 271
192 } // namespace internal 272 } // namespace internal
193 273
194 } // namespace nqe 274 } // namespace nqe
195 275
196 } // namespace net 276 } // namespace net
197 277
198 #endif // NET_NQE_OBSERVATION_BUFFER_H_ 278 #endif // NET_NQE_OBSERVATION_BUFFER_H_
OLDNEW
« no previous file with comments | « no previous file | net/nqe/observation_buffer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698