| 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/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> |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 133 bool allow_smaller_responses_for_tests) | 133 bool allow_smaller_responses_for_tests) |
| 134 : allow_localhost_requests_(allow_local_host_requests_for_tests), | 134 : allow_localhost_requests_(allow_local_host_requests_for_tests), |
| 135 allow_small_responses_(allow_smaller_responses_for_tests), | 135 allow_small_responses_(allow_smaller_responses_for_tests), |
| 136 last_connection_change_(base::TimeTicks::Now()), | 136 last_connection_change_(base::TimeTicks::Now()), |
| 137 current_network_id_( | 137 current_network_id_( |
| 138 NetworkID(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, | 138 NetworkID(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, |
| 139 std::string())), | 139 std::string())), |
| 140 downstream_throughput_kbps_observations_( | 140 downstream_throughput_kbps_observations_( |
| 141 GetWeightMultiplierPerSecond(variation_params)), | 141 GetWeightMultiplierPerSecond(variation_params)), |
| 142 rtt_msec_observations_(GetWeightMultiplierPerSecond(variation_params)), | 142 rtt_msec_observations_(GetWeightMultiplierPerSecond(variation_params)), |
| 143 external_estimates_provider_(external_estimates_provider.Pass()) { | 143 external_estimate_provider_(external_estimates_provider.Pass()), |
| 144 external_estimate_request_time_(base::TimeTicks()) { |
| 144 static_assert(kMinRequestDurationMicroseconds > 0, | 145 static_assert(kMinRequestDurationMicroseconds > 0, |
| 145 "Minimum request duration must be > 0"); | 146 "Minimum request duration must be > 0"); |
| 146 static_assert(kDefaultHalfLifeSeconds > 0, | 147 static_assert(kDefaultHalfLifeSeconds > 0, |
| 147 "Default half life duration must be > 0"); | 148 "Default half life duration must be > 0"); |
| 148 static_assert(kMaximumNetworkQualityCacheSize > 0, | 149 static_assert(kMaximumNetworkQualityCacheSize > 0, |
| 149 "Size of the network quality cache must be > 0"); | 150 "Size of the network quality cache must be > 0"); |
| 150 // This limit should not be increased unless the logic for removing the | 151 // This limit should not be increased unless the logic for removing the |
| 151 // oldest cache entry is rewritten to use a doubly-linked-list LRU queue. | 152 // oldest cache entry is rewritten to use a doubly-linked-list LRU queue. |
| 152 static_assert(kMaximumNetworkQualityCacheSize <= 10, | 153 static_assert(kMaximumNetworkQualityCacheSize <= 10, |
| 153 "Size of the network quality cache must <= 10"); | 154 "Size of the network quality cache must <= 10"); |
| 154 | 155 |
| 155 ObtainOperatingParams(variation_params); | 156 ObtainOperatingParams(variation_params); |
| 156 NetworkChangeNotifier::AddConnectionTypeObserver(this); | 157 NetworkChangeNotifier::AddConnectionTypeObserver(this); |
| 157 if (external_estimates_provider_) | 158 if (external_estimate_provider_) { |
| 158 external_estimates_provider_->SetUpdatedEstimateDelegate(this); | 159 UMA_HISTOGRAM_ENUMERATION("NQE.ExternalEstimateProviderStatus", |
| 160 EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE, |
| 161 EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY); |
| 162 external_estimate_provider_->SetUpdatedEstimateDelegate(this); |
| 163 QueryExternalEstimateProvider(); |
| 164 } else { |
| 165 UMA_HISTOGRAM_ENUMERATION("NQE.ExternalEstimateProviderStatus", |
| 166 EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE, |
| 167 EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY); |
| 168 } |
| 159 current_network_id_ = GetCurrentNetworkID(); | 169 current_network_id_ = GetCurrentNetworkID(); |
| 160 AddDefaultEstimates(); | 170 AddDefaultEstimates(); |
| 161 } | 171 } |
| 162 | 172 |
| 163 // static | 173 // static |
| 164 const base::TimeDelta NetworkQualityEstimator::InvalidRTT() { | 174 const base::TimeDelta NetworkQualityEstimator::InvalidRTT() { |
| 165 return base::TimeDelta::Max(); | 175 return base::TimeDelta::Max(); |
| 166 } | 176 } |
| 167 | 177 |
| 168 void NetworkQualityEstimator::ObtainOperatingParams( | 178 void NetworkQualityEstimator::ObtainOperatingParams( |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 } | 229 } |
| 220 | 230 |
| 221 NetworkQualityEstimator::~NetworkQualityEstimator() { | 231 NetworkQualityEstimator::~NetworkQualityEstimator() { |
| 222 DCHECK(thread_checker_.CalledOnValidThread()); | 232 DCHECK(thread_checker_.CalledOnValidThread()); |
| 223 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 233 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); |
| 224 } | 234 } |
| 225 | 235 |
| 226 void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) { | 236 void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) { |
| 227 DCHECK(thread_checker_.CalledOnValidThread()); | 237 DCHECK(thread_checker_.CalledOnValidThread()); |
| 228 | 238 |
| 239 MaybeQueryExternalEstimateProvider(); |
| 229 if (!RequestProvidesUsefulObservations(request)) | 240 if (!RequestProvidesUsefulObservations(request)) |
| 230 return; | 241 return; |
| 231 | 242 |
| 232 // Update |estimated_median_network_quality_| if this is a main frame request. | 243 // Update |estimated_median_network_quality_| if this is a main frame request. |
| 233 if (request.load_flags() & LOAD_MAIN_FRAME) { | 244 if (request.load_flags() & LOAD_MAIN_FRAME) { |
| 234 estimated_median_network_quality_ = NetworkQuality( | 245 estimated_median_network_quality_ = NetworkQuality( |
| 235 GetRTTEstimateInternal(base::TimeTicks(), 50), | 246 GetRTTEstimateInternal(base::TimeTicks(), 50), |
| 236 GetDownlinkThroughputKbpsEstimateInternal(base::TimeTicks(), 50)); | 247 GetDownlinkThroughputKbpsEstimateInternal(base::TimeTicks(), 50)); |
| 237 } | 248 } |
| 238 | 249 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 269 if (estimated_median_network_quality_.rtt() != InvalidRTT()) { | 280 if (estimated_median_network_quality_.rtt() != InvalidRTT()) { |
| 270 RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(), | 281 RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(), |
| 271 observed_rtt.InMilliseconds()); | 282 observed_rtt.InMilliseconds()); |
| 272 } | 283 } |
| 273 } | 284 } |
| 274 | 285 |
| 275 void NetworkQualityEstimator::NotifyRequestCompleted( | 286 void NetworkQualityEstimator::NotifyRequestCompleted( |
| 276 const URLRequest& request) { | 287 const URLRequest& request) { |
| 277 DCHECK(thread_checker_.CalledOnValidThread()); | 288 DCHECK(thread_checker_.CalledOnValidThread()); |
| 278 | 289 |
| 290 MaybeQueryExternalEstimateProvider(); |
| 279 if (!RequestProvidesUsefulObservations(request)) | 291 if (!RequestProvidesUsefulObservations(request)) |
| 280 return; | 292 return; |
| 281 | 293 |
| 282 base::TimeTicks now = base::TimeTicks::Now(); | 294 base::TimeTicks now = base::TimeTicks::Now(); |
| 283 LoadTimingInfo load_timing_info; | 295 LoadTimingInfo load_timing_info; |
| 284 request.GetLoadTimingInfo(&load_timing_info); | 296 request.GetLoadTimingInfo(&load_timing_info); |
| 285 | 297 |
| 286 // If the load timing info is unavailable, it probably means that the request | 298 // If the load timing info is unavailable, it probably means that the request |
| 287 // did not go over the network. | 299 // did not go over the network. |
| 288 if (load_timing_info.send_start.is_null() || | 300 if (load_timing_info.send_start.is_null() || |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 493 // Write the estimates of the previous network to the cache. | 505 // Write the estimates of the previous network to the cache. |
| 494 CacheNetworkQualityEstimate(); | 506 CacheNetworkQualityEstimate(); |
| 495 | 507 |
| 496 // Clear the local state. | 508 // Clear the local state. |
| 497 last_connection_change_ = base::TimeTicks::Now(); | 509 last_connection_change_ = base::TimeTicks::Now(); |
| 498 peak_network_quality_ = NetworkQuality(); | 510 peak_network_quality_ = NetworkQuality(); |
| 499 downstream_throughput_kbps_observations_.Clear(); | 511 downstream_throughput_kbps_observations_.Clear(); |
| 500 rtt_msec_observations_.Clear(); | 512 rtt_msec_observations_.Clear(); |
| 501 current_network_id_ = GetCurrentNetworkID(); | 513 current_network_id_ = GetCurrentNetworkID(); |
| 502 | 514 |
| 515 QueryExternalEstimateProvider(); |
| 516 |
| 503 // Read any cached estimates for the new network. If cached estimates are | 517 // Read any cached estimates for the new network. If cached estimates are |
| 504 // unavailable, add the default estimates. | 518 // unavailable, add the default estimates. |
| 505 if (!ReadCachedNetworkQualityEstimate()) | 519 if (!ReadCachedNetworkQualityEstimate()) |
| 506 AddDefaultEstimates(); | 520 AddDefaultEstimates(); |
| 507 estimated_median_network_quality_ = NetworkQuality(); | 521 estimated_median_network_quality_ = NetworkQuality(); |
| 508 } | 522 } |
| 509 | 523 |
| 510 bool NetworkQualityEstimator::GetRTTEstimate(base::TimeDelta* rtt) const { | 524 bool NetworkQualityEstimator::GetRTTEstimate(base::TimeDelta* rtt) { |
| 511 DCHECK(thread_checker_.CalledOnValidThread()); | 525 DCHECK(thread_checker_.CalledOnValidThread()); |
| 512 DCHECK(rtt); | 526 DCHECK(rtt); |
| 527 MaybeQueryExternalEstimateProvider(); |
| 513 if (rtt_msec_observations_.Size() == 0) { | 528 if (rtt_msec_observations_.Size() == 0) { |
| 514 *rtt = InvalidRTT(); | 529 *rtt = InvalidRTT(); |
| 515 return false; | 530 return false; |
| 516 } | 531 } |
| 517 *rtt = GetRTTEstimateInternal(base::TimeTicks(), 50); | 532 *rtt = GetRTTEstimateInternal(base::TimeTicks(), 50); |
| 518 return (*rtt != InvalidRTT()); | 533 return (*rtt != InvalidRTT()); |
| 519 } | 534 } |
| 520 | 535 |
| 521 bool NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate( | 536 bool NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(int32_t* kbps) { |
| 522 int32_t* kbps) const { | |
| 523 DCHECK(thread_checker_.CalledOnValidThread()); | 537 DCHECK(thread_checker_.CalledOnValidThread()); |
| 524 DCHECK(kbps); | 538 DCHECK(kbps); |
| 539 MaybeQueryExternalEstimateProvider(); |
| 525 if (downstream_throughput_kbps_observations_.Size() == 0) { | 540 if (downstream_throughput_kbps_observations_.Size() == 0) { |
| 526 *kbps = kInvalidThroughput; | 541 *kbps = kInvalidThroughput; |
| 527 return false; | 542 return false; |
| 528 } | 543 } |
| 529 *kbps = GetDownlinkThroughputKbpsEstimateInternal(base::TimeTicks(), 50); | 544 *kbps = GetDownlinkThroughputKbpsEstimateInternal(base::TimeTicks(), 50); |
| 530 return (*kbps != kInvalidThroughput); | 545 return (*kbps != kInvalidThroughput); |
| 531 } | 546 } |
| 532 | 547 |
| 533 bool NetworkQualityEstimator::GetRecentMedianRTT( | 548 bool NetworkQualityEstimator::GetRecentMedianRTT( |
| 534 const base::TimeTicks& begin_timestamp, | 549 const base::TimeTicks& begin_timestamp, |
| 535 base::TimeDelta* rtt) const { | 550 base::TimeDelta* rtt) { |
| 536 DCHECK(thread_checker_.CalledOnValidThread()); | 551 DCHECK(thread_checker_.CalledOnValidThread()); |
| 537 DCHECK(rtt); | 552 DCHECK(rtt); |
| 553 |
| 554 MaybeQueryExternalEstimateProvider(); |
| 538 *rtt = GetRTTEstimateInternal(begin_timestamp, 50); | 555 *rtt = GetRTTEstimateInternal(begin_timestamp, 50); |
| 539 return (*rtt != InvalidRTT()); | 556 return (*rtt != InvalidRTT()); |
| 540 } | 557 } |
| 541 | 558 |
| 542 bool NetworkQualityEstimator::GetRecentMedianDownlinkThroughputKbps( | 559 bool NetworkQualityEstimator::GetRecentMedianDownlinkThroughputKbps( |
| 543 const base::TimeTicks& begin_timestamp, | 560 const base::TimeTicks& begin_timestamp, |
| 544 int32_t* kbps) const { | 561 int32_t* kbps) { |
| 545 DCHECK(thread_checker_.CalledOnValidThread()); | 562 DCHECK(thread_checker_.CalledOnValidThread()); |
| 546 DCHECK(kbps); | 563 DCHECK(kbps); |
| 564 |
| 565 MaybeQueryExternalEstimateProvider(); |
| 547 *kbps = GetDownlinkThroughputKbpsEstimateInternal(begin_timestamp, 50); | 566 *kbps = GetDownlinkThroughputKbpsEstimateInternal(begin_timestamp, 50); |
| 548 return (*kbps != kInvalidThroughput); | 567 return (*kbps != kInvalidThroughput); |
| 549 } | 568 } |
| 550 | 569 |
| 551 NetworkQualityEstimator::Observation::Observation(int32_t value, | 570 NetworkQualityEstimator::Observation::Observation(int32_t value, |
| 552 base::TimeTicks timestamp) | 571 base::TimeTicks timestamp) |
| 553 : value(value), timestamp(timestamp) { | 572 : value(value), timestamp(timestamp) { |
| 554 DCHECK_GE(value, 0); | 573 DCHECK_GE(value, 0); |
| 555 DCHECK(!timestamp.is_null()); | 574 DCHECK(!timestamp.is_null()); |
| 556 } | 575 } |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 767 | 786 |
| 768 downstream_throughput_kbps_observations_.AddObservation(Observation( | 787 downstream_throughput_kbps_observations_.AddObservation(Observation( |
| 769 network_quality.downstream_throughput_kbps(), base::TimeTicks::Now())); | 788 network_quality.downstream_throughput_kbps(), base::TimeTicks::Now())); |
| 770 rtt_msec_observations_.AddObservation(Observation( | 789 rtt_msec_observations_.AddObservation(Observation( |
| 771 network_quality.rtt().InMilliseconds(), base::TimeTicks::Now())); | 790 network_quality.rtt().InMilliseconds(), base::TimeTicks::Now())); |
| 772 return true; | 791 return true; |
| 773 } | 792 } |
| 774 | 793 |
| 775 void NetworkQualityEstimator::OnUpdatedEstimateAvailable() { | 794 void NetworkQualityEstimator::OnUpdatedEstimateAvailable() { |
| 776 DCHECK(thread_checker_.CalledOnValidThread()); | 795 DCHECK(thread_checker_.CalledOnValidThread()); |
| 777 DCHECK(external_estimates_provider_); | 796 DCHECK(external_estimate_provider_); |
| 778 // TODO(tbansal): Query provider for the recent value. | 797 |
| 798 UMA_HISTOGRAM_ENUMERATION("NQE.ExternalEstimateProviderStatus", |
| 799 EXTERNAL_ESTIMATE_PROVIDER_STATUS_CALLBACK, |
| 800 EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY); |
| 801 |
| 802 QueryExternalEstimateProvider(); |
| 803 } |
| 804 |
| 805 void NetworkQualityEstimator::MaybeQueryExternalEstimateProvider() { |
| 806 if (base::TimeTicks::Now() - external_estimate_request_time_ >= |
| 807 base::TimeDelta::FromMilliseconds( |
| 808 kExternalEstimateProviderQueryIntervalMsec)) { |
| 809 QueryExternalEstimateProvider(); |
| 810 } |
| 811 } |
| 812 |
| 813 void NetworkQualityEstimator::QueryExternalEstimateProvider() { |
| 814 DCHECK(thread_checker_.CalledOnValidThread()); |
| 815 |
| 816 if (!external_estimate_provider_) |
| 817 return; |
| 818 UMA_HISTOGRAM_ENUMERATION("NQE.ExternalEstimateProviderStatus", |
| 819 EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED, |
| 820 EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY); |
| 821 |
| 822 external_estimate_request_time_ = base::TimeTicks::Now(); |
| 823 |
| 824 base::TimeDelta time_since_last_update; |
| 825 if (!external_estimate_provider_->GetTimeSinceLastUpdate( |
| 826 &time_since_last_update) || |
| 827 time_since_last_update > |
| 828 base::TimeDelta::FromMilliseconds( |
| 829 kExternalEstimateProviderQueryIntervalMsec)) { |
| 830 // Request the external estimate provider for updated estimates. When the |
| 831 // updates estimates are available, OnUpdatedEstimateAvailable() will get |
| 832 // called. |
| 833 external_estimate_provider_->RequestUpdate(); |
| 834 return; |
| 835 } |
| 836 |
| 837 UMA_HISTOGRAM_ENUMERATION("NQE.ExternalEstimateProviderStatus", |
| 838 EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL, |
| 839 EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY); |
| 840 |
| 841 base::TimeDelta rtt; |
| 842 if (external_estimate_provider_->GetRTT(&rtt)) { |
| 843 rtt_msec_observations_.AddObservation(Observation( |
| 844 rtt.InMilliseconds(), base::TimeTicks::Now() - time_since_last_update)); |
| 845 } |
| 846 |
| 847 int32_t downstream_throughput_kbps; |
| 848 if (external_estimate_provider_->GetDownstreamThroughputKbps( |
| 849 &downstream_throughput_kbps)) { |
| 850 downstream_throughput_kbps_observations_.AddObservation( |
| 851 Observation(downstream_throughput_kbps, |
| 852 base::TimeTicks::Now() - time_since_last_update)); |
| 853 } |
| 779 } | 854 } |
| 780 | 855 |
| 781 void NetworkQualityEstimator::CacheNetworkQualityEstimate() { | 856 void NetworkQualityEstimator::CacheNetworkQualityEstimate() { |
| 782 DCHECK(thread_checker_.CalledOnValidThread()); | 857 DCHECK(thread_checker_.CalledOnValidThread()); |
| 783 DCHECK_LE(cached_network_qualities_.size(), | 858 DCHECK_LE(cached_network_qualities_.size(), |
| 784 static_cast<size_t>(kMaximumNetworkQualityCacheSize)); | 859 static_cast<size_t>(kMaximumNetworkQualityCacheSize)); |
| 785 | 860 |
| 786 // If the network name is unavailable, caching should not be performed. | 861 // If the network name is unavailable, caching should not be performed. |
| 787 if (current_network_id_.id.empty()) | 862 if (current_network_id_.id.empty()) |
| 788 return; | 863 return; |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 857 | 932 |
| 858 NetworkQualityEstimator::NetworkQuality& | 933 NetworkQualityEstimator::NetworkQuality& |
| 859 NetworkQualityEstimator::NetworkQuality:: | 934 NetworkQualityEstimator::NetworkQuality:: |
| 860 operator=(const NetworkQuality& other) { | 935 operator=(const NetworkQuality& other) { |
| 861 rtt_ = other.rtt_; | 936 rtt_ = other.rtt_; |
| 862 downstream_throughput_kbps_ = other.downstream_throughput_kbps_; | 937 downstream_throughput_kbps_ = other.downstream_throughput_kbps_; |
| 863 return *this; | 938 return *this; |
| 864 } | 939 } |
| 865 | 940 |
| 866 } // namespace net | 941 } // namespace net |
| OLD | NEW |