| OLD | NEW |
| 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/nqe/network_quality_estimator.h" | 5 #include "net/nqe/network_quality_estimator.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 DCHECK_GT(max_limit, kLowerLimit); | 133 DCHECK_GT(max_limit, kLowerLimit); |
| 134 const size_t kBucketCount = 50; | 134 const size_t kBucketCount = 50; |
| 135 | 135 |
| 136 // Prefix of network quality estimator histograms. | 136 // Prefix of network quality estimator histograms. |
| 137 const char prefix[] = "NQE."; | 137 const char prefix[] = "NQE."; |
| 138 return base::Histogram::FactoryGet( | 138 return base::Histogram::FactoryGet( |
| 139 prefix + statistic_name + GetNameForConnectionType(type), kLowerLimit, | 139 prefix + statistic_name + GetNameForConnectionType(type), kLowerLimit, |
| 140 max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag); | 140 max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag); |
| 141 } | 141 } |
| 142 | 142 |
| 143 bool GetValueForVariationParam( | 143 // Sets |variations_value| to the value of |parameter_name| read from |
| 144 // |variation_params|. If the value is unavailable from |variation_params|, then |
| 145 // |variations_value| is set to |default_value|. |
| 146 void GetValueForVariationParam( |
| 144 const std::map<std::string, std::string>& variation_params, | 147 const std::map<std::string, std::string>& variation_params, |
| 145 const std::string& parameter_name, | 148 const std::string& parameter_name, |
| 149 int32_t default_value, |
| 146 int32_t* variations_value) { | 150 int32_t* variations_value) { |
| 147 const auto it = variation_params.find(parameter_name); | 151 const auto it = variation_params.find(parameter_name); |
| 148 return it != variation_params.end() && | 152 if (it != variation_params.end() && |
| 149 base::StringToInt(it->second, variations_value); | 153 base::StringToInt(it->second, variations_value)) { |
| 154 return; |
| 155 } |
| 156 *variations_value = default_value; |
| 150 } | 157 } |
| 151 | 158 |
| 152 // Returns the algorithm that should be used for computing effective connection | 159 // Returns the algorithm that should be used for computing effective connection |
| 153 // type based on field trial params. Returns an empty string if a valid | 160 // type based on field trial params. Returns an empty string if a valid |
| 154 // algorithm paramter is not present in the field trial params. | 161 // algorithm paramter is not present in the field trial params. |
| 155 std::string GetEffectiveConnectionTypeAlgorithm( | 162 std::string GetEffectiveConnectionTypeAlgorithm( |
| 156 const std::map<std::string, std::string>& variation_params) { | 163 const std::map<std::string, std::string>& variation_params) { |
| 157 const auto it = variation_params.find("effective_connection_type_algorithm"); | 164 const auto it = variation_params.find("effective_connection_type_algorithm"); |
| 158 if (it == variation_params.end()) | 165 if (it == variation_params.end()) |
| 159 return std::string(); | 166 return std::string(); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 base::ThreadTaskRunnerHandle::Get(), | 316 base::ThreadTaskRunnerHandle::Get(), |
| 310 base::Bind(&NetworkQualityEstimator::OnUpdatedRTTAvailable, | 317 base::Bind(&NetworkQualityEstimator::OnUpdatedRTTAvailable, |
| 311 base::Unretained(this)))); | 318 base::Unretained(this)))); |
| 312 | 319 |
| 313 // Record accuracy at 3 different intervals. The values used here must remain | 320 // Record accuracy at 3 different intervals. The values used here must remain |
| 314 // in sync with the suffixes specified in | 321 // in sync with the suffixes specified in |
| 315 // tools/metrics/histograms/histograms.xml. | 322 // tools/metrics/histograms/histograms.xml. |
| 316 accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(15)); | 323 accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(15)); |
| 317 accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(30)); | 324 accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(30)); |
| 318 accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(60)); | 325 accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(60)); |
| 326 |
| 327 // Set to 1870 milliseconds which corresponds to below 33rd percentile of 2G |
| 328 // transport RTT observations. |
| 329 default_connection_thresholds_[EFFECTIVE_CONNECTION_TYPE_SLOW_2G] = |
| 330 nqe::internal::NetworkQuality(nqe::internal::InvalidRTT(), |
| 331 base::TimeDelta::FromMilliseconds(1870), |
| 332 nqe::internal::kInvalidThroughput); |
| 333 |
| 334 // Set to 1300 milliseconds which corresponds to 50th percentile of 2G |
| 335 // transport RTT observations. |
| 336 default_connection_thresholds_[EFFECTIVE_CONNECTION_TYPE_2G] = |
| 337 nqe::internal::NetworkQuality(nqe::internal::InvalidRTT(), |
| 338 base::TimeDelta::FromMilliseconds(1300), |
| 339 nqe::internal::kInvalidThroughput); |
| 319 } | 340 } |
| 320 | 341 |
| 321 void NetworkQualityEstimator::ObtainOperatingParams( | 342 void NetworkQualityEstimator::ObtainOperatingParams( |
| 322 const std::map<std::string, std::string>& variation_params) { | 343 const std::map<std::string, std::string>& variation_params) { |
| 323 DCHECK(thread_checker_.CalledOnValidThread()); | 344 DCHECK(thread_checker_.CalledOnValidThread()); |
| 324 | 345 |
| 325 for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) { | 346 for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) { |
| 326 NetworkChangeNotifier::ConnectionType type = | 347 NetworkChangeNotifier::ConnectionType type = |
| 327 static_cast<NetworkChangeNotifier::ConnectionType>(i); | 348 static_cast<NetworkChangeNotifier::ConnectionType>(i); |
| 328 DCHECK_EQ(nqe::internal::InvalidRTT(), default_observations_[i].http_rtt()); | 349 DCHECK_EQ(nqe::internal::InvalidRTT(), default_observations_[i].http_rtt()); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 DCHECK_EQ(nqe::internal::InvalidRTT(), | 395 DCHECK_EQ(nqe::internal::InvalidRTT(), |
| 375 connection_thresholds_[i].transport_rtt()); | 396 connection_thresholds_[i].transport_rtt()); |
| 376 DCHECK_EQ(nqe::internal::kInvalidThroughput, | 397 DCHECK_EQ(nqe::internal::kInvalidThroughput, |
| 377 connection_thresholds_[i].downstream_throughput_kbps()); | 398 connection_thresholds_[i].downstream_throughput_kbps()); |
| 378 if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) | 399 if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) |
| 379 continue; | 400 continue; |
| 380 | 401 |
| 381 std::string connection_type_name = std::string( | 402 std::string connection_type_name = std::string( |
| 382 GetNameForEffectiveConnectionType(effective_connection_type)); | 403 GetNameForEffectiveConnectionType(effective_connection_type)); |
| 383 | 404 |
| 384 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1; | 405 int32_t variations_value; |
| 385 if (GetValueForVariationParam( | 406 GetValueForVariationParam( |
| 386 variation_params, connection_type_name + kThresholdURLRTTMsecSuffix, | 407 variation_params, connection_type_name + kThresholdURLRTTMsecSuffix, |
| 387 &variations_value) && | 408 default_connection_thresholds_[i].http_rtt().InMilliseconds(), |
| 388 variations_value >= kMinimumRTTVariationParameterMsec) { | 409 &variations_value); |
| 389 connection_thresholds_[i].set_http_rtt( | 410 connection_thresholds_[i].set_http_rtt( |
| 390 base::TimeDelta(base::TimeDelta::FromMilliseconds(variations_value))); | 411 base::TimeDelta(base::TimeDelta::FromMilliseconds(variations_value))); |
| 412 // Verify that the RTT values are in decreasing order as the network |
| 413 // quality improves. |
| 414 DCHECK(i == 0 || |
| 415 connection_thresholds_[i].http_rtt() == |
| 416 nqe::internal::InvalidRTT() || |
| 417 connection_thresholds_[i - 1].http_rtt() == |
| 418 nqe::internal::InvalidRTT() || |
| 419 connection_thresholds_[i].http_rtt() <= |
| 420 connection_thresholds_[i - 1].http_rtt()); |
| 391 | 421 |
| 392 // Verify that the RTT values are in decreasing order as the network | 422 GetValueForVariationParam( |
| 393 // quality improves. | 423 variation_params, |
| 394 DCHECK(i == 0 || | 424 connection_type_name + kThresholdTransportRTTMsecSuffix, |
| 395 connection_thresholds_[i - 1].http_rtt() == | 425 default_connection_thresholds_[i].transport_rtt().InMilliseconds(), |
| 396 nqe::internal::InvalidRTT() || | 426 &variations_value); |
| 397 connection_thresholds_[i].http_rtt() <= | 427 connection_thresholds_[i].set_transport_rtt( |
| 398 connection_thresholds_[i - 1].http_rtt()); | 428 base::TimeDelta(base::TimeDelta::FromMilliseconds(variations_value))); |
| 399 } | 429 // Verify that the transport RTT values are in decreasing order as the |
| 430 // network quality improves. |
| 431 DCHECK(i == 0 || |
| 432 connection_thresholds_[i].transport_rtt() == |
| 433 nqe::internal::InvalidRTT() || |
| 434 connection_thresholds_[i - 1].transport_rtt() == |
| 435 nqe::internal::InvalidRTT() || |
| 436 connection_thresholds_[i].transport_rtt() <= |
| 437 connection_thresholds_[i - 1].transport_rtt()); |
| 400 | 438 |
| 401 variations_value = kMinimumRTTVariationParameterMsec - 1; | 439 GetValueForVariationParam( |
| 402 if (GetValueForVariationParam( | 440 variation_params, connection_type_name + kThresholdKbpsSuffix, |
| 403 variation_params, | 441 default_connection_thresholds_[i].downstream_throughput_kbps(), |
| 404 connection_type_name + kThresholdTransportRTTMsecSuffix, | 442 &variations_value); |
| 405 &variations_value) && | 443 connection_thresholds_[i].set_downstream_throughput_kbps(variations_value); |
| 406 variations_value >= kMinimumRTTVariationParameterMsec) { | 444 // Verify that the throughput values are in increasing order as the |
| 407 connection_thresholds_[i].set_transport_rtt( | 445 // network quality improves. |
| 408 base::TimeDelta(base::TimeDelta::FromMilliseconds(variations_value))); | 446 DCHECK(i == 0 || |
| 409 | 447 connection_thresholds_[i].downstream_throughput_kbps() == |
| 410 // Verify that the transport RTT values are in decreasing order as the | 448 kMinimumThroughputVariationParameterKbps || |
| 411 // network quality improves. | 449 connection_thresholds_[i - 1].downstream_throughput_kbps() == |
| 412 DCHECK(i == 0 || | 450 kMinimumThroughputVariationParameterKbps || |
| 413 connection_thresholds_[i - 1].transport_rtt() == | 451 connection_thresholds_[i].downstream_throughput_kbps() >= |
| 414 nqe::internal::InvalidRTT() || | 452 connection_thresholds_[i - 1].downstream_throughput_kbps()); |
| 415 connection_thresholds_[i].transport_rtt() <= | |
| 416 connection_thresholds_[i - 1].transport_rtt()); | |
| 417 } | |
| 418 | |
| 419 variations_value = kMinimumThroughputVariationParameterKbps - 1; | |
| 420 if (GetValueForVariationParam(variation_params, | |
| 421 connection_type_name + kThresholdKbpsSuffix, | |
| 422 &variations_value) && | |
| 423 variations_value >= kMinimumThroughputVariationParameterKbps) { | |
| 424 connection_thresholds_[i].set_downstream_throughput_kbps( | |
| 425 variations_value); | |
| 426 | |
| 427 // Verify that the throughput values are in increasing order as the | |
| 428 // network quality improves. | |
| 429 DCHECK(i == 0 || | |
| 430 connection_thresholds_[i - 1].downstream_throughput_kbps() == | |
| 431 kMinimumThroughputVariationParameterKbps || | |
| 432 connection_thresholds_[i].downstream_throughput_kbps() >= | |
| 433 connection_thresholds_[i - 1].downstream_throughput_kbps()); | |
| 434 } | |
| 435 } | 453 } |
| 436 } | 454 } |
| 437 | 455 |
| 438 void NetworkQualityEstimator::AddDefaultEstimates() { | 456 void NetworkQualityEstimator::AddDefaultEstimates() { |
| 439 DCHECK(thread_checker_.CalledOnValidThread()); | 457 DCHECK(thread_checker_.CalledOnValidThread()); |
| 440 | 458 |
| 441 if (default_observations_[current_network_id_.type].http_rtt() != | 459 if (default_observations_[current_network_id_.type].http_rtt() != |
| 442 nqe::internal::InvalidRTT()) { | 460 nqe::internal::InvalidRTT()) { |
| 443 RttObservation rtt_observation( | 461 RttObservation rtt_observation( |
| 444 default_observations_[current_network_id_.type].http_rtt(), | 462 default_observations_[current_network_id_.type].http_rtt(), |
| (...skipping 1001 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1446 | 1464 |
| 1447 void NetworkQualityEstimator::MaybeRecomputeEffectiveConnectionType() { | 1465 void NetworkQualityEstimator::MaybeRecomputeEffectiveConnectionType() { |
| 1448 DCHECK(thread_checker_.CalledOnValidThread()); | 1466 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1449 | 1467 |
| 1450 const base::TimeTicks now = tick_clock_->NowTicks(); | 1468 const base::TimeTicks now = tick_clock_->NowTicks(); |
| 1451 // Recompute effective connection type only if | 1469 // Recompute effective connection type only if |
| 1452 // |effective_connection_type_recomputation_interval_| has passed since it was | 1470 // |effective_connection_type_recomputation_interval_| has passed since it was |
| 1453 // last computed or a connection change event was observed since the last | 1471 // last computed or a connection change event was observed since the last |
| 1454 // computation. Strict inequalities are used to ensure that effective | 1472 // computation. Strict inequalities are used to ensure that effective |
| 1455 // connection type is recomputed on connection change events even if the clock | 1473 // connection type is recomputed on connection change events even if the clock |
| 1456 // has not updated. | 1474 // has not updated. If the algorithm uses transport RTT, then recompute the |
| 1475 // effective connection type if the effective connection type was previously |
| 1476 // unavailable. This is because the transport RTT observations are voluminous, |
| 1477 // so it may now be possible to compute the effective connection type. |
| 1457 if (now - last_effective_connection_type_computation_ < | 1478 if (now - last_effective_connection_type_computation_ < |
| 1458 effective_connection_type_recomputation_interval_ && | 1479 effective_connection_type_recomputation_interval_ && |
| 1459 last_connection_change_ < last_effective_connection_type_computation_) { | 1480 last_connection_change_ < last_effective_connection_type_computation_ && |
| 1481 (effective_connection_type_ != |
| 1482 NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_UNKNOWN || |
| 1483 effective_connection_type_algorithm_ != |
| 1484 EffectiveConnectionTypeAlgorithm:: |
| 1485 TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT)) { |
| 1460 return; | 1486 return; |
| 1461 } | 1487 } |
| 1462 | 1488 |
| 1463 const EffectiveConnectionType past_type = effective_connection_type_; | 1489 const EffectiveConnectionType past_type = effective_connection_type_; |
| 1464 last_effective_connection_type_computation_ = now; | 1490 last_effective_connection_type_computation_ = now; |
| 1465 effective_connection_type_ = GetEffectiveConnectionType(); | 1491 effective_connection_type_ = GetEffectiveConnectionType(); |
| 1466 | 1492 |
| 1467 if (past_type != effective_connection_type_) | 1493 if (past_type != effective_connection_type_) |
| 1468 NotifyObserversOfEffectiveConnectionTypeChanged(); | 1494 NotifyObserversOfEffectiveConnectionTypeChanged(); |
| 1469 } | 1495 } |
| 1470 | 1496 |
| 1471 void NetworkQualityEstimator:: | 1497 void NetworkQualityEstimator:: |
| 1472 NotifyObserversOfEffectiveConnectionTypeChanged() { | 1498 NotifyObserversOfEffectiveConnectionTypeChanged() { |
| 1473 DCHECK(thread_checker_.CalledOnValidThread()); | 1499 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1474 | 1500 |
| 1475 // TODO(tbansal): Add hysteresis in the notification. | 1501 // TODO(tbansal): Add hysteresis in the notification. |
| 1476 FOR_EACH_OBSERVER( | 1502 FOR_EACH_OBSERVER( |
| 1477 EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, | 1503 EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, |
| 1478 OnEffectiveConnectionTypeChanged(effective_connection_type_)); | 1504 OnEffectiveConnectionTypeChanged(effective_connection_type_)); |
| 1479 } | 1505 } |
| 1480 | 1506 |
| 1481 } // namespace net | 1507 } // namespace net |
| OLD | NEW |