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 |