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

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

Powered by Google App Engine
This is Rietveld 408576698