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_
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/net_export.h"
20 #include "net/base/network_change_notifier.h"
21 #include "net/base/network_quality.h"
25 // NetworkQualityEstimator provides network quality estimates (quality of the
26 // full paths to all origins that have been connected to).
27 // The estimates are based on the observed organic traffic.
28 // A NetworkQualityEstimator instance is attached to URLRequestContexts and
29 // observes the traffic of URLRequests spawned from the URLRequestContexts.
30 // A single instance of NQE can be attached to multiple URLRequestContexts,
31 // thereby increasing the single NQE instance's accuracy by providing more
32 // observed traffic characteristics.
33 class NET_EXPORT_PRIVATE NetworkQualityEstimator
34 : public NetworkChangeNotifier::ConnectionTypeObserver
{
36 // Creates a new NetworkQualityEstimator.
37 // |variation_params| is the map containing all field trial parameters
38 // related to NetworkQualityEstimator field trial.
39 explicit NetworkQualityEstimator(
40 const std::map
<std::string
, std::string
>& variation_params
);
42 ~NetworkQualityEstimator() override
;
44 // Returns the peak estimates (fastest RTT and peak throughput) of the
46 // Virtualized for testing.
47 virtual NetworkQuality
GetPeakEstimate() const;
49 // Sets |median| to the estimate of median network quality. The estimated
50 // quality is computed using a weighted median algorithm that assigns higher
51 // weight to the recent observations. |median| must not be nullptr. Returns
52 // true only if an estimate of the network quality is available (enough
53 // observations must be available to make an estimate). Virtualized for
54 // testing. If the estimate is not available, |median| is set to the default
56 virtual bool GetEstimate(NetworkQuality
* median
) const;
58 // Notifies NetworkQualityEstimator that a response has been received.
59 // |cumulative_prefilter_bytes_read| is the count of the bytes received prior
60 // to applying filters (e.g. decompression, SDCH) from request creation time
62 // |prefiltered_bytes_read| is the count of the bytes received prior
63 // to applying filters in the most recent read.
64 void NotifyDataReceived(const URLRequest
& request
,
65 int64_t cumulative_prefilter_bytes_read
,
66 int64_t prefiltered_bytes_read
);
69 // NetworkID is used to uniquely identify a network.
70 // For the purpose of network quality estimation and caching, a network is
71 // uniquely identified by a combination of |type| and
72 // |id|. This approach is unable to distinguish networks with
73 // same name (e.g., different Wi-Fi networks with same SSID).
74 // This is a protected member to expose it to tests.
75 struct NET_EXPORT_PRIVATE NetworkID
{
76 NetworkID(NetworkChangeNotifier::ConnectionType type
, const std::string
& id
)
77 : type(type
), id(id
) {}
78 NetworkID(const NetworkID
& other
) : type(other
.type
), id(other
.id
) {}
81 NetworkID
& operator=(const NetworkID
& other
) {
87 // Overloaded because NetworkID is used as key in a map.
88 bool operator<(const NetworkID
& other
) const {
89 return type
< other
.type
|| (type
== other
.type
&& id
< other
.id
);
92 // Connection type of the network.
93 NetworkChangeNotifier::ConnectionType type
;
95 // Name of this network. This is set to:
96 // - Wi-Fi SSID if the device is connected to a Wi-Fi access point and the
97 // SSID name is available, or
98 // - MCC/MNC code of the cellular carrier if the device is connected to a
99 // cellular network, or
100 // - "Ethernet" in case the device is connected to ethernet.
101 // - An empty string in all other cases or if the network name is not
102 // exposed by platform APIs.
106 // Construct a NetworkQualityEstimator instance allowing for test
107 // configuration. Registers for network type change notifications so estimates
108 // can be kept network specific.
109 // |variation_params| is the map containing all field trial parameters for the
110 // network quality estimator field trial.
111 // |allow_local_host_requests_for_tests| should only be true when testing
112 // against local HTTP server and allows the requests to local host to be
113 // used for network quality estimation.
114 // |allow_smaller_responses_for_tests| should only be true when testing.
115 // Allows the responses smaller than |kMinTransferSizeInBytes| or shorter than
116 // |kMinRequestDurationMicroseconds| to be used for network quality
118 NetworkQualityEstimator(
119 const std::map
<std::string
, std::string
>& variation_params
,
120 bool allow_local_host_requests_for_tests
,
121 bool allow_smaller_responses_for_tests
);
123 // Returns true if the cached network quality estimate was successfully read.
124 bool ReadCachedNetworkQualityEstimate();
126 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
127 void OnConnectionTypeChanged(
128 NetworkChangeNotifier::ConnectionType type
) override
;
131 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, StoreObservations
);
132 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, TestKbpsRTTUpdates
);
133 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, TestAddObservation
);
134 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, ObtainOperatingParams
);
135 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, HalfLifeParam
);
136 FRIEND_TEST_ALL_PREFIXES(URLRequestTestHTTP
, NetworkQualityEstimator
);
137 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
,
138 PercentileSameTimestamps
);
139 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
,
140 PercentileDifferentTimestamps
);
141 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, ComputedPercentiles
);
142 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, TestCaching
);
143 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
,
144 TestLRUCacheMaximumSize
);
146 // CachedNetworkQuality stores the quality of a previously seen network.
147 class NET_EXPORT_PRIVATE CachedNetworkQuality
{
149 explicit CachedNetworkQuality(const NetworkQuality
& network_quality
);
150 CachedNetworkQuality(const CachedNetworkQuality
& other
);
151 ~CachedNetworkQuality();
153 // Returns the network quality associated with this cached entry.
154 const NetworkQuality
network_quality() const { return network_quality_
; }
156 // Returns true if this cache entry was updated before
157 // |cached_network_quality|.
158 bool OlderThan(const CachedNetworkQuality
& cached_network_quality
) const;
160 // Time when this cache entry was last updated.
161 const base::TimeTicks last_update_time_
;
163 // Quality of this cached network.
164 const NetworkQuality network_quality_
;
167 DISALLOW_ASSIGN(CachedNetworkQuality
);
170 // Records the round trip time or throughput observation, along with the time
171 // the observation was made.
172 struct NET_EXPORT_PRIVATE Observation
{
173 Observation(int32_t value
, base::TimeTicks timestamp
);
176 // Value of the observation.
179 // Time when the observation was taken.
180 const base::TimeTicks timestamp
;
183 // Holds an observation and its weight.
184 struct NET_EXPORT_PRIVATE WeightedObservation
{
185 WeightedObservation(int32_t value
, double weight
)
186 : value(value
), weight(weight
) {}
187 WeightedObservation(const WeightedObservation
& other
)
188 : WeightedObservation(other
.value
, other
.weight
) {}
190 WeightedObservation
& operator=(const WeightedObservation
& other
) {
192 weight
= other
.weight
;
196 // Required for sorting the samples in the ascending order of values.
197 bool operator<(const WeightedObservation
& other
) const {
198 return (value
< other
.value
);
201 // Value of the sample.
204 // Weight of the sample. This is computed based on how much time has passed
205 // since the sample was taken.
209 // Stores observations sorted by time.
210 class NET_EXPORT_PRIVATE ObservationBuffer
{
212 explicit ObservationBuffer(double weight_multiplier_per_second
);
213 ~ObservationBuffer();
215 // Adds |observation| to the buffer. The oldest observation in the buffer
216 // will be evicted to make room if the buffer is already full.
217 void AddObservation(const Observation
& observation
);
219 // Returns the number of observations in this buffer.
222 // Clears the observations stored in this buffer.
225 // Returns the |percentile| value of the observations in this buffer.
226 int32_t GetPercentile(int percentile
) const;
229 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, StoreObservations
);
230 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
,
231 ObtainOperatingParams
);
232 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest
, HalfLifeParam
);
234 // Computes the weighted observations and stores them in
235 // |weighted_observations| sorted by ascending |WeightedObservation.value|.
236 // Sets |total_weight| to the total weight of all observations. Should be
237 // called only when there is at least one observation in the buffer.
238 void ComputeWeightedObservations(
239 std::vector
<WeightedObservation
>& weighted_observations
,
240 double* total_weight
) const;
242 // Holds observations sorted by time, with the oldest observation at the
243 // front of the queue.
244 std::deque
<Observation
> observations_
;
246 // The factor by which the weight of an observation reduces every second.
247 // For example, if an observation is 6 seconds old, its weight would be:
248 // weight_multiplier_per_second_ ^ 6
249 // Calculated from |kHalfLifeSeconds| by solving the following equation:
250 // weight_multiplier_per_second_ ^ kHalfLifeSeconds = 0.5
251 const double weight_multiplier_per_second_
;
253 DISALLOW_COPY_AND_ASSIGN(ObservationBuffer
);
256 // This does not use a unordered_map or hash_map for code simplicity (key just
257 // implements operator<, rather than hash and equality) and because the map is
259 typedef std::map
<NetworkID
, CachedNetworkQuality
> CachedNetworkQualities
;
261 // Tiny transfer sizes may give inaccurate throughput results.
262 // Minimum size of the transfer over which the throughput is computed.
263 static const int kMinTransferSizeInBytes
= 10000;
265 // Minimum duration (in microseconds) of the transfer over which the
266 // throughput is computed.
267 static const int kMinRequestDurationMicroseconds
= 1000;
269 // Minimum valid value of the variation parameter that holds RTT (in
270 // milliseconds) values.
271 static const int kMinimumRTTVariationParameterMsec
= 1;
273 // Minimum valid value of the variation parameter that holds throughput (in
275 static const int kMinimumThroughputVariationParameterKbps
= 1;
277 // Maximum size of the cache that holds network quality estimates.
278 // Smaller size may reduce the cache hit rate due to frequent evictions.
279 // Larger size may affect performance.
280 static const size_t kMaximumNetworkQualityCacheSize
= 10;
282 // Maximum number of observations that can be held in the ObservationBuffer.
283 static const size_t kMaximumObservationsBufferSize
= 300;
285 // Obtains operating parameters from the field trial parameters.
286 void ObtainOperatingParams(
287 const std::map
<std::string
, std::string
>& variation_params
);
289 // Adds the default median RTT and downstream throughput estimate for the
290 // current connection type to the observation buffer.
291 void AddDefaultEstimates();
293 // Returns an estimate of network quality at the specified |percentile|.
294 // |percentile| must be between 0 and 100 (both inclusive) with higher
295 // percentiles indicating less performant networks. For example, if
296 // |percentile| is 90, then the network is expected to be faster than the
297 // returned estimate with 0.9 probability. Similarly, network is expected to
298 // be slower than the returned estimate with 0.1 probability.
299 NetworkQuality
GetEstimate(int percentile
) const;
301 // Returns the current network ID checking by calling the platform APIs.
302 // Virtualized for testing.
303 virtual NetworkID
GetCurrentNetworkID() const;
305 // Writes the estimated quality of the current network to the cache.
306 void CacheNetworkQualityEstimate();
308 // Records the UMA related to RTT.
309 void RecordRTTUMA(int32_t estimated_value_msec
,
310 int32_t actual_value_msec
) const;
312 // Determines if the requests to local host can be used in estimating the
313 // network quality. Set to true only for tests.
314 const bool allow_localhost_requests_
;
316 // Determines if the responses smaller than |kMinTransferSizeInBytes|
317 // or shorter than |kMinTransferSizeInBytes| can be used in estimating the
318 // network quality. Set to true only for tests.
319 const bool allow_small_responses_
;
321 // Time when last connection change was observed.
322 base::TimeTicks last_connection_change_
;
324 // ID of the current network.
325 NetworkID current_network_id_
;
327 // Peak network quality (fastest round-trip-time (RTT) and highest
328 // downstream throughput) measured since last connectivity change. RTT is
329 // measured from time the request is sent until the first byte received.
330 // The accuracy is decreased by ignoring these factors:
331 // 1) Multiple URLRequests can occur concurrently.
332 // 2) Includes server processing time.
333 NetworkQuality peak_network_quality_
;
335 // Cache that stores quality of previously seen networks.
336 CachedNetworkQualities cached_network_qualities_
;
338 // Buffer that holds Kbps observations sorted by timestamp.
339 ObservationBuffer kbps_observations_
;
341 // Buffer that holds RTT (in milliseconds) observations sorted by timestamp.
342 ObservationBuffer rtt_msec_observations_
;
344 // Default network quality observations obtained from the network quality
345 // estimator field trial parameters. The observations are indexed by
348 default_observations_
[NetworkChangeNotifier::CONNECTION_LAST
+ 1];
350 // Estimated network quality. Updated on mainframe requests.
351 NetworkQuality estimated_median_network_quality_
;
353 base::ThreadChecker thread_checker_
;
355 DISALLOW_COPY_AND_ASSIGN(NetworkQualityEstimator
);
360 #endif // NET_BASE_NETWORK_QUALITY_ESTIMATOR_H_