blob: c4444438932abbf007a7a459a10b2935f08eecef [file] [log] [blame]
tbansalea2fb8c2015-05-22 22:23:001// 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
tbansal6f840fc52015-06-13 03:30:3410#include <deque>
tbansalb177b5392015-06-25 11:13:0211#include <map>
tbansal6f840fc52015-06-13 03:30:3412
tbansalea2fb8c2015-05-22 22:23:0013#include "base/gtest_prod_util.h"
14#include "base/macros.h"
15#include "base/threading/thread_checker.h"
16#include "base/time/time.h"
tbansal6f840fc52015-06-13 03:30:3417#include "net/base/net_export.h"
tbansalea2fb8c2015-05-22 22:23:0018#include "net/base/network_change_notifier.h"
tbansalb177b5392015-06-25 11:13:0219#include "net/base/network_quality.h"
tbansalea2fb8c2015-05-22 22:23:0020
21namespace net {
22
tbansalea2fb8c2015-05-22 22:23:0023// 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.
31class NET_EXPORT_PRIVATE NetworkQualityEstimator
32 : public NetworkChangeNotifier::ConnectionTypeObserver {
33 public:
34 // Creates a new NetworkQualityEstimator.
tbansalb177b5392015-06-25 11:13:0235 // |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);
tbansalea2fb8c2015-05-22 22:23:0039
40 ~NetworkQualityEstimator() override;
41
tbansal6f840fc52015-06-13 03:30:3442 // Returns the peak estimates (fastest RTT and peak throughput) of the
43 // current network.
tbansal99083a72015-06-09 23:44:1844 // Virtualized for testing.
tbansal6f840fc52015-06-13 03:30:3445 virtual NetworkQuality GetPeakEstimate() const;
tbansalea2fb8c2015-05-22 22:23:0046
tbansal11af83132015-06-24 20:34:2247 // 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
tbansalea2fb8c2015-05-22 22:23:0055 // Notifies NetworkQualityEstimator that a response has been received.
tbansal6f840fc52015-06-13 03:30:3456 // |cumulative_prefilter_bytes_read| is the count of the bytes received prior
57 // to applying filters (e.g. decompression, SDCH) from request creation time
tbansalea2fb8c2015-05-22 22:23:0058 // until now.
tbansal6f840fc52015-06-13 03:30:3459 // |prefiltered_bytes_read| is the count of the bytes received prior
60 // to applying filters in the most recent read.
tbansalea2fb8c2015-05-22 22:23:0061 void NotifyDataReceived(const URLRequest& request,
tbansal6f840fc52015-06-13 03:30:3462 int64_t cumulative_prefilter_bytes_read,
63 int64_t prefiltered_bytes_read);
tbansalea2fb8c2015-05-22 22:23:0064
65 private:
tbansal6f840fc52015-06-13 03:30:3466 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations);
tbansalea2fb8c2015-05-22 22:23:0067 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
68 TestPeakKbpsFastestRTTUpdates);
tbansal6f840fc52015-06-13 03:30:3469 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestAddObservation);
tbansalb177b5392015-06-25 11:13:0270 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ObtainOperatingParams);
tbansalea2fb8c2015-05-22 22:23:0071 FRIEND_TEST_ALL_PREFIXES(URLRequestTestHTTP, NetworkQualityEstimator);
tbansal11af83132015-06-24 20:34:2272 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
73 PercentileSameTimestamps);
74 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
75 PercentileDifferentTimestamps);
76 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ComputedPercentiles);
tbansalea2fb8c2015-05-22 22:23:0077
tbansal6f840fc52015-06-13 03:30:3478 // Records the round trip time or throughput observation, along with the time
79 // the observation was made.
tbansal5659c35e2015-06-25 16:49:3680 struct NET_EXPORT_PRIVATE Observation {
tbansal6f840fc52015-06-13 03:30:3481 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
tbansal11af83132015-06-24 20:34:2292 // 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
tbansal6f840fc52015-06-13 03:30:34118 // Stores observations sorted by time.
tbansal5659c35e2015-06-25 16:49:36119 class NET_EXPORT_PRIVATE ObservationBuffer {
tbansal6f840fc52015-06-13 03:30:34120 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
tbansal11af83132015-06-24 20:34:22135 // Returns the |percentile| value of the observations in this buffer.
136 int32_t GetPercentile(int percentile) const;
137
tbansal6f840fc52015-06-13 03:30:34138 private:
139 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations);
tbansalb177b5392015-06-25 11:13:02140 FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
141 ObtainOperatingParams);
tbansal6f840fc52015-06-13 03:30:34142
tbansal11af83132015-06-24 20:34:22143 // 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
tbansal6f840fc52015-06-13 03:30:34151 // Holds observations sorted by time, with the oldest observation at the
152 // front of the queue.
153 std::deque<Observation> observations_;
154
tbansal11af83132015-06-24 20:34:22155 // 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
tbansal6f840fc52015-06-13 03:30:34162 DISALLOW_COPY_AND_ASSIGN(ObservationBuffer);
163 };
164
tbansalea2fb8c2015-05-22 22:23:00165 // 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
tbansalb177b5392015-06-25 11:13:02173 // 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
tbansalea2fb8c2015-05-22 22:23:00181 // Construct a NetworkQualityEstimator instance allowing for test
tbansalb177b5392015-06-25 11:13:02182 // 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.
tbansalea2fb8c2015-05-22 22:23:00186 // |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.
tbansalafc2c1cb2015-06-15 23:58:59189 // |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.
tbansalb177b5392015-06-25 11:13:02193 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();
tbansalea2fb8c2015-05-22 22:23:00205
tbansal6f840fc52015-06-13 03:30:34206 // 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
tbansalea2fb8c2015-05-22 22:23:00214 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
215 void OnConnectionTypeChanged(
216 NetworkChangeNotifier::ConnectionType type) override;
217
tbansal11af83132015-06-24 20:34:22218 // 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
tbansalea2fb8c2015-05-22 22:23:00226 // 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
tbansalafc2c1cb2015-06-15 23:58:59230 // 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
tbansalea2fb8c2015-05-22 22:23:00235 // 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
tbansalea2fb8c2015-05-22 22:23:00242 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
243 // from URLRequest creation until first byte received.
tbansal6f840fc52015-06-13 03:30:34244 base::TimeDelta fastest_rtt_since_last_connection_change_;
tbansalea2fb8c2015-05-22 22:23:00245
tbansal6f840fc52015-06-13 03:30:34246 // Rough measurement of downstream peak Kbps witnessed since last connectivity
tbansalea2fb8c2015-05-22 22:23:00247 // 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.
tbansal6f840fc52015-06-13 03:30:34250 int32_t peak_kbps_since_last_connection_change_;
251
tbansal11af83132015-06-24 20:34:22252 // Buffer that holds Kbps observations sorted by timestamp.
tbansal6f840fc52015-06-13 03:30:34253 ObservationBuffer kbps_observations_;
254
tbansal11af83132015-06-24 20:34:22255 // Buffer that holds RTT (in milliseconds) observations sorted by timestamp.
tbansal6f840fc52015-06-13 03:30:34256 ObservationBuffer rtt_msec_observations_;
tbansalea2fb8c2015-05-22 22:23:00257
tbansalb177b5392015-06-25 11:13:02258 // 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
tbansalea2fb8c2015-05-22 22:23:00264 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_