tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 1 | // Copyright 2015 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_BASE_NETWORK_QUALITY_ESTIMATOR_H_ |
| 6 | #define NET_BASE_NETWORK_QUALITY_ESTIMATOR_H_ |
| 7 | |
| 8 | #include <stdint.h> |
| 9 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 10 | #include <deque> |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 11 | #include <map> |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 12 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 13 | #include "base/gtest_prod_util.h" |
| 14 | #include "base/macros.h" |
| 15 | #include "base/threading/thread_checker.h" |
| 16 | #include "base/time/time.h" |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 17 | #include "net/base/net_export.h" |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 18 | #include "net/base/network_change_notifier.h" |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 19 | #include "net/base/network_quality.h" |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 20 | |
| 21 | namespace net { |
| 22 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 23 | // NetworkQualityEstimator provides network quality estimates (quality of the |
| 24 | // full paths to all origins that have been connected to). |
| 25 | // The estimates are based on the observed organic traffic. |
| 26 | // A NetworkQualityEstimator instance is attached to URLRequestContexts and |
| 27 | // observes the traffic of URLRequests spawned from the URLRequestContexts. |
| 28 | // A single instance of NQE can be attached to multiple URLRequestContexts, |
| 29 | // thereby increasing the single NQE instance's accuracy by providing more |
| 30 | // observed traffic characteristics. |
| 31 | class NET_EXPORT_PRIVATE NetworkQualityEstimator |
| 32 | : public NetworkChangeNotifier::ConnectionTypeObserver { |
| 33 | public: |
| 34 | // Creates a new NetworkQualityEstimator. |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 35 | // |variation_params| is the map containing all field trial parameters |
| 36 | // related to NetworkQualityEstimator field trial. |
| 37 | explicit NetworkQualityEstimator( |
| 38 | const std::map<std::string, std::string>& variation_params); |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 39 | |
| 40 | ~NetworkQualityEstimator() override; |
| 41 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 42 | // Returns the peak estimates (fastest RTT and peak throughput) of the |
| 43 | // current network. |
tbansal | 99083a7 | 2015-06-09 23:44:18 | [diff] [blame] | 44 | // Virtualized for testing. |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 45 | virtual NetworkQuality GetPeakEstimate() const; |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 46 | |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 47 | // Sets |median| to the estimate of median network quality. The estimated |
| 48 | // quality is computed using a weighted median algorithm that assigns higher |
| 49 | // weight to the recent observations. |median| must not be nullptr. Returns |
| 50 | // true only if an estimate of the network quality is available (enough |
| 51 | // observations must be available to make an estimate). Virtualized for |
| 52 | // testing. |
| 53 | virtual bool GetEstimate(NetworkQuality* median) const; |
| 54 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 55 | // Notifies NetworkQualityEstimator that a response has been received. |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 56 | // |cumulative_prefilter_bytes_read| is the count of the bytes received prior |
| 57 | // to applying filters (e.g. decompression, SDCH) from request creation time |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 58 | // until now. |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 59 | // |prefiltered_bytes_read| is the count of the bytes received prior |
| 60 | // to applying filters in the most recent read. |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 61 | void NotifyDataReceived(const URLRequest& request, |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 62 | int64_t cumulative_prefilter_bytes_read, |
| 63 | int64_t prefiltered_bytes_read); |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 64 | |
| 65 | private: |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 66 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations); |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 67 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, |
| 68 | TestPeakKbpsFastestRTTUpdates); |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 69 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestAddObservation); |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 70 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ObtainOperatingParams); |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 71 | FRIEND_TEST_ALL_PREFIXES(URLRequestTestHTTP, NetworkQualityEstimator); |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 72 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, |
| 73 | PercentileSameTimestamps); |
| 74 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, |
| 75 | PercentileDifferentTimestamps); |
| 76 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ComputedPercentiles); |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 77 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 78 | // Records the round trip time or throughput observation, along with the time |
| 79 | // the observation was made. |
tbansal | 5659c35e | 2015-06-25 16:49:36 | [diff] [blame^] | 80 | struct NET_EXPORT_PRIVATE Observation { |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 81 | Observation(int32_t value, base::TimeTicks timestamp); |
| 82 | |
| 83 | ~Observation(); |
| 84 | |
| 85 | // Value of the observation. |
| 86 | const int32_t value; |
| 87 | |
| 88 | // Time when the observation was taken. |
| 89 | const base::TimeTicks timestamp; |
| 90 | }; |
| 91 | |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 92 | // Holds an observation and its weight. |
| 93 | struct WeightedObservation { |
| 94 | WeightedObservation(int32_t value, double weight) |
| 95 | : value(value), weight(weight) {} |
| 96 | WeightedObservation(const WeightedObservation& other) |
| 97 | : WeightedObservation(other.value, other.weight) {} |
| 98 | |
| 99 | WeightedObservation& operator=(const WeightedObservation& other) { |
| 100 | value = other.value; |
| 101 | weight = other.weight; |
| 102 | return *this; |
| 103 | } |
| 104 | |
| 105 | // Required for sorting the samples in the ascending order of values. |
| 106 | bool operator<(const WeightedObservation& other) const { |
| 107 | return (value < other.value); |
| 108 | } |
| 109 | |
| 110 | // Value of the sample. |
| 111 | int32_t value; |
| 112 | |
| 113 | // Weight of the sample. This is computed based on how much time has passed |
| 114 | // since the sample was taken. |
| 115 | double weight; |
| 116 | }; |
| 117 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 118 | // Stores observations sorted by time. |
tbansal | 5659c35e | 2015-06-25 16:49:36 | [diff] [blame^] | 119 | class NET_EXPORT_PRIVATE ObservationBuffer { |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 120 | public: |
| 121 | ObservationBuffer(); |
| 122 | |
| 123 | ~ObservationBuffer(); |
| 124 | |
| 125 | // Adds |observation| to the buffer. The oldest observation in the buffer |
| 126 | // will be evicted to make room if the buffer is already full. |
| 127 | void AddObservation(const Observation& observation); |
| 128 | |
| 129 | // Returns the number of observations in this buffer. |
| 130 | size_t Size() const; |
| 131 | |
| 132 | // Clears the observations stored in this buffer. |
| 133 | void Clear(); |
| 134 | |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 135 | // Returns the |percentile| value of the observations in this buffer. |
| 136 | int32_t GetPercentile(int percentile) const; |
| 137 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 138 | private: |
| 139 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations); |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 140 | FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, |
| 141 | ObtainOperatingParams); |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 142 | |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 143 | // Computes the weighted observations and stores them in |
| 144 | // |weighted_observations| sorted by ascending |WeightedObservation.value|. |
| 145 | // Sets |total_weight| to the total weight of all observations. Should be |
| 146 | // called only when there is at least one observation in the buffer. |
| 147 | void ComputeWeightedObservations( |
| 148 | std::vector<WeightedObservation>& weighted_observations, |
| 149 | double* total_weight) const; |
| 150 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 151 | // Holds observations sorted by time, with the oldest observation at the |
| 152 | // front of the queue. |
| 153 | std::deque<Observation> observations_; |
| 154 | |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 155 | // The factor by which the weight of an observation reduces every second. |
| 156 | // For example, if an observation is 6 seconds old, its weight would be: |
| 157 | // weight_multiplier_per_second_ ^ 6 |
| 158 | // Calculated from |kHalfLifeSeconds| by solving the following equation: |
| 159 | // weight_multiplier_per_second_ ^ kHalfLifeSeconds = 0.5 |
| 160 | const double weight_multiplier_per_second_; |
| 161 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 162 | DISALLOW_COPY_AND_ASSIGN(ObservationBuffer); |
| 163 | }; |
| 164 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 165 | // Tiny transfer sizes may give inaccurate throughput results. |
| 166 | // Minimum size of the transfer over which the throughput is computed. |
| 167 | static const int kMinTransferSizeInBytes = 10000; |
| 168 | |
| 169 | // Minimum duration (in microseconds) of the transfer over which the |
| 170 | // throughput is computed. |
| 171 | static const int kMinRequestDurationMicroseconds = 1000; |
| 172 | |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 173 | // Minimum valid value of the variation parameter that holds RTT (in |
| 174 | // milliseconds) values. |
| 175 | static const int kMinimumRTTVariationParameterMsec = 1; |
| 176 | |
| 177 | // Minimum valid value of the variation parameter that holds throughput (in |
| 178 | // kbps) values. |
| 179 | static const int kMinimumThroughputVariationParameterKbps = 1; |
| 180 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 181 | // Construct a NetworkQualityEstimator instance allowing for test |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 182 | // configuration. Registers for network type change notifications so estimates |
| 183 | // can be kept network specific. |
| 184 | // |variation_params| is the map containing all field trial parameters for the |
| 185 | // network quality estimator field trial. |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 186 | // |allow_local_host_requests_for_tests| should only be true when testing |
| 187 | // against local HTTP server and allows the requests to local host to be |
| 188 | // used for network quality estimation. |
tbansal | afc2c1cb | 2015-06-15 23:58:59 | [diff] [blame] | 189 | // |allow_smaller_responses_for_tests| should only be true when testing |
| 190 | // against local HTTP server and allows the responses smaller than |
| 191 | // |kMinTransferSizeInBytes| or shorter than |kMinRequestDurationMicroseconds| |
| 192 | // to be used for network quality estimation. |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 193 | NetworkQualityEstimator( |
| 194 | const std::map<std::string, std::string>& variation_params, |
| 195 | bool allow_local_host_requests_for_tests, |
| 196 | bool allow_smaller_responses_for_tests); |
| 197 | |
| 198 | // Obtains operating parameters from the field trial parameters. |
| 199 | void ObtainOperatingParams( |
| 200 | const std::map<std::string, std::string>& variation_params); |
| 201 | |
| 202 | // Adds the default median RTT and downstream throughput estimate for the |
| 203 | // current connection type to the observation buffer. |
| 204 | void AddDefaultEstimates(); |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 205 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 206 | // Returns the maximum size of the observation buffer. |
| 207 | // Used for testing. |
| 208 | size_t GetMaximumObservationBufferSizeForTests() const; |
| 209 | |
| 210 | // Returns true if the size of all observation buffers is equal to the |
| 211 | // |expected_size|. Used for testing. |
| 212 | bool VerifyBufferSizeForTests(size_t expected_size) const; |
| 213 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 214 | // NetworkChangeNotifier::ConnectionTypeObserver implementation. |
| 215 | void OnConnectionTypeChanged( |
| 216 | NetworkChangeNotifier::ConnectionType type) override; |
| 217 | |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 218 | // Returns an estimate of network quality at the specified |percentile|. |
| 219 | // |percentile| must be between 0 and 100 (both inclusive) with higher |
| 220 | // percentiles indicating less performant networks. For example, if |
| 221 | // |percentile| is 90, then the network is expected to be faster than the |
| 222 | // returned estimate with 0.9 probability. Similarly, network is expected to |
| 223 | // be slower than the returned estimate with 0.1 probability. |
| 224 | NetworkQuality GetEstimate(int percentile) const; |
| 225 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 226 | // Determines if the requests to local host can be used in estimating the |
| 227 | // network quality. Set to true only for tests. |
| 228 | const bool allow_localhost_requests_; |
| 229 | |
tbansal | afc2c1cb | 2015-06-15 23:58:59 | [diff] [blame] | 230 | // Determines if the responses smaller than |kMinTransferSizeInBytes| |
| 231 | // or shorter than |kMinTransferSizeInBytes| can be used in estimating the |
| 232 | // network quality. Set to true only for tests. |
| 233 | const bool allow_small_responses_; |
| 234 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 235 | // Time when last connection change was observed. |
| 236 | base::TimeTicks last_connection_change_; |
| 237 | |
| 238 | // Last value passed to |OnConnectionTypeChanged|. This indicates the |
| 239 | // current connection type. |
| 240 | NetworkChangeNotifier::ConnectionType current_connection_type_; |
| 241 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 242 | // Fastest round-trip-time (RTT) since last connectivity change. RTT measured |
| 243 | // from URLRequest creation until first byte received. |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 244 | base::TimeDelta fastest_rtt_since_last_connection_change_; |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 245 | |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 246 | // Rough measurement of downstream peak Kbps witnessed since last connectivity |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 247 | // change. The accuracy is decreased by ignoring these factors: |
| 248 | // 1) Multiple URLRequests can occur concurrently. |
| 249 | // 2) The transfer time includes at least one RTT while no bytes are read. |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 250 | int32_t peak_kbps_since_last_connection_change_; |
| 251 | |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 252 | // Buffer that holds Kbps observations sorted by timestamp. |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 253 | ObservationBuffer kbps_observations_; |
| 254 | |
tbansal | 11af8313 | 2015-06-24 20:34:22 | [diff] [blame] | 255 | // Buffer that holds RTT (in milliseconds) observations sorted by timestamp. |
tbansal | 6f840fc5 | 2015-06-13 03:30:34 | [diff] [blame] | 256 | ObservationBuffer rtt_msec_observations_; |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 257 | |
tbansal | b177b539 | 2015-06-25 11:13:02 | [diff] [blame] | 258 | // Default network quality observations obtained from the network quality |
| 259 | // estimator field trial parameters. The observations are indexed by |
| 260 | // ConnectionType. |
| 261 | NetworkQuality |
| 262 | default_observations_[NetworkChangeNotifier::CONNECTION_LAST + 1]; |
| 263 | |
tbansal | ea2fb8c | 2015-05-22 22:23:00 | [diff] [blame] | 264 | base::ThreadChecker thread_checker_; |
| 265 | |
| 266 | DISALLOW_COPY_AND_ASSIGN(NetworkQualityEstimator); |
| 267 | }; |
| 268 | |
| 269 | } // namespace net |
| 270 | |
| 271 | #endif // NET_BASE_NETWORK_QUALITY_ESTIMATOR_H_ |