| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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_ |
| OLD | NEW |