Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: net/base/network_quality_estimator.cc

Issue 1144163008: Add in-memory caching of network quality estimates across network changes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/network_quality_estimator.h ('k') | net/base/network_quality_estimator_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 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 #include "net/base/network_quality_estimator.h" 5 #include "net/base/network_quality_estimator.h"
6 6
7 #include <float.h> 7 #include <float.h>
8 #include <algorithm> 8 #include <algorithm>
9 #include <cmath> 9 #include <cmath>
10 #include <limits> 10 #include <limits>
11 #include <string>
12 #include <vector> 11 #include <vector>
13 12
14 #include "base/logging.h" 13 #include "base/logging.h"
15 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
16 #include "base/metrics/histogram_base.h" 15 #include "base/metrics/histogram_base.h"
17 #include "base/strings/safe_sprintf.h" 16 #include "base/strings/safe_sprintf.h"
18 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_number_conversions.h"
18 #include "build/build_config.h"
19 #include "net/base/load_flags.h" 19 #include "net/base/load_flags.h"
20 #include "net/base/load_timing_info.h" 20 #include "net/base/load_timing_info.h"
21 #include "net/base/net_util.h" 21 #include "net/base/net_util.h"
22 #include "net/base/network_interfaces.h"
22 #include "net/url_request/url_request.h" 23 #include "net/url_request/url_request.h"
23 #include "url/gurl.h" 24 #include "url/gurl.h"
24 25
26 #if defined(OS_ANDROID)
27 #include "net/android/network_library.h"
28 #endif // OS_ANDROID
29
25 namespace { 30 namespace {
26 31
27 // Maximum number of observations that can be held in the ObservationBuffer.
28 const size_t kMaximumObservationsBufferSize = 300;
29
30 // Default value of the half life (in seconds) for computing time weighted 32 // Default value of the half life (in seconds) for computing time weighted
31 // percentiles. Every half life, the weight of all observations reduces by 33 // percentiles. Every half life, the weight of all observations reduces by
32 // half. Lowering the half life would reduce the weight of older values faster. 34 // half. Lowering the half life would reduce the weight of older values faster.
33 const int kDefaultHalfLifeSeconds = 60; 35 const int kDefaultHalfLifeSeconds = 60;
34 36
35 // Name of the variation parameter that holds the value of the half life (in 37 // Name of the variation parameter that holds the value of the half life (in
36 // seconds) of the observations. 38 // seconds) of the observations.
37 const char kHalfLifeSecondsParamName[] = "HalfLifeSeconds"; 39 const char kHalfLifeSecondsParamName[] = "HalfLifeSeconds";
38 40
39 // Returns a descriptive name corresponding to |connection_type|. 41 // Returns a descriptive name corresponding to |connection_type|.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 const char prefix[] = "NQE."; 110 const char prefix[] = "NQE.";
109 return base::Histogram::FactoryGet( 111 return base::Histogram::FactoryGet(
110 prefix + statistic_name + GetNameForConnectionType(type), kLowerLimit, 112 prefix + statistic_name + GetNameForConnectionType(type), kLowerLimit,
111 max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag); 113 max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag);
112 } 114 }
113 115
114 } // namespace 116 } // namespace
115 117
116 namespace net { 118 namespace net {
117 119
120 const size_t NetworkQualityEstimator::kMaximumNetworkQualityCacheSize = 10;
pauljensen 2015/07/14 11:59:03 how about initializing this in the header like the
tbansal1 2015/07/14 19:51:48 I get linking error: ../../net/base/network_qualit
pauljensen 2015/07/14 20:19:59 Can you track this down further? Use objdump or n
121
122 const size_t NetworkQualityEstimator::kMaximumObservationsBufferSize = 300;
pauljensen 2015/07/14 11:59:03 ditto
tbansal1 2015/07/14 19:51:48 See reply above.
123
118 NetworkQualityEstimator::NetworkQualityEstimator( 124 NetworkQualityEstimator::NetworkQualityEstimator(
119 const std::map<std::string, std::string>& variation_params) 125 const std::map<std::string, std::string>& variation_params)
120 : NetworkQualityEstimator(variation_params, false, false) { 126 : NetworkQualityEstimator(variation_params, false, false) {
121 } 127 }
122 128
123 NetworkQualityEstimator::NetworkQualityEstimator( 129 NetworkQualityEstimator::NetworkQualityEstimator(
124 const std::map<std::string, std::string>& variation_params, 130 const std::map<std::string, std::string>& variation_params,
125 bool allow_local_host_requests_for_tests, 131 bool allow_local_host_requests_for_tests,
126 bool allow_smaller_responses_for_tests) 132 bool allow_smaller_responses_for_tests)
127 : allow_localhost_requests_(allow_local_host_requests_for_tests), 133 : allow_localhost_requests_(allow_local_host_requests_for_tests),
128 allow_small_responses_(allow_smaller_responses_for_tests), 134 allow_small_responses_(allow_smaller_responses_for_tests),
129 last_connection_change_(base::TimeTicks::Now()), 135 last_connection_change_(base::TimeTicks::Now()),
130 current_connection_type_(NetworkChangeNotifier::GetConnectionType()), 136 current_network_id_(
131 fastest_rtt_since_last_connection_change_(NetworkQuality::InvalidRTT()), 137 NetworkID(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
132 peak_kbps_since_last_connection_change_( 138 std::string())),
133 NetworkQuality::kInvalidThroughput),
134 kbps_observations_(GetWeightMultiplierPerSecond(variation_params)), 139 kbps_observations_(GetWeightMultiplierPerSecond(variation_params)),
135 rtt_msec_observations_(GetWeightMultiplierPerSecond(variation_params)) { 140 rtt_msec_observations_(GetWeightMultiplierPerSecond(variation_params)) {
136 static_assert(kMinRequestDurationMicroseconds > 0, 141 static_assert(kMinRequestDurationMicroseconds > 0,
137 "Minimum request duration must be > 0"); 142 "Minimum request duration must be > 0");
138 static_assert(kDefaultHalfLifeSeconds > 0, 143 static_assert(kDefaultHalfLifeSeconds > 0,
139 "Default half life duration must be > 0"); 144 "Default half life duration must be > 0");
145 static_assert(kMaximumNetworkQualityCacheSize > 0,
146 "Size of the network quality cache must be > 0");
147 // This limit should not be increased unless the logic for removing the
148 // oldest cache entry is rewritten to use a doubly-linked-list LRU queue.
149 static_assert(kMaximumNetworkQualityCacheSize <= 10,
150 "Size of the network quality cache must <= 10");
140 151
141 ObtainOperatingParams(variation_params); 152 ObtainOperatingParams(variation_params);
153 NetworkChangeNotifier::AddConnectionTypeObserver(this);
154 current_network_id_ = GetCurrentNetworkID();
142 AddDefaultEstimates(); 155 AddDefaultEstimates();
143 NetworkChangeNotifier::AddConnectionTypeObserver(this);
144 } 156 }
145 157
146 void NetworkQualityEstimator::ObtainOperatingParams( 158 void NetworkQualityEstimator::ObtainOperatingParams(
147 const std::map<std::string, std::string>& variation_params) { 159 const std::map<std::string, std::string>& variation_params) {
148 DCHECK(thread_checker_.CalledOnValidThread()); 160 DCHECK(thread_checker_.CalledOnValidThread());
149 161
150 for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) { 162 for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) {
151 NetworkChangeNotifier::ConnectionType type = 163 NetworkChangeNotifier::ConnectionType type =
152 static_cast<NetworkChangeNotifier::ConnectionType>(i); 164 static_cast<NetworkChangeNotifier::ConnectionType>(i);
153 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1; 165 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1;
(...skipping 21 matching lines...) Expand all
175 base::StringToInt(it->second, &variations_value) && 187 base::StringToInt(it->second, &variations_value) &&
176 variations_value >= kMinimumThroughputVariationParameterKbps) { 188 variations_value >= kMinimumThroughputVariationParameterKbps) {
177 default_observations_[i] = 189 default_observations_[i] =
178 NetworkQuality(default_observations_[i].rtt(), variations_value); 190 NetworkQuality(default_observations_[i].rtt(), variations_value);
179 } 191 }
180 } 192 }
181 } 193 }
182 194
183 void NetworkQualityEstimator::AddDefaultEstimates() { 195 void NetworkQualityEstimator::AddDefaultEstimates() {
184 DCHECK(thread_checker_.CalledOnValidThread()); 196 DCHECK(thread_checker_.CalledOnValidThread());
185 197 if (default_observations_[current_network_id_.type].rtt() !=
186 if (default_observations_[current_connection_type_].rtt() !=
187 NetworkQuality::InvalidRTT()) { 198 NetworkQuality::InvalidRTT()) {
188 rtt_msec_observations_.AddObservation(Observation( 199 rtt_msec_observations_.AddObservation(Observation(
189 default_observations_[current_connection_type_].rtt().InMilliseconds(), 200 default_observations_[current_network_id_.type].rtt().InMilliseconds(),
190 base::TimeTicks::Now())); 201 base::TimeTicks::Now()));
191 } 202 }
192 203 if (default_observations_[current_network_id_.type]
193 if (default_observations_[current_connection_type_]
194 .downstream_throughput_kbps() != NetworkQuality::kInvalidThroughput) { 204 .downstream_throughput_kbps() != NetworkQuality::kInvalidThroughput) {
195 kbps_observations_.AddObservation( 205 kbps_observations_.AddObservation(
196 Observation(default_observations_[current_connection_type_] 206 Observation(default_observations_[current_network_id_.type]
197 .downstream_throughput_kbps(), 207 .downstream_throughput_kbps(),
198 base::TimeTicks::Now())); 208 base::TimeTicks::Now()));
199 } 209 }
200 } 210 }
201 211
202 NetworkQualityEstimator::~NetworkQualityEstimator() { 212 NetworkQualityEstimator::~NetworkQualityEstimator() {
203 DCHECK(thread_checker_.CalledOnValidThread()); 213 DCHECK(thread_checker_.CalledOnValidThread());
204 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); 214 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
205 } 215 }
206 216
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 253
244 // Time when the headers were received. 254 // Time when the headers were received.
245 base::TimeTicks headers_received_time = load_timing_info.receive_headers_end; 255 base::TimeTicks headers_received_time = load_timing_info.receive_headers_end;
246 256
247 // Only add RTT observation if this is the first read for this response. 257 // Only add RTT observation if this is the first read for this response.
248 if (cumulative_prefilter_bytes_read == prefiltered_bytes_read) { 258 if (cumulative_prefilter_bytes_read == prefiltered_bytes_read) {
249 // Duration between when the resource was requested and when response 259 // Duration between when the resource was requested and when response
250 // headers were received. 260 // headers were received.
251 base::TimeDelta observed_rtt = headers_received_time - request_start_time; 261 base::TimeDelta observed_rtt = headers_received_time - request_start_time;
252 DCHECK_GE(observed_rtt, base::TimeDelta()); 262 DCHECK_GE(observed_rtt, base::TimeDelta());
253 if (observed_rtt < fastest_rtt_since_last_connection_change_) 263 if (observed_rtt < peak_network_quality_.rtt()) {
254 fastest_rtt_since_last_connection_change_ = observed_rtt; 264 peak_network_quality_ = NetworkQuality(
265 observed_rtt, peak_network_quality_.downstream_throughput_kbps());
266 }
255 267
256 rtt_msec_observations_.AddObservation( 268 rtt_msec_observations_.AddObservation(
257 Observation(observed_rtt.InMilliseconds(), now)); 269 Observation(observed_rtt.InMilliseconds(), now));
258 270
259 // Compare the RTT observation with the estimated value and record it. 271 // Compare the RTT observation with the estimated value and record it.
260 if (estimated_median_network_quality_.rtt() != 272 if (estimated_median_network_quality_.rtt() !=
261 NetworkQuality::InvalidRTT()) { 273 NetworkQuality::InvalidRTT()) {
262 RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(), 274 RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(),
263 observed_rtt.InMilliseconds()); 275 observed_rtt.InMilliseconds());
264 } 276 }
(...skipping 20 matching lines...) Expand all
285 kbps_f = std::numeric_limits<int32_t>::max() - 1; 297 kbps_f = std::numeric_limits<int32_t>::max() - 1;
286 298
287 int32_t kbps = static_cast<int32_t>(kbps_f); 299 int32_t kbps = static_cast<int32_t>(kbps_f);
288 300
289 // If the |kbps| is less than 1, we set it to 1 to differentiate from case 301 // If the |kbps| is less than 1, we set it to 1 to differentiate from case
290 // when there is no connection. 302 // when there is no connection.
291 if (kbps_f > 0.0 && kbps == 0) 303 if (kbps_f > 0.0 && kbps == 0)
292 kbps = 1; 304 kbps = 1;
293 305
294 if (kbps > 0) { 306 if (kbps > 0) {
295 if (kbps > peak_kbps_since_last_connection_change_) 307 if (kbps > peak_network_quality_.downstream_throughput_kbps()) {
296 peak_kbps_since_last_connection_change_ = kbps; 308 peak_network_quality_ =
309 NetworkQuality(peak_network_quality_.rtt(), kbps);
310 }
297 311
298 kbps_observations_.AddObservation(Observation(kbps, now)); 312 kbps_observations_.AddObservation(Observation(kbps, now));
299 } 313 }
300 } 314 }
301 } 315 }
302 316
303 void NetworkQualityEstimator::RecordRTTUMA(int32_t estimated_value_msec, 317 void NetworkQualityEstimator::RecordRTTUMA(int32_t estimated_value_msec,
304 int32_t actual_value_msec) const { 318 int32_t actual_value_msec) const {
305 DCHECK(thread_checker_.CalledOnValidThread()); 319 DCHECK(thread_checker_.CalledOnValidThread());
306 320
307 // Record the difference between the actual and the estimated value. 321 // Record the difference between the actual and the estimated value.
308 if (estimated_value_msec >= actual_value_msec) { 322 if (estimated_value_msec >= actual_value_msec) {
309 base::HistogramBase* difference_rtt = 323 base::HistogramBase* difference_rtt =
310 GetHistogram("DifferenceRTTEstimatedAndActual.", 324 GetHistogram("DifferenceRTTEstimatedAndActual.",
311 current_connection_type_, 10 * 1000); // 10 seconds 325 current_network_id_.type, 10 * 1000); // 10 seconds
312 difference_rtt->Add(estimated_value_msec - actual_value_msec); 326 difference_rtt->Add(estimated_value_msec - actual_value_msec);
313 } else { 327 } else {
314 base::HistogramBase* difference_rtt = 328 base::HistogramBase* difference_rtt =
315 GetHistogram("DifferenceRTTActualAndEstimated.", 329 GetHistogram("DifferenceRTTActualAndEstimated.",
316 current_connection_type_, 10 * 1000); // 10 seconds 330 current_network_id_.type, 10 * 1000); // 10 seconds
317 difference_rtt->Add(actual_value_msec - estimated_value_msec); 331 difference_rtt->Add(actual_value_msec - estimated_value_msec);
318 } 332 }
319 333
320 // Record all the RTT observations. 334 // Record all the RTT observations.
321 base::HistogramBase* rtt_observations = 335 base::HistogramBase* rtt_observations =
322 GetHistogram("RTTObservations.", current_connection_type_, 336 GetHistogram("RTTObservations.", current_network_id_.type,
323 10 * 1000); // 10 seconds upper bound 337 10 * 1000); // 10 seconds upper bound
324 rtt_observations->Add(actual_value_msec); 338 rtt_observations->Add(actual_value_msec);
325 339
326 if (actual_value_msec == 0) 340 if (actual_value_msec == 0)
327 return; 341 return;
328 342
329 int32 ratio = (estimated_value_msec * 100) / actual_value_msec; 343 int32 ratio = (estimated_value_msec * 100) / actual_value_msec;
330 344
331 // Record the accuracy of estimation by recording the ratio of estimated 345 // Record the accuracy of estimation by recording the ratio of estimated
332 // value to the actual value. 346 // value to the actual value.
333 base::HistogramBase* ratio_median_rtt = GetHistogram( 347 base::HistogramBase* ratio_median_rtt = GetHistogram(
334 "RatioEstimatedToActualRTT.", current_connection_type_, 1000); 348 "RatioEstimatedToActualRTT.", current_network_id_.type, 1000);
335 ratio_median_rtt->Add(ratio); 349 ratio_median_rtt->Add(ratio);
336 } 350 }
337 351
338 void NetworkQualityEstimator::OnConnectionTypeChanged( 352 void NetworkQualityEstimator::OnConnectionTypeChanged(
339 NetworkChangeNotifier::ConnectionType type) { 353 NetworkChangeNotifier::ConnectionType type) {
340 DCHECK(thread_checker_.CalledOnValidThread()); 354 DCHECK(thread_checker_.CalledOnValidThread());
341 if (fastest_rtt_since_last_connection_change_ != 355 if (peak_network_quality_.rtt() != NetworkQuality::InvalidRTT()) {
342 NetworkQuality::InvalidRTT()) { 356 switch (current_network_id_.type) {
343 switch (current_connection_type_) {
344 case NetworkChangeNotifier::CONNECTION_UNKNOWN: 357 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
345 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", 358 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown",
346 fastest_rtt_since_last_connection_change_); 359 peak_network_quality_.rtt());
347 break; 360 break;
348 case NetworkChangeNotifier::CONNECTION_ETHERNET: 361 case NetworkChangeNotifier::CONNECTION_ETHERNET:
349 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", 362 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet",
350 fastest_rtt_since_last_connection_change_); 363 peak_network_quality_.rtt());
351 break; 364 break;
352 case NetworkChangeNotifier::CONNECTION_WIFI: 365 case NetworkChangeNotifier::CONNECTION_WIFI:
353 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", 366 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", peak_network_quality_.rtt());
354 fastest_rtt_since_last_connection_change_);
355 break; 367 break;
356 case NetworkChangeNotifier::CONNECTION_2G: 368 case NetworkChangeNotifier::CONNECTION_2G:
357 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.2G", 369 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.2G", peak_network_quality_.rtt());
358 fastest_rtt_since_last_connection_change_);
359 break; 370 break;
360 case NetworkChangeNotifier::CONNECTION_3G: 371 case NetworkChangeNotifier::CONNECTION_3G:
361 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.3G", 372 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.3G", peak_network_quality_.rtt());
362 fastest_rtt_since_last_connection_change_);
363 break; 373 break;
364 case NetworkChangeNotifier::CONNECTION_4G: 374 case NetworkChangeNotifier::CONNECTION_4G:
365 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.4G", 375 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.4G", peak_network_quality_.rtt());
366 fastest_rtt_since_last_connection_change_);
367 break; 376 break;
368 case NetworkChangeNotifier::CONNECTION_NONE: 377 case NetworkChangeNotifier::CONNECTION_NONE:
369 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", 378 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", peak_network_quality_.rtt());
370 fastest_rtt_since_last_connection_change_);
371 break; 379 break;
372 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 380 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
373 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", 381 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth",
374 fastest_rtt_since_last_connection_change_); 382 peak_network_quality_.rtt());
375 break; 383 break;
376 default: 384 default:
377 NOTREACHED(); 385 NOTREACHED() << "Unexpected connection type = "
386 << current_network_id_.type;
378 break; 387 break;
379 } 388 }
380 } 389 }
381 390
382 if (peak_kbps_since_last_connection_change_ != 391 if (peak_network_quality_.downstream_throughput_kbps() !=
383 NetworkQuality::kInvalidThroughput) { 392 NetworkQuality::kInvalidThroughput) {
384 switch (current_connection_type_) { 393 switch (current_network_id_.type) {
385 case NetworkChangeNotifier::CONNECTION_UNKNOWN: 394 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
386 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", 395 UMA_HISTOGRAM_COUNTS(
387 peak_kbps_since_last_connection_change_); 396 "NQE.PeakKbps.Unknown",
397 peak_network_quality_.downstream_throughput_kbps());
388 break; 398 break;
389 case NetworkChangeNotifier::CONNECTION_ETHERNET: 399 case NetworkChangeNotifier::CONNECTION_ETHERNET:
390 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet", 400 UMA_HISTOGRAM_COUNTS(
391 peak_kbps_since_last_connection_change_); 401 "NQE.PeakKbps.Ethernet",
402 peak_network_quality_.downstream_throughput_kbps());
392 break; 403 break;
393 case NetworkChangeNotifier::CONNECTION_WIFI: 404 case NetworkChangeNotifier::CONNECTION_WIFI:
394 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi", 405 UMA_HISTOGRAM_COUNTS(
395 peak_kbps_since_last_connection_change_); 406 "NQE.PeakKbps.Wifi",
407 peak_network_quality_.downstream_throughput_kbps());
396 break; 408 break;
397 case NetworkChangeNotifier::CONNECTION_2G: 409 case NetworkChangeNotifier::CONNECTION_2G:
398 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.2G", 410 UMA_HISTOGRAM_COUNTS(
399 peak_kbps_since_last_connection_change_); 411 "NQE.PeakKbps.2G",
412 peak_network_quality_.downstream_throughput_kbps());
400 break; 413 break;
401 case NetworkChangeNotifier::CONNECTION_3G: 414 case NetworkChangeNotifier::CONNECTION_3G:
402 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.3G", 415 UMA_HISTOGRAM_COUNTS(
403 peak_kbps_since_last_connection_change_); 416 "NQE.PeakKbps.3G",
417 peak_network_quality_.downstream_throughput_kbps());
404 break; 418 break;
405 case NetworkChangeNotifier::CONNECTION_4G: 419 case NetworkChangeNotifier::CONNECTION_4G:
406 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.4G", 420 UMA_HISTOGRAM_COUNTS(
407 peak_kbps_since_last_connection_change_); 421 "NQE.PeakKbps.4G",
422 peak_network_quality_.downstream_throughput_kbps());
408 break; 423 break;
409 case NetworkChangeNotifier::CONNECTION_NONE: 424 case NetworkChangeNotifier::CONNECTION_NONE:
410 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", 425 UMA_HISTOGRAM_COUNTS(
411 peak_kbps_since_last_connection_change_); 426 "NQE.PeakKbps.None",
427 peak_network_quality_.downstream_throughput_kbps());
412 break; 428 break;
413 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 429 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
414 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", 430 UMA_HISTOGRAM_COUNTS(
415 peak_kbps_since_last_connection_change_); 431 "NQE.PeakKbps.Bluetooth",
432 peak_network_quality_.downstream_throughput_kbps());
416 break; 433 break;
417 default: 434 default:
418 NOTREACHED(); 435 NOTREACHED() << "Unexpected connection type = "
436 << current_network_id_.type;
419 break; 437 break;
420 } 438 }
421 } 439 }
422 440
423 NetworkQuality network_quality; 441 NetworkQuality network_quality;
424 if (GetEstimate(&network_quality)) { 442 if (GetEstimate(&network_quality)) {
425 // Add the 50th percentile value. 443 // Add the 50th percentile value.
426 base::HistogramBase* rtt_percentile = 444 base::HistogramBase* rtt_percentile =
427 GetHistogram("RTT.Percentile50.", current_connection_type_, 445 GetHistogram("RTT.Percentile50.", current_network_id_.type,
428 10 * 1000); // 10 seconds 446 10 * 1000); // 10 seconds
429 rtt_percentile->Add(network_quality.rtt().InMilliseconds()); 447 rtt_percentile->Add(network_quality.rtt().InMilliseconds());
430 448
431 // Add the remaining percentile values. 449 // Add the remaining percentile values.
432 static const int kPercentiles[] = {0, 10, 90, 100}; 450 static const int kPercentiles[] = {0, 10, 90, 100};
433 for (size_t i = 0; i < arraysize(kPercentiles); ++i) { 451 for (size_t i = 0; i < arraysize(kPercentiles); ++i) {
434 network_quality = GetEstimate(kPercentiles[i]); 452 network_quality = GetEstimate(kPercentiles[i]);
435 453
436 char percentile_stringified[20]; 454 char percentile_stringified[20];
437 base::strings::SafeSPrintf(percentile_stringified, "%d", kPercentiles[i]); 455 base::strings::SafeSPrintf(percentile_stringified, "%d", kPercentiles[i]);
438 456
439 rtt_percentile = GetHistogram( 457 rtt_percentile = GetHistogram(
440 "RTT.Percentile" + std::string(percentile_stringified) + ".", 458 "RTT.Percentile" + std::string(percentile_stringified) + ".",
441 current_connection_type_, 10 * 1000); // 10 seconds 459 current_network_id_.type, 10 * 1000); // 10 seconds
442 rtt_percentile->Add(network_quality.rtt().InMilliseconds()); 460 rtt_percentile->Add(network_quality.rtt().InMilliseconds());
443 } 461 }
444 } 462 }
445 463
464 // Write the estimates of the previous network to the cache.
465 CacheNetworkQualityEstimate();
466
467 // Clear the local state.
446 last_connection_change_ = base::TimeTicks::Now(); 468 last_connection_change_ = base::TimeTicks::Now();
447 peak_kbps_since_last_connection_change_ = NetworkQuality::kInvalidThroughput; 469 peak_network_quality_ = NetworkQuality();
448 fastest_rtt_since_last_connection_change_ = NetworkQuality::InvalidRTT();
449 kbps_observations_.Clear(); 470 kbps_observations_.Clear();
450 rtt_msec_observations_.Clear(); 471 rtt_msec_observations_.Clear();
451 current_connection_type_ = type; 472 current_network_id_ = GetCurrentNetworkID();
452 473
453 AddDefaultEstimates(); 474 // Read any cached estimates for the new network. If cached estimates are
475 // unavailable, add the default estimates.
476 if (!ReadCachedNetworkQualityEstimate())
477 AddDefaultEstimates();
454 estimated_median_network_quality_ = NetworkQuality(); 478 estimated_median_network_quality_ = NetworkQuality();
455 } 479 }
456 480
457 NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const { 481 NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const {
458 DCHECK(thread_checker_.CalledOnValidThread()); 482 DCHECK(thread_checker_.CalledOnValidThread());
459 483
460 return NetworkQuality(fastest_rtt_since_last_connection_change_, 484 return peak_network_quality_;
461 peak_kbps_since_last_connection_change_);
462 } 485 }
463 486
464 bool NetworkQualityEstimator::GetEstimate(NetworkQuality* median) const { 487 bool NetworkQualityEstimator::GetEstimate(NetworkQuality* median) const {
465 if (kbps_observations_.Size() == 0 || rtt_msec_observations_.Size() == 0) { 488 if (kbps_observations_.Size() == 0 || rtt_msec_observations_.Size() == 0) {
466 *median = NetworkQuality(); 489 *median = NetworkQuality();
467 return false; 490 return false;
468 } 491 }
469 *median = GetEstimate(50); 492 *median = GetEstimate(50);
470 return true; 493 return true;
471 } 494 }
472 495
473 size_t NetworkQualityEstimator::GetMaximumObservationBufferSizeForTests()
474 const {
475 return kMaximumObservationsBufferSize;
476 }
477
478 bool NetworkQualityEstimator::VerifyBufferSizeForTests(
479 size_t expected_size) const {
480 return kbps_observations_.Size() == expected_size &&
481 rtt_msec_observations_.Size() == expected_size;
482 }
483
484 NetworkQualityEstimator::Observation::Observation(int32_t value, 496 NetworkQualityEstimator::Observation::Observation(int32_t value,
485 base::TimeTicks timestamp) 497 base::TimeTicks timestamp)
486 : value(value), timestamp(timestamp) { 498 : value(value), timestamp(timestamp) {
487 DCHECK_GE(value, 0); 499 DCHECK_GE(value, 0);
488 DCHECK(!timestamp.is_null()); 500 DCHECK(!timestamp.is_null());
489 } 501 }
490 502
491 NetworkQualityEstimator::Observation::~Observation() { 503 NetworkQualityEstimator::Observation::~Observation() {
492 } 504 }
493 505
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 } 601 }
590 602
591 // Computation may reach here due to floating point errors. This may happen 603 // Computation may reach here due to floating point errors. This may happen
592 // if |percentile| was 100 (or close to 100), and |desired_weight| was 604 // if |percentile| was 100 (or close to 100), and |desired_weight| was
593 // slightly larger than |total_weight| (due to floating point errors). 605 // slightly larger than |total_weight| (due to floating point errors).
594 // In this case, we return the highest |value| among all observations. 606 // In this case, we return the highest |value| among all observations.
595 // This is same as value of the last observation in the sorted vector. 607 // This is same as value of the last observation in the sorted vector.
596 return weighted_observations.at(weighted_observations.size() - 1).value; 608 return weighted_observations.at(weighted_observations.size() - 1).value;
597 } 609 }
598 610
611 NetworkQualityEstimator::NetworkID
612 NetworkQualityEstimator::GetCurrentNetworkID() const {
613 DCHECK(thread_checker_.CalledOnValidThread());
614
615 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class
616 // that overrides this method on the Android platform.
617
618 // It is possible that the connection type changed between when
619 // GetConnectionType() was called and when the API to determine the
620 // network name was called. Check if that happened and retry until the
621 // connection type stabilizes. This is an imperfect solution but should
622 // capture majority of cases, and should not significantly affect estimates
623 // (that are approximate to begin with).
624 while (true) {
625 NetworkQualityEstimator::NetworkID network_id(
626 NetworkChangeNotifier::GetConnectionType(), std::string());
627
628 switch (network_id.type) {
629 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
630 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
631 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
632 break;
633 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
634 network_id.id = "Ethernet";
635 break;
636 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
637 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
638 network_id.id = GetWifiSSID();
639 break;
640 #else
641 break;
642 #endif
pauljensen 2015/07/14 11:59:03 #if ... ... break; #else break; #endif ->
tbansal1 2015/07/14 19:51:48 Done.
643 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
644 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
645 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
646 #if defined(OS_ANDROID)
647 network_id.id = android::GetTelephonyNetworkOperator();
648 break;
649 #else
650 break;
651 #endif
pauljensen 2015/07/14 11:59:02 ditto
tbansal1 2015/07/14 19:51:47 Done.
652 default:
653 NOTREACHED() << "Unexpected connection type = " << network_id.type;
654 }
pauljensen 2015/07/14 11:59:03 break;
tbansal1 2015/07/14 19:51:48 Done.
655
656 if (network_id.type == NetworkChangeNotifier::GetConnectionType())
657 return network_id;
658 }
659 NOTREACHED();
660 }
661
662 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
663 DCHECK(thread_checker_.CalledOnValidThread());
664
665 // If the network name is unavailable, caching should not be performed.
666 if (current_network_id_.id.empty())
667 return false;
668
669 CachedNetworkQualities::iterator it =
670 cached_network_qualities_.find(current_network_id_);
671
672 if (it == cached_network_qualities_.end())
673 return false;
674
675 NetworkQuality network_quality(
676 it->second->network_quality().rtt(),
677 it->second->network_quality().downstream_throughput_kbps());
678
679 DCHECK_NE(NetworkQuality::InvalidRTT(), network_quality.rtt());
680 DCHECK_NE(NetworkQuality::kInvalidThroughput,
681 network_quality.downstream_throughput_kbps());
682
683 kbps_observations_.AddObservation(Observation(
684 network_quality.downstream_throughput_kbps(), base::TimeTicks::Now()));
685 rtt_msec_observations_.AddObservation(Observation(
686 network_quality.rtt().InMilliseconds(), base::TimeTicks::Now()));
687 return true;
688 }
689
690 void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
691 DCHECK(thread_checker_.CalledOnValidThread());
692 DCHECK_LE(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize);
693
694 // If the network name is unavailable, caching should not be performed.
695 if (current_network_id_.id.empty())
696 return;
697
698 NetworkQuality network_quality;
699 if (!GetEstimate(&network_quality))
700 return;
701
702 DCHECK_NE(NetworkQuality::InvalidRTT(), network_quality.rtt());
703 DCHECK_NE(NetworkQuality::kInvalidThroughput,
704 network_quality.downstream_throughput_kbps());
705
706 if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) {
707 // Remove the oldest entry.
708 CachedNetworkQualities::iterator oldest_entry_iterator =
709 cached_network_qualities_.begin();
710
711 for (CachedNetworkQualities::iterator it =
712 cached_network_qualities_.begin();
713 it != cached_network_qualities_.end(); ++it) {
714 if ((it->second)->OlderThan(*(oldest_entry_iterator->second.get())))
715 oldest_entry_iterator = it;
716 }
717 cached_network_qualities_.erase(oldest_entry_iterator);
718 }
719 DCHECK_LT(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize);
720
721 cached_network_qualities_[current_network_id_].reset(
722 new CachedNetworkQuality(network_quality));
723 DCHECK_LE(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize);
724 }
725
726 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
727 const NetworkQuality& network_quality)
728 : last_update_time_(base::TimeTicks::Now()),
729 network_quality_(network_quality) {
730 }
731
732 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() {
733 }
734
735 bool NetworkQualityEstimator::CachedNetworkQuality::OlderThan(
736 const CachedNetworkQuality& cached_network_quality) const {
737 return last_update_time_ < cached_network_quality.last_update_time_;
738 }
739
599 } // namespace net 740 } // namespace net
OLDNEW
« no previous file with comments | « net/base/network_quality_estimator.h ('k') | net/base/network_quality_estimator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698