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

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