| 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 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 last_connection_change_(tick_clock_->NowTicks()), | 379 last_connection_change_(tick_clock_->NowTicks()), |
| 380 current_network_id_(nqe::internal::NetworkID( | 380 current_network_id_(nqe::internal::NetworkID( |
| 381 NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, | 381 NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, |
| 382 std::string())), | 382 std::string())), |
| 383 downstream_throughput_kbps_observations_(weight_multiplier_per_second_), | 383 downstream_throughput_kbps_observations_(weight_multiplier_per_second_), |
| 384 rtt_observations_(weight_multiplier_per_second_), | 384 rtt_observations_(weight_multiplier_per_second_), |
| 385 effective_connection_type_at_last_main_frame_( | 385 effective_connection_type_at_last_main_frame_( |
| 386 EFFECTIVE_CONNECTION_TYPE_UNKNOWN), | 386 EFFECTIVE_CONNECTION_TYPE_UNKNOWN), |
| 387 external_estimate_provider_(std::move(external_estimates_provider)), | 387 external_estimate_provider_(std::move(external_estimates_provider)), |
| 388 effective_connection_type_recomputation_interval_( | 388 effective_connection_type_recomputation_interval_( |
| 389 base::TimeDelta::FromSeconds(15)), | 389 base::TimeDelta::FromSeconds(10)), |
| 390 rtt_observations_size_at_last_ect_computation_(0), | 390 rtt_observations_size_at_last_ect_computation_(0), |
| 391 throughput_observations_size_at_last_ect_computation_(0), | 391 throughput_observations_size_at_last_ect_computation_(0), |
| 392 effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN), | 392 effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN), |
| 393 min_signal_strength_since_connection_change_(INT32_MAX), | 393 min_signal_strength_since_connection_change_(INT32_MAX), |
| 394 max_signal_strength_since_connection_change_(INT32_MIN), | 394 max_signal_strength_since_connection_change_(INT32_MIN), |
| 395 correlation_uma_logging_probability_( | 395 correlation_uma_logging_probability_( |
| 396 GetDoubleValueForVariationParamWithDefaultValue( | 396 GetDoubleValueForVariationParamWithDefaultValue( |
| 397 variation_params, | 397 variation_params, |
| 398 "correlation_logging_probability", | 398 "correlation_logging_probability", |
| 399 0.0)), | 399 0.0)), |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 654 if (!GetTransportRTT(&estimated_transport_rtt)) | 654 if (!GetTransportRTT(&estimated_transport_rtt)) |
| 655 estimated_transport_rtt = nqe::internal::InvalidRTT(); | 655 estimated_transport_rtt = nqe::internal::InvalidRTT(); |
| 656 | 656 |
| 657 int32_t downstream_throughput_kbps; | 657 int32_t downstream_throughput_kbps; |
| 658 if (!GetDownlinkThroughputKbps(&downstream_throughput_kbps)) | 658 if (!GetDownlinkThroughputKbps(&downstream_throughput_kbps)) |
| 659 downstream_throughput_kbps = nqe::internal::kInvalidThroughput; | 659 downstream_throughput_kbps = nqe::internal::kInvalidThroughput; |
| 660 | 660 |
| 661 estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality( | 661 estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality( |
| 662 estimated_http_rtt, estimated_transport_rtt, | 662 estimated_http_rtt, estimated_transport_rtt, |
| 663 downstream_throughput_kbps); | 663 downstream_throughput_kbps); |
| 664 |
| 665 ComputeEffectiveConnectionType(); |
| 664 effective_connection_type_at_last_main_frame_ = | 666 effective_connection_type_at_last_main_frame_ = |
| 665 GetEffectiveConnectionType(); | 667 GetEffectiveConnectionType(); |
| 666 | 668 |
| 667 RecordMetricsOnMainFrameRequest(); | 669 RecordMetricsOnMainFrameRequest(); |
| 668 MaybeQueryExternalEstimateProvider(); | 670 MaybeQueryExternalEstimateProvider(); |
| 669 | 671 |
| 670 // Post the tasks which will run in the future and record the estimation | 672 // Post the tasks which will run in the future and record the estimation |
| 671 // accuracy based on the observations received between now and the time of | 673 // accuracy based on the observations received between now and the time of |
| 672 // task execution. Posting the task at different intervals makes it | 674 // task execution. Posting the task at different intervals makes it |
| 673 // possible to measure the accuracy by comparing the estimate with the | 675 // possible to measure the accuracy by comparing the estimate with the |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1029 RecordNetworkIDAvailability(); | 1031 RecordNetworkIDAvailability(); |
| 1030 | 1032 |
| 1031 MaybeQueryExternalEstimateProvider(); | 1033 MaybeQueryExternalEstimateProvider(); |
| 1032 | 1034 |
| 1033 // Read any cached estimates for the new network. If cached estimates are | 1035 // Read any cached estimates for the new network. If cached estimates are |
| 1034 // unavailable, add the default estimates. | 1036 // unavailable, add the default estimates. |
| 1035 if (!ReadCachedNetworkQualityEstimate()) | 1037 if (!ReadCachedNetworkQualityEstimate()) |
| 1036 AddDefaultEstimates(); | 1038 AddDefaultEstimates(); |
| 1037 estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality(); | 1039 estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality(); |
| 1038 throughput_analyzer_->OnConnectionTypeChanged(); | 1040 throughput_analyzer_->OnConnectionTypeChanged(); |
| 1039 MaybeRecomputeEffectiveConnectionType(); | 1041 MaybeComputeEffectiveConnectionType(); |
| 1040 UpdateSignalStrength(); | 1042 UpdateSignalStrength(); |
| 1041 } | 1043 } |
| 1042 | 1044 |
| 1043 void NetworkQualityEstimator::MaybeQueryExternalEstimateProvider() const { | 1045 void NetworkQualityEstimator::MaybeQueryExternalEstimateProvider() const { |
| 1044 // Query the external estimate provider on certain connection types. Once the | 1046 // Query the external estimate provider on certain connection types. Once the |
| 1045 // updated estimates are available, OnUpdatedEstimateAvailable will be called | 1047 // updated estimates are available, OnUpdatedEstimateAvailable will be called |
| 1046 // by |external_estimate_provider_| with updated estimates. | 1048 // by |external_estimate_provider_| with updated estimates. |
| 1047 if (external_estimate_provider_ && | 1049 if (external_estimate_provider_ && |
| 1048 current_network_id_.type != NetworkChangeNotifier::CONNECTION_NONE && | 1050 current_network_id_.type != NetworkChangeNotifier::CONNECTION_NONE && |
| 1049 current_network_id_.type != NetworkChangeNotifier::CONNECTION_UNKNOWN && | 1051 current_network_id_.type != NetworkChangeNotifier::CONNECTION_UNKNOWN && |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1184 base::Histogram::FactoryGet( | 1186 base::Histogram::FactoryGet( |
| 1185 std::string("NQE.MainFrame.EffectiveConnectionType.") + | 1187 std::string("NQE.MainFrame.EffectiveConnectionType.") + |
| 1186 GetNameForConnectionType(current_network_id_.type), | 1188 GetNameForConnectionType(current_network_id_.type), |
| 1187 0, EFFECTIVE_CONNECTION_TYPE_LAST, | 1189 0, EFFECTIVE_CONNECTION_TYPE_LAST, |
| 1188 EFFECTIVE_CONNECTION_TYPE_LAST /* Number of buckets */, | 1190 EFFECTIVE_CONNECTION_TYPE_LAST /* Number of buckets */, |
| 1189 base::HistogramBase::kUmaTargetedHistogramFlag); | 1191 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 1190 | 1192 |
| 1191 effective_connection_type_histogram->Add(effective_connection_type); | 1193 effective_connection_type_histogram->Add(effective_connection_type); |
| 1192 } | 1194 } |
| 1193 | 1195 |
| 1196 void NetworkQualityEstimator::ComputeEffectiveConnectionType() { |
| 1197 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1198 |
| 1199 const base::TimeTicks now = tick_clock_->NowTicks(); |
| 1200 |
| 1201 const EffectiveConnectionType past_type = effective_connection_type_; |
| 1202 last_effective_connection_type_computation_ = now; |
| 1203 |
| 1204 effective_connection_type_ = |
| 1205 GetRecentEffectiveConnectionType(base::TimeTicks()); |
| 1206 |
| 1207 if (past_type != effective_connection_type_) |
| 1208 NotifyObserversOfEffectiveConnectionTypeChanged(); |
| 1209 |
| 1210 rtt_observations_size_at_last_ect_computation_ = rtt_observations_.Size(); |
| 1211 throughput_observations_size_at_last_ect_computation_ = |
| 1212 downstream_throughput_kbps_observations_.Size(); |
| 1213 } |
| 1214 |
| 1194 EffectiveConnectionType NetworkQualityEstimator::GetEffectiveConnectionType() | 1215 EffectiveConnectionType NetworkQualityEstimator::GetEffectiveConnectionType() |
| 1195 const { | 1216 const { |
| 1196 DCHECK(thread_checker_.CalledOnValidThread()); | 1217 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1197 return GetRecentEffectiveConnectionType(base::TimeTicks()); | 1218 return effective_connection_type_; |
| 1198 } | 1219 } |
| 1199 | 1220 |
| 1200 EffectiveConnectionType | 1221 EffectiveConnectionType |
| 1201 NetworkQualityEstimator::GetRecentEffectiveConnectionType( | 1222 NetworkQualityEstimator::GetRecentEffectiveConnectionType( |
| 1202 const base::TimeTicks& start_time) const { | 1223 const base::TimeTicks& start_time) const { |
| 1203 DCHECK(thread_checker_.CalledOnValidThread()); | 1224 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1204 | 1225 |
| 1205 if (effective_connection_type_algorithm_ == | 1226 if (effective_connection_type_algorithm_ == |
| 1206 EffectiveConnectionTypeAlgorithm::HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT) { | 1227 EffectiveConnectionTypeAlgorithm::HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT) { |
| 1207 return GetRecentEffectiveConnectionTypeUsingMetrics( | 1228 return GetRecentEffectiveConnectionTypeUsingMetrics( |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1598 rtt_observations_.AddObservation(observation); | 1619 rtt_observations_.AddObservation(observation); |
| 1599 } | 1620 } |
| 1600 | 1621 |
| 1601 void NetworkQualityEstimator::NotifyObserversOfRTT( | 1622 void NetworkQualityEstimator::NotifyObserversOfRTT( |
| 1602 const RttObservation& observation) { | 1623 const RttObservation& observation) { |
| 1603 DCHECK(thread_checker_.CalledOnValidThread()); | 1624 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1604 DCHECK_NE(nqe::internal::InvalidRTT(), observation.value); | 1625 DCHECK_NE(nqe::internal::InvalidRTT(), observation.value); |
| 1605 | 1626 |
| 1606 // Maybe recompute the effective connection type since a new RTT observation | 1627 // Maybe recompute the effective connection type since a new RTT observation |
| 1607 // is available. | 1628 // is available. |
| 1608 MaybeRecomputeEffectiveConnectionType(); | 1629 MaybeComputeEffectiveConnectionType(); |
| 1609 FOR_EACH_OBSERVER( | 1630 FOR_EACH_OBSERVER( |
| 1610 RTTObserver, rtt_observer_list_, | 1631 RTTObserver, rtt_observer_list_, |
| 1611 OnRTTObservation(observation.value.InMilliseconds(), | 1632 OnRTTObservation(observation.value.InMilliseconds(), |
| 1612 observation.timestamp, observation.source)); | 1633 observation.timestamp, observation.source)); |
| 1613 } | 1634 } |
| 1614 | 1635 |
| 1615 void NetworkQualityEstimator::NotifyObserversOfThroughput( | 1636 void NetworkQualityEstimator::NotifyObserversOfThroughput( |
| 1616 const ThroughputObservation& observation) { | 1637 const ThroughputObservation& observation) { |
| 1617 DCHECK(thread_checker_.CalledOnValidThread()); | 1638 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1618 DCHECK_NE(nqe::internal::kInvalidThroughput, observation.value); | 1639 DCHECK_NE(nqe::internal::kInvalidThroughput, observation.value); |
| 1619 | 1640 |
| 1620 // Maybe recompute the effective connection type since a new throughput | 1641 // Maybe recompute the effective connection type since a new throughput |
| 1621 // observation is available. | 1642 // observation is available. |
| 1622 MaybeRecomputeEffectiveConnectionType(); | 1643 MaybeComputeEffectiveConnectionType(); |
| 1623 FOR_EACH_OBSERVER( | 1644 FOR_EACH_OBSERVER( |
| 1624 ThroughputObserver, throughput_observer_list_, | 1645 ThroughputObserver, throughput_observer_list_, |
| 1625 OnThroughputObservation(observation.value, observation.timestamp, | 1646 OnThroughputObservation(observation.value, observation.timestamp, |
| 1626 observation.source)); | 1647 observation.source)); |
| 1627 } | 1648 } |
| 1628 | 1649 |
| 1629 void NetworkQualityEstimator::OnNewThroughputObservationAvailable( | 1650 void NetworkQualityEstimator::OnNewThroughputObservationAvailable( |
| 1630 int32_t downstream_kbps) { | 1651 int32_t downstream_kbps) { |
| 1631 DCHECK(thread_checker_.CalledOnValidThread()); | 1652 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1632 | 1653 |
| 1633 if (downstream_kbps == 0) | 1654 if (downstream_kbps == 0) |
| 1634 return; | 1655 return; |
| 1635 | 1656 |
| 1636 DCHECK_NE(nqe::internal::kInvalidThroughput, downstream_kbps); | 1657 DCHECK_NE(nqe::internal::kInvalidThroughput, downstream_kbps); |
| 1637 | 1658 |
| 1638 if (downstream_kbps > peak_network_quality_.downstream_throughput_kbps()) { | 1659 if (downstream_kbps > peak_network_quality_.downstream_throughput_kbps()) { |
| 1639 peak_network_quality_ = nqe::internal::NetworkQuality( | 1660 peak_network_quality_ = nqe::internal::NetworkQuality( |
| 1640 peak_network_quality_.http_rtt(), peak_network_quality_.transport_rtt(), | 1661 peak_network_quality_.http_rtt(), peak_network_quality_.transport_rtt(), |
| 1641 downstream_kbps); | 1662 downstream_kbps); |
| 1642 } | 1663 } |
| 1643 ThroughputObservation throughput_observation( | 1664 ThroughputObservation throughput_observation( |
| 1644 downstream_kbps, tick_clock_->NowTicks(), | 1665 downstream_kbps, tick_clock_->NowTicks(), |
| 1645 NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST); | 1666 NETWORK_QUALITY_OBSERVATION_SOURCE_URL_REQUEST); |
| 1646 downstream_throughput_kbps_observations_.AddObservation( | 1667 downstream_throughput_kbps_observations_.AddObservation( |
| 1647 throughput_observation); | 1668 throughput_observation); |
| 1648 NotifyObserversOfThroughput(throughput_observation); | 1669 NotifyObserversOfThroughput(throughput_observation); |
| 1649 } | 1670 } |
| 1650 | 1671 |
| 1651 void NetworkQualityEstimator::MaybeRecomputeEffectiveConnectionType() { | 1672 void NetworkQualityEstimator::MaybeComputeEffectiveConnectionType() { |
| 1652 DCHECK(thread_checker_.CalledOnValidThread()); | 1673 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1653 | 1674 |
| 1654 const base::TimeTicks now = tick_clock_->NowTicks(); | 1675 const base::TimeTicks now = tick_clock_->NowTicks(); |
| 1655 // Recompute effective connection type only if | 1676 // Recompute effective connection type only if |
| 1656 // |effective_connection_type_recomputation_interval_| has passed since it was | 1677 // |effective_connection_type_recomputation_interval_| has passed since it was |
| 1657 // last computed or a connection change event was observed since the last | 1678 // last computed or a connection change event was observed since the last |
| 1658 // computation. Strict inequalities are used to ensure that effective | 1679 // computation. Strict inequalities are used to ensure that effective |
| 1659 // connection type is recomputed on connection change events even if the clock | 1680 // connection type is recomputed on connection change events even if the clock |
| 1660 // has not updated. | 1681 // has not updated. |
| 1661 if (now - last_effective_connection_type_computation_ < | 1682 if (now - last_effective_connection_type_computation_ < |
| 1662 effective_connection_type_recomputation_interval_ && | 1683 effective_connection_type_recomputation_interval_ && |
| 1663 last_connection_change_ < last_effective_connection_type_computation_ && | 1684 last_connection_change_ < last_effective_connection_type_computation_ && |
| 1664 // Recompute the effective connection type if the previously computed | 1685 // Recompute the effective connection type if the previously computed |
| 1665 // effective connection type was unknown. | 1686 // effective connection type was unknown. |
| 1666 effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN && | 1687 effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN && |
| 1667 // Recompute the effective connection type if the number of samples | 1688 // Recompute the effective connection type if the number of samples |
| 1668 // available now are more than twice in count than the number of | 1689 // available now are 50% more than the number of samples that were |
| 1669 // samples that were available when the effective connection type was | 1690 // available when the effective connection type was last computed. |
| 1670 // last computed. | 1691 rtt_observations_size_at_last_ect_computation_ * 1.5 >= |
| 1671 rtt_observations_size_at_last_ect_computation_ * 2 >= | |
| 1672 rtt_observations_.Size() && | 1692 rtt_observations_.Size() && |
| 1673 throughput_observations_size_at_last_ect_computation_ * 2 >= | 1693 throughput_observations_size_at_last_ect_computation_ * 1.5 >= |
| 1674 downstream_throughput_kbps_observations_.Size()) { | 1694 downstream_throughput_kbps_observations_.Size()) { |
| 1675 return; | 1695 return; |
| 1676 } | 1696 } |
| 1677 | 1697 ComputeEffectiveConnectionType(); |
| 1678 const EffectiveConnectionType past_type = effective_connection_type_; | |
| 1679 last_effective_connection_type_computation_ = now; | |
| 1680 effective_connection_type_ = GetEffectiveConnectionType(); | |
| 1681 | |
| 1682 if (past_type != effective_connection_type_) | |
| 1683 NotifyObserversOfEffectiveConnectionTypeChanged(); | |
| 1684 | |
| 1685 rtt_observations_size_at_last_ect_computation_ = rtt_observations_.Size(); | |
| 1686 throughput_observations_size_at_last_ect_computation_ = | |
| 1687 downstream_throughput_kbps_observations_.Size(); | |
| 1688 } | 1698 } |
| 1689 | 1699 |
| 1690 void NetworkQualityEstimator:: | 1700 void NetworkQualityEstimator:: |
| 1691 NotifyObserversOfEffectiveConnectionTypeChanged() { | 1701 NotifyObserversOfEffectiveConnectionTypeChanged() { |
| 1692 DCHECK(thread_checker_.CalledOnValidThread()); | 1702 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1693 DCHECK_NE(EFFECTIVE_CONNECTION_TYPE_LAST, effective_connection_type_); | 1703 DCHECK_NE(EFFECTIVE_CONNECTION_TYPE_LAST, effective_connection_type_); |
| 1694 | 1704 |
| 1695 // TODO(tbansal): Add hysteresis in the notification. | 1705 // TODO(tbansal): Add hysteresis in the notification. |
| 1696 FOR_EACH_OBSERVER( | 1706 FOR_EACH_OBSERVER( |
| 1697 EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, | 1707 EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, |
| 1698 OnEffectiveConnectionTypeChanged(effective_connection_type_)); | 1708 OnEffectiveConnectionTypeChanged(effective_connection_type_)); |
| 1699 | 1709 |
| 1700 // Add the estimates of the current network to the cache store. | 1710 // Add the estimates of the current network to the cache store. |
| 1701 if (effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN) { | 1711 if (effective_connection_type_ != EFFECTIVE_CONNECTION_TYPE_UNKNOWN) { |
| 1702 network_quality_store_->Add( | 1712 network_quality_store_->Add( |
| 1703 current_network_id_, | 1713 current_network_id_, |
| 1704 nqe::internal::CachedNetworkQuality( | 1714 nqe::internal::CachedNetworkQuality( |
| 1705 tick_clock_->NowTicks(), estimated_quality_at_last_main_frame_, | 1715 tick_clock_->NowTicks(), estimated_quality_at_last_main_frame_, |
| 1706 effective_connection_type_)); | 1716 effective_connection_type_)); |
| 1707 } | 1717 } |
| 1708 } | 1718 } |
| 1709 | 1719 |
| 1710 } // namespace net | 1720 } // namespace net |
| OLD | NEW |