Chromium Code Reviews| 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 <limits> | 7 #include <limits> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/metrics/histogram.h" | 12 #include "base/metrics/histogram.h" |
| 13 #include "build/build_config.h" | |
| 12 #include "net/base/load_timing_info.h" | 14 #include "net/base/load_timing_info.h" |
| 13 #include "net/base/net_util.h" | 15 #include "net/base/net_util.h" |
| 14 #include "net/base/network_quality.h" | 16 #include "net/base/network_interfaces.h" |
| 15 #include "net/url_request/url_request.h" | 17 #include "net/url_request/url_request.h" |
| 16 #include "url/gurl.h" | 18 #include "url/gurl.h" |
| 17 | 19 |
| 20 #if defined(OS_ANDROID) | |
| 21 #include "net/android/network_library.h" | |
| 22 #endif // OS_ANDROID | |
| 23 | |
| 18 namespace { | 24 namespace { |
| 19 | 25 |
| 20 // Maximum number of observations that can be held in the ObservationBuffer. | 26 // Maximum number of observations that can be held in the ObservationBuffer. |
| 21 const size_t kMaximumObservationsBufferSize = 500; | 27 const size_t kMaximumObservationsBufferSize = 500; |
| 22 | 28 |
| 23 } // namespace | 29 } // namespace |
| 24 | 30 |
| 25 namespace net { | 31 namespace net { |
| 26 | 32 |
| 33 const size_t NetworkQualityEstimator::kMaximumNetworkQualityCacheSize = 10; | |
|
pauljensen
2015/06/17 14:19:15
Please add a comment like this or preferably addre
pauljensen
2015/06/17 14:32:45
Another benefit to switching to an LRU queue is th
tbansal1
2015/06/17 21:18:45
Thats a valid point but I think here for some reas
tbansal1
2015/06/17 21:18:46
Done.
| |
| 34 | |
| 27 NetworkQualityEstimator::NetworkQualityEstimator() | 35 NetworkQualityEstimator::NetworkQualityEstimator() |
| 28 : NetworkQualityEstimator(false, false) { | 36 : NetworkQualityEstimator(false, false) { |
| 29 } | 37 } |
| 30 | 38 |
| 31 NetworkQualityEstimator::NetworkQualityEstimator( | 39 NetworkQualityEstimator::NetworkQualityEstimator( |
| 32 bool allow_local_host_requests_for_tests, | 40 bool allow_local_host_requests_for_tests, |
| 33 bool allow_smaller_responses_for_tests) | 41 bool allow_smaller_responses_for_tests) |
| 34 : allow_localhost_requests_(allow_local_host_requests_for_tests), | 42 : allow_localhost_requests_(allow_local_host_requests_for_tests), |
| 35 allow_small_responses_(allow_smaller_responses_for_tests), | 43 allow_small_responses_(allow_smaller_responses_for_tests), |
| 36 last_connection_change_(base::TimeTicks::Now()), | 44 last_connection_change_(base::TimeTicks::Now()), |
| 37 current_connection_type_(NetworkChangeNotifier::GetConnectionType()), | 45 current_network_id_( |
| 46 NetworkID(NetworkChangeNotifier::GetConnectionType(), std::string())), | |
| 38 fastest_rtt_since_last_connection_change_(base::TimeDelta::Max()), | 47 fastest_rtt_since_last_connection_change_(base::TimeDelta::Max()), |
| 39 peak_kbps_since_last_connection_change_(0) { | 48 peak_kbps_since_last_connection_change_(0) { |
| 40 static_assert(kMinRequestDurationMicroseconds > 0, | 49 static_assert(kMinRequestDurationMicroseconds > 0, |
| 41 "Minimum request duration must be > 0"); | 50 "Minimum request duration must be > 0"); |
| 51 static_assert(kMaximumNetworkQualityCacheSize > 0, | |
| 52 "Size of the network quality cache must be > 0"); | |
| 42 NetworkChangeNotifier::AddConnectionTypeObserver(this); | 53 NetworkChangeNotifier::AddConnectionTypeObserver(this); |
| 54 current_network_id_.id = GetCurrentNetworkName(); | |
| 43 } | 55 } |
| 44 | 56 |
| 45 NetworkQualityEstimator::~NetworkQualityEstimator() { | 57 NetworkQualityEstimator::~NetworkQualityEstimator() { |
| 46 DCHECK(thread_checker_.CalledOnValidThread()); | 58 DCHECK(thread_checker_.CalledOnValidThread()); |
| 47 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 59 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); |
| 48 } | 60 } |
| 49 | 61 |
| 50 void NetworkQualityEstimator::NotifyDataReceived( | 62 void NetworkQualityEstimator::NotifyDataReceived( |
| 51 const URLRequest& request, | 63 const URLRequest& request, |
| 52 int64_t cumulative_prefilter_bytes_read, | 64 int64_t cumulative_prefilter_bytes_read, |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 129 | 141 |
| 130 kbps_observations_.AddObservation(Observation(kbps, now)); | 142 kbps_observations_.AddObservation(Observation(kbps, now)); |
| 131 } | 143 } |
| 132 } | 144 } |
| 133 } | 145 } |
| 134 | 146 |
| 135 void NetworkQualityEstimator::OnConnectionTypeChanged( | 147 void NetworkQualityEstimator::OnConnectionTypeChanged( |
| 136 NetworkChangeNotifier::ConnectionType type) { | 148 NetworkChangeNotifier::ConnectionType type) { |
| 137 DCHECK(thread_checker_.CalledOnValidThread()); | 149 DCHECK(thread_checker_.CalledOnValidThread()); |
| 138 if (fastest_rtt_since_last_connection_change_ != base::TimeDelta::Max()) { | 150 if (fastest_rtt_since_last_connection_change_ != base::TimeDelta::Max()) { |
| 139 switch (current_connection_type_) { | 151 switch (current_network_id_.type) { |
| 140 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | 152 case NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| 141 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", | 153 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", |
| 142 fastest_rtt_since_last_connection_change_); | 154 fastest_rtt_since_last_connection_change_); |
| 143 break; | 155 break; |
| 144 case NetworkChangeNotifier::CONNECTION_ETHERNET: | 156 case NetworkChangeNotifier::CONNECTION_ETHERNET: |
| 145 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", | 157 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", |
| 146 fastest_rtt_since_last_connection_change_); | 158 fastest_rtt_since_last_connection_change_); |
| 147 break; | 159 break; |
| 148 case NetworkChangeNotifier::CONNECTION_WIFI: | 160 case NetworkChangeNotifier::CONNECTION_WIFI: |
| 149 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", | 161 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 163 break; | 175 break; |
| 164 case NetworkChangeNotifier::CONNECTION_NONE: | 176 case NetworkChangeNotifier::CONNECTION_NONE: |
| 165 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", | 177 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", |
| 166 fastest_rtt_since_last_connection_change_); | 178 fastest_rtt_since_last_connection_change_); |
| 167 break; | 179 break; |
| 168 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | 180 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| 169 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", | 181 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", |
| 170 fastest_rtt_since_last_connection_change_); | 182 fastest_rtt_since_last_connection_change_); |
| 171 break; | 183 break; |
| 172 default: | 184 default: |
| 173 NOTREACHED(); | 185 NOTREACHED() << "Unexpected connection type = " |
| 186 << current_network_id_.type; | |
| 174 break; | 187 break; |
| 175 } | 188 } |
| 176 } | 189 } |
| 177 | 190 |
| 178 if (peak_kbps_since_last_connection_change_) { | 191 if (peak_kbps_since_last_connection_change_) { |
| 179 switch (current_connection_type_) { | 192 switch (current_network_id_.type) { |
| 180 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | 193 case NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| 181 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", | 194 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", |
| 182 peak_kbps_since_last_connection_change_); | 195 peak_kbps_since_last_connection_change_); |
| 183 break; | 196 break; |
| 184 case NetworkChangeNotifier::CONNECTION_ETHERNET: | 197 case NetworkChangeNotifier::CONNECTION_ETHERNET: |
| 185 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet", | 198 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet", |
| 186 peak_kbps_since_last_connection_change_); | 199 peak_kbps_since_last_connection_change_); |
| 187 break; | 200 break; |
| 188 case NetworkChangeNotifier::CONNECTION_WIFI: | 201 case NetworkChangeNotifier::CONNECTION_WIFI: |
| 189 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi", | 202 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi", |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 203 break; | 216 break; |
| 204 case NetworkChangeNotifier::CONNECTION_NONE: | 217 case NetworkChangeNotifier::CONNECTION_NONE: |
| 205 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", | 218 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", |
| 206 peak_kbps_since_last_connection_change_); | 219 peak_kbps_since_last_connection_change_); |
| 207 break; | 220 break; |
| 208 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | 221 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| 209 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", | 222 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", |
| 210 peak_kbps_since_last_connection_change_); | 223 peak_kbps_since_last_connection_change_); |
| 211 break; | 224 break; |
| 212 default: | 225 default: |
| 213 NOTREACHED(); | 226 NOTREACHED() << "Unexpected connection type = " |
| 227 << current_network_id_.type; | |
| 214 break; | 228 break; |
| 215 } | 229 } |
| 216 } | 230 } |
| 217 | 231 |
| 232 // Write the estimates of the previous network to the cache. | |
| 233 CacheNetworkQualityEstimate(); | |
| 234 | |
| 235 // Clear the local state. | |
| 218 last_connection_change_ = base::TimeTicks::Now(); | 236 last_connection_change_ = base::TimeTicks::Now(); |
| 219 peak_kbps_since_last_connection_change_ = 0; | 237 peak_kbps_since_last_connection_change_ = 0; |
| 220 fastest_rtt_since_last_connection_change_ = base::TimeDelta::Max(); | 238 fastest_rtt_since_last_connection_change_ = base::TimeDelta::Max(); |
| 221 kbps_observations_.Clear(); | 239 kbps_observations_.Clear(); |
| 222 rtt_msec_observations_.Clear(); | 240 rtt_msec_observations_.Clear(); |
| 223 current_connection_type_ = type; | 241 |
| 242 // Update the current network ID. | |
| 243 current_network_id_.type = type; | |
| 244 current_network_id_.id = GetCurrentNetworkName(); | |
| 245 | |
| 246 // Read any cached estimates for the new network. | |
| 247 ReadCachedNetworkQualityEstimate(); | |
| 248 } | |
| 249 | |
| 250 size_t NetworkQualityEstimator::GetNetworkQualityCacheSizeForTests() const { | |
| 251 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 252 return cached_network_qualities_.size(); | |
| 224 } | 253 } |
| 225 | 254 |
| 226 NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const { | 255 NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const { |
| 227 DCHECK(thread_checker_.CalledOnValidThread()); | 256 DCHECK(thread_checker_.CalledOnValidThread()); |
| 228 | 257 |
| 229 return NetworkQuality(fastest_rtt_since_last_connection_change_, | 258 return NetworkQuality(fastest_rtt_since_last_connection_change_, |
| 230 peak_kbps_since_last_connection_change_); | 259 peak_kbps_since_last_connection_change_); |
| 231 } | 260 } |
| 232 | 261 |
| 233 size_t NetworkQualityEstimator::GetMaximumObservationBufferSizeForTests() | 262 size_t NetworkQualityEstimator::GetMaximumObservationBufferSizeForTests() |
| 234 const { | 263 const { |
| 264 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 235 return kMaximumObservationsBufferSize; | 265 return kMaximumObservationsBufferSize; |
| 236 } | 266 } |
| 237 | 267 |
| 238 bool NetworkQualityEstimator::VerifyBufferSizeForTests( | 268 bool NetworkQualityEstimator::VerifyBufferSizeForTests( |
| 239 size_t expected_size) const { | 269 size_t expected_size) const { |
| 270 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 240 return kbps_observations_.Size() == expected_size && | 271 return kbps_observations_.Size() == expected_size && |
| 241 rtt_msec_observations_.Size() == expected_size; | 272 rtt_msec_observations_.Size() == expected_size; |
| 242 } | 273 } |
| 243 | 274 |
| 244 NetworkQualityEstimator::Observation::Observation(int32_t value, | 275 NetworkQualityEstimator::Observation::Observation(int32_t value, |
| 245 base::TimeTicks timestamp) | 276 base::TimeTicks timestamp) |
| 246 : value(value), timestamp(timestamp) { | 277 : value(value), timestamp(timestamp) { |
| 247 DCHECK_GE(value, 0); | 278 DCHECK_GE(value, 0); |
| 248 DCHECK(!timestamp.is_null()); | 279 DCHECK(!timestamp.is_null()); |
| 249 } | 280 } |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 272 | 303 |
| 273 size_t NetworkQualityEstimator::ObservationBuffer::Size() const { | 304 size_t NetworkQualityEstimator::ObservationBuffer::Size() const { |
| 274 return observations_.size(); | 305 return observations_.size(); |
| 275 } | 306 } |
| 276 | 307 |
| 277 void NetworkQualityEstimator::ObservationBuffer::Clear() { | 308 void NetworkQualityEstimator::ObservationBuffer::Clear() { |
| 278 observations_.clear(); | 309 observations_.clear(); |
| 279 DCHECK(observations_.empty()); | 310 DCHECK(observations_.empty()); |
| 280 } | 311 } |
| 281 | 312 |
| 313 std::string NetworkQualityEstimator::GetCurrentNetworkName() const { | |
| 314 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class | |
| 315 // that overrides this method on the Android platform. | |
| 316 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 317 | |
| 318 switch (current_network_id_.type) { | |
|
pauljensen
2015/06/17 14:19:15
This is racy. You're using a potentially old valu
tbansal1
2015/06/17 21:18:46
Thanks for catching this. I made the change but th
| |
| 319 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN: | |
| 320 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE: | |
| 321 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH: | |
| 322 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET: | |
| 323 return std::string(); | |
| 324 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI: | |
| 325 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) | |
| 326 return GetWifiSSID(); | |
| 327 #else | |
| 328 return std::string(); | |
|
pauljensen
2015/06/17 14:19:15
Does this mean every WiFi network will match every
tbansal1
2015/06/17 21:18:46
Yes, it does mean that on unsupported OSes. My pre
pauljensen
2015/06/18 16:20:25
I don't think I agree with that. We already have
tbansal1
2015/06/18 20:57:40
I don't think I feel strongly either way (especial
| |
| 329 #endif | |
| 330 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G: | |
| 331 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G: | |
| 332 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G: | |
| 333 #if defined(OS_ANDROID) | |
| 334 return android::GetTelephonyNetworkOperator(); | |
| 335 #else | |
| 336 return std::string(); | |
| 337 #endif | |
| 338 default: | |
| 339 NOTREACHED() << "Unexpected connection type = " | |
| 340 << current_network_id_.type; | |
| 341 return std::string(); | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() { | |
| 346 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 347 | |
| 348 CachedNetworkQualities::iterator it = | |
| 349 cached_network_qualities_.find(current_network_id_); | |
| 350 if (it != cached_network_qualities_.end()) { | |
| 351 // TOOD(tbansal): Populate these values back into the median computing | |
| 352 // algorithm. | |
| 353 // Add UMA to record how frequently matches happen. | |
| 354 // Ensure that the estimates read are non-zero before populating them into | |
| 355 // the median computing algorithm. | |
| 356 peak_kbps_since_last_connection_change_ = | |
| 357 it->second->network_quality().downstream_throughput_kbps(); | |
| 358 fastest_rtt_since_last_connection_change_ = | |
| 359 it->second->network_quality().rtt(); | |
| 360 return true; | |
| 361 } | |
| 362 return false; | |
| 363 } | |
| 364 | |
| 365 void NetworkQualityEstimator::CacheNetworkQualityEstimate() { | |
| 366 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 367 DCHECK_LE(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize); | |
| 368 | |
| 369 // TODO(tbansal): The following variables should be initialized using the | |
| 370 // median values reported by the NetworkQualityEstimator. | |
| 371 int median_kbps = peak_kbps_since_last_connection_change_; | |
| 372 base::TimeDelta median_rtt = fastest_rtt_since_last_connection_change_; | |
| 373 | |
| 374 // If this network is already in the cache, overwrite that entry. | |
| 375 CachedNetworkQualities::iterator it = | |
| 376 cached_network_qualities_.find(current_network_id_); | |
| 377 if (it != cached_network_qualities_.end()) { | |
| 378 (it->second)->UpdateNetworkQuality(median_kbps, median_rtt); | |
| 379 return; | |
| 380 } | |
| 381 | |
| 382 if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) { | |
| 383 // Remove the oldest entry. | |
| 384 CachedNetworkQualities::iterator oldest_entry_iterator = | |
| 385 cached_network_qualities_.begin(); | |
| 386 | |
| 387 for (CachedNetworkQualities::iterator iterator = | |
| 388 cached_network_qualities_.begin(); | |
| 389 iterator != cached_network_qualities_.end(); ++iterator) { | |
| 390 if ((oldest_entry_iterator->second)->last_update_time() > | |
| 391 (iterator->second)->last_update_time()) { | |
| 392 oldest_entry_iterator = iterator; | |
| 393 } | |
| 394 } | |
| 395 cached_network_qualities_.erase(oldest_entry_iterator); | |
| 396 } | |
| 397 | |
| 398 DCHECK_LT(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize); | |
| 399 cached_network_qualities_.insert(std::make_pair( | |
| 400 current_network_id_, make_scoped_ptr(new CachedNetworkQuality( | |
| 401 NetworkQuality(median_rtt, median_kbps))))); | |
| 402 DCHECK_LE(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize); | |
| 403 } | |
| 404 | |
| 405 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality( | |
| 406 const NetworkQuality& network_quality) | |
| 407 : last_update_time_(base::TimeTicks::Now()), | |
| 408 network_quality_(network_quality) { | |
| 409 } | |
| 410 | |
| 411 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() { | |
| 412 } | |
| 413 | |
| 414 void NetworkQualityEstimator::CachedNetworkQuality::UpdateNetworkQuality( | |
| 415 int32_t median_kbps, | |
| 416 const base::TimeDelta& median_rtt) { | |
| 417 DCHECK_GE(median_kbps, 0); | |
| 418 DCHECK_GE(median_rtt, base::TimeDelta()); | |
| 419 last_update_time_ = base::TimeTicks::Now(); | |
| 420 | |
| 421 network_quality_ = NetworkQuality(median_rtt, median_kbps); | |
| 422 } | |
| 423 | |
| 282 } // namespace net | 424 } // namespace net |
| OLD | NEW |