Record accuracy rate for Lo-Fi.
[chromium-blink-merge.git] / net / base / network_quality_estimator.h
bloba32264f89703e90cfb600f25f82dad5ebbf8b6cc
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.
5 #ifndef NET_BASE_NETWORK_QUALITY_ESTIMATOR_H_
6 #define NET_BASE_NETWORK_QUALITY_ESTIMATOR_H_
8 #include <stdint.h>
10 #include <deque>
11 #include <map>
12 #include <string>
14 #include "base/gtest_prod_util.h"
15 #include "base/macros.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/threading/thread_checker.h"
18 #include "base/time/time.h"
19 #include "net/base/external_estimate_provider.h"
20 #include "net/base/net_export.h"
21 #include "net/base/network_change_notifier.h"
23 namespace net {
25 class URLRequest;
27 // NetworkQualityEstimator provides network quality estimates (quality of the
28 // full paths to all origins that have been connected to).
29 // The estimates are based on the observed organic traffic.
30 // A NetworkQualityEstimator instance is attached to URLRequestContexts and
31 // observes the traffic of URLRequests spawned from the URLRequestContexts.
32 // A single instance of NQE can be attached to multiple URLRequestContexts,
33 // thereby increasing the single NQE instance's accuracy by providing more
34 // observed traffic characteristics.
35 class NET_EXPORT_PRIVATE NetworkQualityEstimator
36 : public NetworkChangeNotifier::ConnectionTypeObserver,
37 public ExternalEstimateProvider::UpdatedEstimateDelegate {
38 public:
39 // Creates a new NetworkQualityEstimator.
40 // |variation_params| is the map containing all field trial parameters
41 // related to NetworkQualityEstimator field trial.
42 // |external_estimates_provider| may be NULL.
43 NetworkQualityEstimator(
44 scoped_ptr<ExternalEstimateProvider> external_estimates_provider,
45 const std::map<std::string, std::string>& variation_params);
47 ~NetworkQualityEstimator() override;
49 // Returns true if RTT is available and sets |rtt| to estimated RTT.
50 // Virtualized for testing. |rtt| should not be null.
51 virtual bool GetRTTEstimate(base::TimeDelta* rtt) const;
53 // Returns true if downlink throughput is available and sets |kbps| to
54 // estimated downlink throughput (in Kilobits per second).
55 // Virtualized for testing. |kbps| should not be null.
56 virtual bool GetDownlinkThroughputKbpsEstimate(int32_t* kbps) const;
58 // Notifies NetworkQualityEstimator that the response header of |request| has
59 // been received.
60 void NotifyHeadersReceived(const URLRequest& request);
62 // Notifies NetworkQualityEstimator that the response body of |request| has
63 // been received.
64 void NotifyRequestCompleted(const URLRequest& request);
66 // Returns true if median RTT is available and sets |rtt| to the median of
67 // RTT observations since |begin_timestamp|.
68 // Virtualized for testing. |rtt| should not be null.
69 virtual bool GetRecentMedianRTT(const base::TimeTicks& begin_timestamp,
70 base::TimeDelta* rtt) const;
72 // Returns true if median downstream throughput is available and sets |kbps|
73 // to the median of downstream Kbps observations since |begin_timestamp|.
74 // Virtualized for testing. |kbps| should not be null.
75 virtual bool GetRecentMedianDownlinkThroughputKbps(
76 const base::TimeTicks& begin_timestamp,
77 int32_t* kbps) const;
79 protected:
80 // NetworkID is used to uniquely identify a network.
81 // For the purpose of network quality estimation and caching, a network is
82 // uniquely identified by a combination of |type| and
83 // |id|. This approach is unable to distinguish networks with
84 // same name (e.g., different Wi-Fi networks with same SSID).
85 // This is a protected member to expose it to tests.
86 struct NET_EXPORT_PRIVATE NetworkID {
87 NetworkID(NetworkChangeNotifier::ConnectionType type, const std::string& id)
88 : type(type), id(id) {}
89 NetworkID(const NetworkID& other) : type(other.type), id(other.id) {}
90 ~NetworkID() {}
92 NetworkID& operator=(const NetworkID& other) {
93 type = other.type;
94 id = other.id;
95 return *this;
98 // Overloaded because NetworkID is used as key in a map.
99 bool operator<(const NetworkID& other) const {
100 return type < other.type || (type == other.type && id < other.id);
103 // Connection type of the network.
104 NetworkChangeNotifier::ConnectionType type;
106 // Name of this network. This is set to:
107 // - Wi-Fi SSID if the device is connected to a Wi-Fi access point and the
108 // SSID name is available, or
109 // - MCC/MNC code of the cellular carrier if the device is connected to a
110 // cellular network, or
111 // - "Ethernet" in case the device is connected to ethernet.
112 // - An empty string in all other cases or if the network name is not
113 // exposed by platform APIs.
114 std::string id;
117 // Construct a NetworkQualityEstimator instance allowing for test
118 // configuration. Registers for network type change notifications so estimates
119 // can be kept network specific.
120 // |external_estimates_provider| may be NULL.
121 // |variation_params| is the map containing all field trial parameters for the
122 // network quality estimator field trial.
123 // |allow_local_host_requests_for_tests| should only be true when testing
124 // against local HTTP server and allows the requests to local host to be
125 // used for network quality estimation.
126 // |allow_smaller_responses_for_tests| should only be true when testing.
127 // Allows the responses smaller than |kMinTransferSizeInBytes| or shorter than
128 // |kMinRequestDurationMicroseconds| to be used for network quality
129 // estimation.
130 NetworkQualityEstimator(
131 scoped_ptr<ExternalEstimateProvider> external_estimates_provider,
132 const std::map<std::string, std::string>& variation_params,
133 bool allow_local_host_requests_for_tests,
134 bool allow_smaller_responses_for_tests);
136 // Returns true if the cached network quality estimate was successfully read.
137 bool ReadCachedNetworkQualityEstimate();
139 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
140 void OnConnectionTypeChanged(
141 NetworkChangeNotifier::ConnectionType type) override;
143 private:
144 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations);
145 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestKbpsRTTUpdates);
146 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestAddObservation);
147 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ObtainOperatingParams);
148 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, HalfLifeParam);
149 FRIEND_TEST_ALL_PREFIXES(URLRequestTestHTTP, NetworkQualityEstimator);
150 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
151 PercentileSameTimestamps);
152 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
153 PercentileDifferentTimestamps);
154 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ComputedPercentiles);
155 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestCaching);
156 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
157 TestLRUCacheMaximumSize);
158 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestGetMedianRTTSince);
160 // NetworkQuality is used to cache the quality of a network connection.
161 class NET_EXPORT_PRIVATE NetworkQuality {
162 public:
163 NetworkQuality();
164 // |rtt| is the estimate of the round trip time.
165 // |downstream_throughput_kbps| is the estimate of the downstream
166 // throughput.
167 NetworkQuality(const base::TimeDelta& rtt,
168 int32_t downstream_throughput_kbps);
169 NetworkQuality(const NetworkQuality& other);
170 ~NetworkQuality();
172 NetworkQuality& operator=(const NetworkQuality& other);
174 // Returns the estimate of the round trip time.
175 const base::TimeDelta& rtt() const { return rtt_; }
177 // Returns the estimate of the downstream throughput in Kbps (Kilo bits per
178 // second).
179 int32_t downstream_throughput_kbps() const {
180 return downstream_throughput_kbps_;
183 private:
184 // Estimated round trip time.
185 base::TimeDelta rtt_;
187 // Estimated downstream throughput in Kbps.
188 int32_t downstream_throughput_kbps_;
191 // CachedNetworkQuality stores the quality of a previously seen network.
192 class NET_EXPORT_PRIVATE CachedNetworkQuality {
193 public:
194 explicit CachedNetworkQuality(const NetworkQuality& network_quality);
195 CachedNetworkQuality(const CachedNetworkQuality& other);
196 ~CachedNetworkQuality();
198 // Returns the network quality associated with this cached entry.
199 const NetworkQuality network_quality() const { return network_quality_; }
201 // Returns true if this cache entry was updated before
202 // |cached_network_quality|.
203 bool OlderThan(const CachedNetworkQuality& cached_network_quality) const;
205 // Time when this cache entry was last updated.
206 const base::TimeTicks last_update_time_;
208 // Quality of this cached network.
209 const NetworkQuality network_quality_;
211 private:
212 DISALLOW_ASSIGN(CachedNetworkQuality);
215 // Records the round trip time or throughput observation, along with the time
216 // the observation was made.
217 struct NET_EXPORT_PRIVATE Observation {
218 Observation(int32_t value, base::TimeTicks timestamp);
219 ~Observation();
221 // Value of the observation.
222 const int32_t value;
224 // Time when the observation was taken.
225 const base::TimeTicks timestamp;
228 // Holds an observation and its weight.
229 struct NET_EXPORT_PRIVATE WeightedObservation {
230 WeightedObservation(int32_t value, double weight)
231 : value(value), weight(weight) {}
232 WeightedObservation(const WeightedObservation& other)
233 : WeightedObservation(other.value, other.weight) {}
235 WeightedObservation& operator=(const WeightedObservation& other) {
236 value = other.value;
237 weight = other.weight;
238 return *this;
241 // Required for sorting the samples in the ascending order of values.
242 bool operator<(const WeightedObservation& other) const {
243 return (value < other.value);
246 // Value of the sample.
247 int32_t value;
249 // Weight of the sample. This is computed based on how much time has passed
250 // since the sample was taken.
251 double weight;
254 // Stores observations sorted by time.
255 class NET_EXPORT_PRIVATE ObservationBuffer {
256 public:
257 explicit ObservationBuffer(double weight_multiplier_per_second);
258 ~ObservationBuffer();
260 // Adds |observation| to the buffer. The oldest observation in the buffer
261 // will be evicted to make room if the buffer is already full.
262 void AddObservation(const Observation& observation);
264 // Returns the number of observations in this buffer.
265 size_t Size() const;
267 // Clears the observations stored in this buffer.
268 void Clear();
270 // Returns true iff the |percentile| value of the observations in this
271 // buffer is available. Sets |result| to the computed |percentile|
272 // value among all observations since |begin_timestamp|. If the value is
273 // unavailable, false is returned and |result| is not modified. Percentile
274 // value is unavailable if all the values in observation buffer are older
275 // than |begin_timestamp|.
276 // |result| must not be null.
277 bool GetPercentile(const base::TimeTicks& begin_timestamp,
278 int32_t* result,
279 int percentile) const;
281 private:
282 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations);
283 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
284 ObtainOperatingParams);
285 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, HalfLifeParam);
287 // Computes the weighted observations and stores them in
288 // |weighted_observations| sorted by ascending |WeightedObservation.value|.
289 // Only the observations with timestamp later than |begin_timestamp| are
290 // considered. Also, sets |total_weight| to the total weight of all
291 // observations. Should be called only when there is at least one
292 // observation in the buffer.
293 void ComputeWeightedObservations(
294 const base::TimeTicks& begin_timestamp,
295 std::vector<WeightedObservation>& weighted_observations,
296 double* total_weight) const;
298 // Holds observations sorted by time, with the oldest observation at the
299 // front of the queue.
300 std::deque<Observation> observations_;
302 // The factor by which the weight of an observation reduces every second.
303 // For example, if an observation is 6 seconds old, its weight would be:
304 // weight_multiplier_per_second_ ^ 6
305 // Calculated from |kHalfLifeSeconds| by solving the following equation:
306 // weight_multiplier_per_second_ ^ kHalfLifeSeconds = 0.5
307 const double weight_multiplier_per_second_;
309 DISALLOW_COPY_AND_ASSIGN(ObservationBuffer);
312 // This does not use a unordered_map or hash_map for code simplicity (key just
313 // implements operator<, rather than hash and equality) and because the map is
314 // tiny.
315 typedef std::map<NetworkID, CachedNetworkQuality> CachedNetworkQualities;
317 // Throughput is set to |kInvalidThroughput| if a valid value is
318 // unavailable. Readers should discard throughput value if it is set to
319 // |kInvalidThroughput|.
320 static const int32_t kInvalidThroughput;
322 // Tiny transfer sizes may give inaccurate throughput results.
323 // Minimum size of the transfer over which the throughput is computed.
324 static const int kMinTransferSizeInBytes = 10000;
326 // Minimum duration (in microseconds) of the transfer over which the
327 // throughput is computed.
328 static const int kMinRequestDurationMicroseconds = 1000;
330 // Minimum valid value of the variation parameter that holds RTT (in
331 // milliseconds) values.
332 static const int kMinimumRTTVariationParameterMsec = 1;
334 // Minimum valid value of the variation parameter that holds throughput (in
335 // kbps) values.
336 static const int kMinimumThroughputVariationParameterKbps = 1;
338 // Maximum size of the cache that holds network quality estimates.
339 // Smaller size may reduce the cache hit rate due to frequent evictions.
340 // Larger size may affect performance.
341 static const size_t kMaximumNetworkQualityCacheSize = 10;
343 // Maximum number of observations that can be held in the ObservationBuffer.
344 static const size_t kMaximumObservationsBufferSize = 300;
346 // Returns the RTT value to be used when the valid RTT is unavailable. Readers
347 // should discard RTT if it is set to the value returned by |InvalidRTT()|.
348 static const base::TimeDelta InvalidRTT();
350 // ExternalEstimateProvider::UpdatedEstimateObserver implementation.
351 void OnUpdatedEstimateAvailable() override;
353 // Obtains operating parameters from the field trial parameters.
354 void ObtainOperatingParams(
355 const std::map<std::string, std::string>& variation_params);
357 // Adds the default median RTT and downstream throughput estimate for the
358 // current connection type to the observation buffer.
359 void AddDefaultEstimates();
361 // Returns an estimate of network quality at the specified |percentile|.
362 // Only the observations later than |begin_timestamp| are taken into account.
363 // |percentile| must be between 0 and 100 (both inclusive) with higher
364 // percentiles indicating less performant networks. For example, if
365 // |percentile| is 90, then the network is expected to be faster than the
366 // returned estimate with 0.9 probability. Similarly, network is expected to
367 // be slower than the returned estimate with 0.1 probability.
368 base::TimeDelta GetRTTEstimateInternal(const base::TimeTicks& begin_timestamp,
369 int percentile) const;
370 int32_t GetDownlinkThroughputKbpsEstimateInternal(
371 const base::TimeTicks& begin_timestamp,
372 int percentile) const;
374 // Returns the current network ID checking by calling the platform APIs.
375 // Virtualized for testing.
376 virtual NetworkID GetCurrentNetworkID() const;
378 // Writes the estimated quality of the current network to the cache.
379 void CacheNetworkQualityEstimate();
381 // Records the UMA related to RTT.
382 void RecordRTTUMA(int32_t estimated_value_msec,
383 int32_t actual_value_msec) const;
385 // Returns true only if |request| can be used for network quality estimation.
386 // Only the requests that go over network are considered to provide useful
387 // observations.
388 bool RequestProvidesUsefulObservations(const URLRequest& request) const;
390 // Determines if the requests to local host can be used in estimating the
391 // network quality. Set to true only for tests.
392 const bool allow_localhost_requests_;
394 // Determines if the responses smaller than |kMinTransferSizeInBytes|
395 // or shorter than |kMinTransferSizeInBytes| can be used in estimating the
396 // network quality. Set to true only for tests.
397 const bool allow_small_responses_;
399 // Time when last connection change was observed.
400 base::TimeTicks last_connection_change_;
402 // ID of the current network.
403 NetworkID current_network_id_;
405 // Peak network quality (fastest round-trip-time (RTT) and highest
406 // downstream throughput) measured since last connectivity change. RTT is
407 // measured from time the request is sent until the first byte received.
408 // The accuracy is decreased by ignoring these factors:
409 // 1) Multiple URLRequests can occur concurrently.
410 // 2) Includes server processing time.
411 NetworkQuality peak_network_quality_;
413 // Cache that stores quality of previously seen networks.
414 CachedNetworkQualities cached_network_qualities_;
416 // Buffer that holds Kbps observations sorted by timestamp.
417 ObservationBuffer downstream_throughput_kbps_observations_;
419 // Buffer that holds RTT (in milliseconds) observations sorted by timestamp.
420 ObservationBuffer rtt_msec_observations_;
422 // Default network quality observations obtained from the network quality
423 // estimator field trial parameters. The observations are indexed by
424 // ConnectionType.
425 NetworkQuality
426 default_observations_[NetworkChangeNotifier::CONNECTION_LAST + 1];
428 // Estimated network quality. Updated on mainframe requests.
429 NetworkQuality estimated_median_network_quality_;
431 // ExternalEstimateProvider that provides network quality using operating
432 // system APIs. May be NULL.
433 const scoped_ptr<ExternalEstimateProvider> external_estimates_provider_;
435 base::ThreadChecker thread_checker_;
437 DISALLOW_COPY_AND_ASSIGN(NetworkQualityEstimator);
440 } // namespace net
442 #endif // NET_BASE_NETWORK_QUALITY_ESTIMATOR_H_