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 <float.h> | 7 #include <float.h> |
| 8 #include <algorithm> | 8 #include <algorithm> |
| 9 #include <cmath> | 9 #include <cmath> |
| 10 #include <limits> | 10 #include <limits> |
| 11 #include <string> | |
| 12 #include <vector> | 11 #include <vector> |
| 13 | 12 |
| 14 #include "base/logging.h" | 13 #include "base/logging.h" |
| 15 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 16 #include "base/metrics/histogram_base.h" | 15 #include "base/metrics/histogram_base.h" |
| 17 #include "base/strings/safe_sprintf.h" | 16 #include "base/strings/safe_sprintf.h" |
| 18 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 18 #include "build/build_config.h" | |
| 19 #include "net/base/load_flags.h" | 19 #include "net/base/load_flags.h" |
| 20 #include "net/base/load_timing_info.h" | 20 #include "net/base/load_timing_info.h" |
| 21 #include "net/base/net_util.h" | 21 #include "net/base/net_util.h" |
| 22 #include "net/base/network_interfaces.h" | |
| 22 #include "net/url_request/url_request.h" | 23 #include "net/url_request/url_request.h" |
| 23 #include "url/gurl.h" | 24 #include "url/gurl.h" |
| 24 | 25 |
| 26 #if defined(OS_ANDROID) | |
| 27 #include "net/android/network_library.h" | |
| 28 #endif // OS_ANDROID | |
| 29 | |
| 25 namespace { | 30 namespace { |
| 26 | 31 |
| 27 // Maximum number of observations that can be held in the ObservationBuffer. | |
| 28 const size_t kMaximumObservationsBufferSize = 300; | |
| 29 | |
| 30 // Default value of the half life (in seconds) for computing time weighted | 32 // Default value of the half life (in seconds) for computing time weighted |
| 31 // percentiles. Every half life, the weight of all observations reduces by | 33 // percentiles. Every half life, the weight of all observations reduces by |
| 32 // half. Lowering the half life would reduce the weight of older values faster. | 34 // half. Lowering the half life would reduce the weight of older values faster. |
| 33 const int kDefaultHalfLifeSeconds = 60; | 35 const int kDefaultHalfLifeSeconds = 60; |
| 34 | 36 |
| 35 // Name of the variation parameter that holds the value of the half life (in | 37 // Name of the variation parameter that holds the value of the half life (in |
| 36 // seconds) of the observations. | 38 // seconds) of the observations. |
| 37 const char kHalfLifeSecondsParamName[] = "HalfLifeSeconds"; | 39 const char kHalfLifeSecondsParamName[] = "HalfLifeSeconds"; |
| 38 | 40 |
| 39 // Returns a descriptive name corresponding to |connection_type|. | 41 // Returns a descriptive name corresponding to |connection_type|. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 const char prefix[] = "NQE."; | 110 const char prefix[] = "NQE."; |
| 109 return base::Histogram::FactoryGet( | 111 return base::Histogram::FactoryGet( |
| 110 prefix + statistic_name + GetNameForConnectionType(type), kLowerLimit, | 112 prefix + statistic_name + GetNameForConnectionType(type), kLowerLimit, |
| 111 max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag); | 113 max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag); |
| 112 } | 114 } |
| 113 | 115 |
| 114 } // namespace | 116 } // namespace |
| 115 | 117 |
| 116 namespace net { | 118 namespace net { |
| 117 | 119 |
| 120 const size_t NetworkQualityEstimator::kMaximumNetworkQualityCacheSize = 10; | |
|
pauljensen
2015/07/14 11:59:03
how about initializing this in the header like the
tbansal1
2015/07/14 19:51:48
I get linking error:
../../net/base/network_qualit
pauljensen
2015/07/14 20:19:59
Can you track this down further? Use objdump or n
| |
| 121 | |
| 122 const size_t NetworkQualityEstimator::kMaximumObservationsBufferSize = 300; | |
|
pauljensen
2015/07/14 11:59:03
ditto
tbansal1
2015/07/14 19:51:48
See reply above.
| |
| 123 | |
| 118 NetworkQualityEstimator::NetworkQualityEstimator( | 124 NetworkQualityEstimator::NetworkQualityEstimator( |
| 119 const std::map<std::string, std::string>& variation_params) | 125 const std::map<std::string, std::string>& variation_params) |
| 120 : NetworkQualityEstimator(variation_params, false, false) { | 126 : NetworkQualityEstimator(variation_params, false, false) { |
| 121 } | 127 } |
| 122 | 128 |
| 123 NetworkQualityEstimator::NetworkQualityEstimator( | 129 NetworkQualityEstimator::NetworkQualityEstimator( |
| 124 const std::map<std::string, std::string>& variation_params, | 130 const std::map<std::string, std::string>& variation_params, |
| 125 bool allow_local_host_requests_for_tests, | 131 bool allow_local_host_requests_for_tests, |
| 126 bool allow_smaller_responses_for_tests) | 132 bool allow_smaller_responses_for_tests) |
| 127 : allow_localhost_requests_(allow_local_host_requests_for_tests), | 133 : allow_localhost_requests_(allow_local_host_requests_for_tests), |
| 128 allow_small_responses_(allow_smaller_responses_for_tests), | 134 allow_small_responses_(allow_smaller_responses_for_tests), |
| 129 last_connection_change_(base::TimeTicks::Now()), | 135 last_connection_change_(base::TimeTicks::Now()), |
| 130 current_connection_type_(NetworkChangeNotifier::GetConnectionType()), | 136 current_network_id_( |
| 131 fastest_rtt_since_last_connection_change_(NetworkQuality::InvalidRTT()), | 137 NetworkID(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, |
| 132 peak_kbps_since_last_connection_change_( | 138 std::string())), |
| 133 NetworkQuality::kInvalidThroughput), | |
| 134 kbps_observations_(GetWeightMultiplierPerSecond(variation_params)), | 139 kbps_observations_(GetWeightMultiplierPerSecond(variation_params)), |
| 135 rtt_msec_observations_(GetWeightMultiplierPerSecond(variation_params)) { | 140 rtt_msec_observations_(GetWeightMultiplierPerSecond(variation_params)) { |
| 136 static_assert(kMinRequestDurationMicroseconds > 0, | 141 static_assert(kMinRequestDurationMicroseconds > 0, |
| 137 "Minimum request duration must be > 0"); | 142 "Minimum request duration must be > 0"); |
| 138 static_assert(kDefaultHalfLifeSeconds > 0, | 143 static_assert(kDefaultHalfLifeSeconds > 0, |
| 139 "Default half life duration must be > 0"); | 144 "Default half life duration must be > 0"); |
| 145 static_assert(kMaximumNetworkQualityCacheSize > 0, | |
| 146 "Size of the network quality cache must be > 0"); | |
| 147 // This limit should not be increased unless the logic for removing the | |
| 148 // oldest cache entry is rewritten to use a doubly-linked-list LRU queue. | |
| 149 static_assert(kMaximumNetworkQualityCacheSize <= 10, | |
| 150 "Size of the network quality cache must <= 10"); | |
| 140 | 151 |
| 141 ObtainOperatingParams(variation_params); | 152 ObtainOperatingParams(variation_params); |
| 153 NetworkChangeNotifier::AddConnectionTypeObserver(this); | |
| 154 current_network_id_ = GetCurrentNetworkID(); | |
| 142 AddDefaultEstimates(); | 155 AddDefaultEstimates(); |
| 143 NetworkChangeNotifier::AddConnectionTypeObserver(this); | |
| 144 } | 156 } |
| 145 | 157 |
| 146 void NetworkQualityEstimator::ObtainOperatingParams( | 158 void NetworkQualityEstimator::ObtainOperatingParams( |
| 147 const std::map<std::string, std::string>& variation_params) { | 159 const std::map<std::string, std::string>& variation_params) { |
| 148 DCHECK(thread_checker_.CalledOnValidThread()); | 160 DCHECK(thread_checker_.CalledOnValidThread()); |
| 149 | 161 |
| 150 for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) { | 162 for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) { |
| 151 NetworkChangeNotifier::ConnectionType type = | 163 NetworkChangeNotifier::ConnectionType type = |
| 152 static_cast<NetworkChangeNotifier::ConnectionType>(i); | 164 static_cast<NetworkChangeNotifier::ConnectionType>(i); |
| 153 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1; | 165 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 175 base::StringToInt(it->second, &variations_value) && | 187 base::StringToInt(it->second, &variations_value) && |
| 176 variations_value >= kMinimumThroughputVariationParameterKbps) { | 188 variations_value >= kMinimumThroughputVariationParameterKbps) { |
| 177 default_observations_[i] = | 189 default_observations_[i] = |
| 178 NetworkQuality(default_observations_[i].rtt(), variations_value); | 190 NetworkQuality(default_observations_[i].rtt(), variations_value); |
| 179 } | 191 } |
| 180 } | 192 } |
| 181 } | 193 } |
| 182 | 194 |
| 183 void NetworkQualityEstimator::AddDefaultEstimates() { | 195 void NetworkQualityEstimator::AddDefaultEstimates() { |
| 184 DCHECK(thread_checker_.CalledOnValidThread()); | 196 DCHECK(thread_checker_.CalledOnValidThread()); |
| 185 | 197 if (default_observations_[current_network_id_.type].rtt() != |
| 186 if (default_observations_[current_connection_type_].rtt() != | |
| 187 NetworkQuality::InvalidRTT()) { | 198 NetworkQuality::InvalidRTT()) { |
| 188 rtt_msec_observations_.AddObservation(Observation( | 199 rtt_msec_observations_.AddObservation(Observation( |
| 189 default_observations_[current_connection_type_].rtt().InMilliseconds(), | 200 default_observations_[current_network_id_.type].rtt().InMilliseconds(), |
| 190 base::TimeTicks::Now())); | 201 base::TimeTicks::Now())); |
| 191 } | 202 } |
| 192 | 203 if (default_observations_[current_network_id_.type] |
| 193 if (default_observations_[current_connection_type_] | |
| 194 .downstream_throughput_kbps() != NetworkQuality::kInvalidThroughput) { | 204 .downstream_throughput_kbps() != NetworkQuality::kInvalidThroughput) { |
| 195 kbps_observations_.AddObservation( | 205 kbps_observations_.AddObservation( |
| 196 Observation(default_observations_[current_connection_type_] | 206 Observation(default_observations_[current_network_id_.type] |
| 197 .downstream_throughput_kbps(), | 207 .downstream_throughput_kbps(), |
| 198 base::TimeTicks::Now())); | 208 base::TimeTicks::Now())); |
| 199 } | 209 } |
| 200 } | 210 } |
| 201 | 211 |
| 202 NetworkQualityEstimator::~NetworkQualityEstimator() { | 212 NetworkQualityEstimator::~NetworkQualityEstimator() { |
| 203 DCHECK(thread_checker_.CalledOnValidThread()); | 213 DCHECK(thread_checker_.CalledOnValidThread()); |
| 204 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 214 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); |
| 205 } | 215 } |
| 206 | 216 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 | 253 |
| 244 // Time when the headers were received. | 254 // Time when the headers were received. |
| 245 base::TimeTicks headers_received_time = load_timing_info.receive_headers_end; | 255 base::TimeTicks headers_received_time = load_timing_info.receive_headers_end; |
| 246 | 256 |
| 247 // Only add RTT observation if this is the first read for this response. | 257 // Only add RTT observation if this is the first read for this response. |
| 248 if (cumulative_prefilter_bytes_read == prefiltered_bytes_read) { | 258 if (cumulative_prefilter_bytes_read == prefiltered_bytes_read) { |
| 249 // Duration between when the resource was requested and when response | 259 // Duration between when the resource was requested and when response |
| 250 // headers were received. | 260 // headers were received. |
| 251 base::TimeDelta observed_rtt = headers_received_time - request_start_time; | 261 base::TimeDelta observed_rtt = headers_received_time - request_start_time; |
| 252 DCHECK_GE(observed_rtt, base::TimeDelta()); | 262 DCHECK_GE(observed_rtt, base::TimeDelta()); |
| 253 if (observed_rtt < fastest_rtt_since_last_connection_change_) | 263 if (observed_rtt < peak_network_quality_.rtt()) { |
| 254 fastest_rtt_since_last_connection_change_ = observed_rtt; | 264 peak_network_quality_ = NetworkQuality( |
| 265 observed_rtt, peak_network_quality_.downstream_throughput_kbps()); | |
| 266 } | |
| 255 | 267 |
| 256 rtt_msec_observations_.AddObservation( | 268 rtt_msec_observations_.AddObservation( |
| 257 Observation(observed_rtt.InMilliseconds(), now)); | 269 Observation(observed_rtt.InMilliseconds(), now)); |
| 258 | 270 |
| 259 // Compare the RTT observation with the estimated value and record it. | 271 // Compare the RTT observation with the estimated value and record it. |
| 260 if (estimated_median_network_quality_.rtt() != | 272 if (estimated_median_network_quality_.rtt() != |
| 261 NetworkQuality::InvalidRTT()) { | 273 NetworkQuality::InvalidRTT()) { |
| 262 RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(), | 274 RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(), |
| 263 observed_rtt.InMilliseconds()); | 275 observed_rtt.InMilliseconds()); |
| 264 } | 276 } |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 285 kbps_f = std::numeric_limits<int32_t>::max() - 1; | 297 kbps_f = std::numeric_limits<int32_t>::max() - 1; |
| 286 | 298 |
| 287 int32_t kbps = static_cast<int32_t>(kbps_f); | 299 int32_t kbps = static_cast<int32_t>(kbps_f); |
| 288 | 300 |
| 289 // If the |kbps| is less than 1, we set it to 1 to differentiate from case | 301 // If the |kbps| is less than 1, we set it to 1 to differentiate from case |
| 290 // when there is no connection. | 302 // when there is no connection. |
| 291 if (kbps_f > 0.0 && kbps == 0) | 303 if (kbps_f > 0.0 && kbps == 0) |
| 292 kbps = 1; | 304 kbps = 1; |
| 293 | 305 |
| 294 if (kbps > 0) { | 306 if (kbps > 0) { |
| 295 if (kbps > peak_kbps_since_last_connection_change_) | 307 if (kbps > peak_network_quality_.downstream_throughput_kbps()) { |
| 296 peak_kbps_since_last_connection_change_ = kbps; | 308 peak_network_quality_ = |
| 309 NetworkQuality(peak_network_quality_.rtt(), kbps); | |
| 310 } | |
| 297 | 311 |
| 298 kbps_observations_.AddObservation(Observation(kbps, now)); | 312 kbps_observations_.AddObservation(Observation(kbps, now)); |
| 299 } | 313 } |
| 300 } | 314 } |
| 301 } | 315 } |
| 302 | 316 |
| 303 void NetworkQualityEstimator::RecordRTTUMA(int32_t estimated_value_msec, | 317 void NetworkQualityEstimator::RecordRTTUMA(int32_t estimated_value_msec, |
| 304 int32_t actual_value_msec) const { | 318 int32_t actual_value_msec) const { |
| 305 DCHECK(thread_checker_.CalledOnValidThread()); | 319 DCHECK(thread_checker_.CalledOnValidThread()); |
| 306 | 320 |
| 307 // Record the difference between the actual and the estimated value. | 321 // Record the difference between the actual and the estimated value. |
| 308 if (estimated_value_msec >= actual_value_msec) { | 322 if (estimated_value_msec >= actual_value_msec) { |
| 309 base::HistogramBase* difference_rtt = | 323 base::HistogramBase* difference_rtt = |
| 310 GetHistogram("DifferenceRTTEstimatedAndActual.", | 324 GetHistogram("DifferenceRTTEstimatedAndActual.", |
| 311 current_connection_type_, 10 * 1000); // 10 seconds | 325 current_network_id_.type, 10 * 1000); // 10 seconds |
| 312 difference_rtt->Add(estimated_value_msec - actual_value_msec); | 326 difference_rtt->Add(estimated_value_msec - actual_value_msec); |
| 313 } else { | 327 } else { |
| 314 base::HistogramBase* difference_rtt = | 328 base::HistogramBase* difference_rtt = |
| 315 GetHistogram("DifferenceRTTActualAndEstimated.", | 329 GetHistogram("DifferenceRTTActualAndEstimated.", |
| 316 current_connection_type_, 10 * 1000); // 10 seconds | 330 current_network_id_.type, 10 * 1000); // 10 seconds |
| 317 difference_rtt->Add(actual_value_msec - estimated_value_msec); | 331 difference_rtt->Add(actual_value_msec - estimated_value_msec); |
| 318 } | 332 } |
| 319 | 333 |
| 320 // Record all the RTT observations. | 334 // Record all the RTT observations. |
| 321 base::HistogramBase* rtt_observations = | 335 base::HistogramBase* rtt_observations = |
| 322 GetHistogram("RTTObservations.", current_connection_type_, | 336 GetHistogram("RTTObservations.", current_network_id_.type, |
| 323 10 * 1000); // 10 seconds upper bound | 337 10 * 1000); // 10 seconds upper bound |
| 324 rtt_observations->Add(actual_value_msec); | 338 rtt_observations->Add(actual_value_msec); |
| 325 | 339 |
| 326 if (actual_value_msec == 0) | 340 if (actual_value_msec == 0) |
| 327 return; | 341 return; |
| 328 | 342 |
| 329 int32 ratio = (estimated_value_msec * 100) / actual_value_msec; | 343 int32 ratio = (estimated_value_msec * 100) / actual_value_msec; |
| 330 | 344 |
| 331 // Record the accuracy of estimation by recording the ratio of estimated | 345 // Record the accuracy of estimation by recording the ratio of estimated |
| 332 // value to the actual value. | 346 // value to the actual value. |
| 333 base::HistogramBase* ratio_median_rtt = GetHistogram( | 347 base::HistogramBase* ratio_median_rtt = GetHistogram( |
| 334 "RatioEstimatedToActualRTT.", current_connection_type_, 1000); | 348 "RatioEstimatedToActualRTT.", current_network_id_.type, 1000); |
| 335 ratio_median_rtt->Add(ratio); | 349 ratio_median_rtt->Add(ratio); |
| 336 } | 350 } |
| 337 | 351 |
| 338 void NetworkQualityEstimator::OnConnectionTypeChanged( | 352 void NetworkQualityEstimator::OnConnectionTypeChanged( |
| 339 NetworkChangeNotifier::ConnectionType type) { | 353 NetworkChangeNotifier::ConnectionType type) { |
| 340 DCHECK(thread_checker_.CalledOnValidThread()); | 354 DCHECK(thread_checker_.CalledOnValidThread()); |
| 341 if (fastest_rtt_since_last_connection_change_ != | 355 if (peak_network_quality_.rtt() != NetworkQuality::InvalidRTT()) { |
| 342 NetworkQuality::InvalidRTT()) { | 356 switch (current_network_id_.type) { |
| 343 switch (current_connection_type_) { | |
| 344 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | 357 case NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| 345 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", | 358 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", |
| 346 fastest_rtt_since_last_connection_change_); | 359 peak_network_quality_.rtt()); |
| 347 break; | 360 break; |
| 348 case NetworkChangeNotifier::CONNECTION_ETHERNET: | 361 case NetworkChangeNotifier::CONNECTION_ETHERNET: |
| 349 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", | 362 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", |
| 350 fastest_rtt_since_last_connection_change_); | 363 peak_network_quality_.rtt()); |
| 351 break; | 364 break; |
| 352 case NetworkChangeNotifier::CONNECTION_WIFI: | 365 case NetworkChangeNotifier::CONNECTION_WIFI: |
| 353 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", | 366 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", peak_network_quality_.rtt()); |
| 354 fastest_rtt_since_last_connection_change_); | |
| 355 break; | 367 break; |
| 356 case NetworkChangeNotifier::CONNECTION_2G: | 368 case NetworkChangeNotifier::CONNECTION_2G: |
| 357 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.2G", | 369 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.2G", peak_network_quality_.rtt()); |
| 358 fastest_rtt_since_last_connection_change_); | |
| 359 break; | 370 break; |
| 360 case NetworkChangeNotifier::CONNECTION_3G: | 371 case NetworkChangeNotifier::CONNECTION_3G: |
| 361 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.3G", | 372 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.3G", peak_network_quality_.rtt()); |
| 362 fastest_rtt_since_last_connection_change_); | |
| 363 break; | 373 break; |
| 364 case NetworkChangeNotifier::CONNECTION_4G: | 374 case NetworkChangeNotifier::CONNECTION_4G: |
| 365 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.4G", | 375 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.4G", peak_network_quality_.rtt()); |
| 366 fastest_rtt_since_last_connection_change_); | |
| 367 break; | 376 break; |
| 368 case NetworkChangeNotifier::CONNECTION_NONE: | 377 case NetworkChangeNotifier::CONNECTION_NONE: |
| 369 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", | 378 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", peak_network_quality_.rtt()); |
| 370 fastest_rtt_since_last_connection_change_); | |
| 371 break; | 379 break; |
| 372 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | 380 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| 373 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", | 381 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", |
| 374 fastest_rtt_since_last_connection_change_); | 382 peak_network_quality_.rtt()); |
| 375 break; | 383 break; |
| 376 default: | 384 default: |
| 377 NOTREACHED(); | 385 NOTREACHED() << "Unexpected connection type = " |
| 386 << current_network_id_.type; | |
| 378 break; | 387 break; |
| 379 } | 388 } |
| 380 } | 389 } |
| 381 | 390 |
| 382 if (peak_kbps_since_last_connection_change_ != | 391 if (peak_network_quality_.downstream_throughput_kbps() != |
| 383 NetworkQuality::kInvalidThroughput) { | 392 NetworkQuality::kInvalidThroughput) { |
| 384 switch (current_connection_type_) { | 393 switch (current_network_id_.type) { |
| 385 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | 394 case NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| 386 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", | 395 UMA_HISTOGRAM_COUNTS( |
| 387 peak_kbps_since_last_connection_change_); | 396 "NQE.PeakKbps.Unknown", |
| 397 peak_network_quality_.downstream_throughput_kbps()); | |
| 388 break; | 398 break; |
| 389 case NetworkChangeNotifier::CONNECTION_ETHERNET: | 399 case NetworkChangeNotifier::CONNECTION_ETHERNET: |
| 390 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet", | 400 UMA_HISTOGRAM_COUNTS( |
| 391 peak_kbps_since_last_connection_change_); | 401 "NQE.PeakKbps.Ethernet", |
| 402 peak_network_quality_.downstream_throughput_kbps()); | |
| 392 break; | 403 break; |
| 393 case NetworkChangeNotifier::CONNECTION_WIFI: | 404 case NetworkChangeNotifier::CONNECTION_WIFI: |
| 394 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi", | 405 UMA_HISTOGRAM_COUNTS( |
| 395 peak_kbps_since_last_connection_change_); | 406 "NQE.PeakKbps.Wifi", |
| 407 peak_network_quality_.downstream_throughput_kbps()); | |
| 396 break; | 408 break; |
| 397 case NetworkChangeNotifier::CONNECTION_2G: | 409 case NetworkChangeNotifier::CONNECTION_2G: |
| 398 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.2G", | 410 UMA_HISTOGRAM_COUNTS( |
| 399 peak_kbps_since_last_connection_change_); | 411 "NQE.PeakKbps.2G", |
| 412 peak_network_quality_.downstream_throughput_kbps()); | |
| 400 break; | 413 break; |
| 401 case NetworkChangeNotifier::CONNECTION_3G: | 414 case NetworkChangeNotifier::CONNECTION_3G: |
| 402 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.3G", | 415 UMA_HISTOGRAM_COUNTS( |
| 403 peak_kbps_since_last_connection_change_); | 416 "NQE.PeakKbps.3G", |
| 417 peak_network_quality_.downstream_throughput_kbps()); | |
| 404 break; | 418 break; |
| 405 case NetworkChangeNotifier::CONNECTION_4G: | 419 case NetworkChangeNotifier::CONNECTION_4G: |
| 406 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.4G", | 420 UMA_HISTOGRAM_COUNTS( |
| 407 peak_kbps_since_last_connection_change_); | 421 "NQE.PeakKbps.4G", |
| 422 peak_network_quality_.downstream_throughput_kbps()); | |
| 408 break; | 423 break; |
| 409 case NetworkChangeNotifier::CONNECTION_NONE: | 424 case NetworkChangeNotifier::CONNECTION_NONE: |
| 410 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", | 425 UMA_HISTOGRAM_COUNTS( |
| 411 peak_kbps_since_last_connection_change_); | 426 "NQE.PeakKbps.None", |
| 427 peak_network_quality_.downstream_throughput_kbps()); | |
| 412 break; | 428 break; |
| 413 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | 429 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| 414 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", | 430 UMA_HISTOGRAM_COUNTS( |
| 415 peak_kbps_since_last_connection_change_); | 431 "NQE.PeakKbps.Bluetooth", |
| 432 peak_network_quality_.downstream_throughput_kbps()); | |
| 416 break; | 433 break; |
| 417 default: | 434 default: |
| 418 NOTREACHED(); | 435 NOTREACHED() << "Unexpected connection type = " |
| 436 << current_network_id_.type; | |
| 419 break; | 437 break; |
| 420 } | 438 } |
| 421 } | 439 } |
| 422 | 440 |
| 423 NetworkQuality network_quality; | 441 NetworkQuality network_quality; |
| 424 if (GetEstimate(&network_quality)) { | 442 if (GetEstimate(&network_quality)) { |
| 425 // Add the 50th percentile value. | 443 // Add the 50th percentile value. |
| 426 base::HistogramBase* rtt_percentile = | 444 base::HistogramBase* rtt_percentile = |
| 427 GetHistogram("RTT.Percentile50.", current_connection_type_, | 445 GetHistogram("RTT.Percentile50.", current_network_id_.type, |
| 428 10 * 1000); // 10 seconds | 446 10 * 1000); // 10 seconds |
| 429 rtt_percentile->Add(network_quality.rtt().InMilliseconds()); | 447 rtt_percentile->Add(network_quality.rtt().InMilliseconds()); |
| 430 | 448 |
| 431 // Add the remaining percentile values. | 449 // Add the remaining percentile values. |
| 432 static const int kPercentiles[] = {0, 10, 90, 100}; | 450 static const int kPercentiles[] = {0, 10, 90, 100}; |
| 433 for (size_t i = 0; i < arraysize(kPercentiles); ++i) { | 451 for (size_t i = 0; i < arraysize(kPercentiles); ++i) { |
| 434 network_quality = GetEstimate(kPercentiles[i]); | 452 network_quality = GetEstimate(kPercentiles[i]); |
| 435 | 453 |
| 436 char percentile_stringified[20]; | 454 char percentile_stringified[20]; |
| 437 base::strings::SafeSPrintf(percentile_stringified, "%d", kPercentiles[i]); | 455 base::strings::SafeSPrintf(percentile_stringified, "%d", kPercentiles[i]); |
| 438 | 456 |
| 439 rtt_percentile = GetHistogram( | 457 rtt_percentile = GetHistogram( |
| 440 "RTT.Percentile" + std::string(percentile_stringified) + ".", | 458 "RTT.Percentile" + std::string(percentile_stringified) + ".", |
| 441 current_connection_type_, 10 * 1000); // 10 seconds | 459 current_network_id_.type, 10 * 1000); // 10 seconds |
| 442 rtt_percentile->Add(network_quality.rtt().InMilliseconds()); | 460 rtt_percentile->Add(network_quality.rtt().InMilliseconds()); |
| 443 } | 461 } |
| 444 } | 462 } |
| 445 | 463 |
| 464 // Write the estimates of the previous network to the cache. | |
| 465 CacheNetworkQualityEstimate(); | |
| 466 | |
| 467 // Clear the local state. | |
| 446 last_connection_change_ = base::TimeTicks::Now(); | 468 last_connection_change_ = base::TimeTicks::Now(); |
| 447 peak_kbps_since_last_connection_change_ = NetworkQuality::kInvalidThroughput; | 469 peak_network_quality_ = NetworkQuality(); |
| 448 fastest_rtt_since_last_connection_change_ = NetworkQuality::InvalidRTT(); | |
| 449 kbps_observations_.Clear(); | 470 kbps_observations_.Clear(); |
| 450 rtt_msec_observations_.Clear(); | 471 rtt_msec_observations_.Clear(); |
| 451 current_connection_type_ = type; | 472 current_network_id_ = GetCurrentNetworkID(); |
| 452 | 473 |
| 453 AddDefaultEstimates(); | 474 // Read any cached estimates for the new network. If cached estimates are |
| 475 // unavailable, add the default estimates. | |
| 476 if (!ReadCachedNetworkQualityEstimate()) | |
| 477 AddDefaultEstimates(); | |
| 454 estimated_median_network_quality_ = NetworkQuality(); | 478 estimated_median_network_quality_ = NetworkQuality(); |
| 455 } | 479 } |
| 456 | 480 |
| 457 NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const { | 481 NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const { |
| 458 DCHECK(thread_checker_.CalledOnValidThread()); | 482 DCHECK(thread_checker_.CalledOnValidThread()); |
| 459 | 483 |
| 460 return NetworkQuality(fastest_rtt_since_last_connection_change_, | 484 return peak_network_quality_; |
| 461 peak_kbps_since_last_connection_change_); | |
| 462 } | 485 } |
| 463 | 486 |
| 464 bool NetworkQualityEstimator::GetEstimate(NetworkQuality* median) const { | 487 bool NetworkQualityEstimator::GetEstimate(NetworkQuality* median) const { |
| 465 if (kbps_observations_.Size() == 0 || rtt_msec_observations_.Size() == 0) { | 488 if (kbps_observations_.Size() == 0 || rtt_msec_observations_.Size() == 0) { |
| 466 *median = NetworkQuality(); | 489 *median = NetworkQuality(); |
| 467 return false; | 490 return false; |
| 468 } | 491 } |
| 469 *median = GetEstimate(50); | 492 *median = GetEstimate(50); |
| 470 return true; | 493 return true; |
| 471 } | 494 } |
| 472 | 495 |
| 473 size_t NetworkQualityEstimator::GetMaximumObservationBufferSizeForTests() | |
| 474 const { | |
| 475 return kMaximumObservationsBufferSize; | |
| 476 } | |
| 477 | |
| 478 bool NetworkQualityEstimator::VerifyBufferSizeForTests( | |
| 479 size_t expected_size) const { | |
| 480 return kbps_observations_.Size() == expected_size && | |
| 481 rtt_msec_observations_.Size() == expected_size; | |
| 482 } | |
| 483 | |
| 484 NetworkQualityEstimator::Observation::Observation(int32_t value, | 496 NetworkQualityEstimator::Observation::Observation(int32_t value, |
| 485 base::TimeTicks timestamp) | 497 base::TimeTicks timestamp) |
| 486 : value(value), timestamp(timestamp) { | 498 : value(value), timestamp(timestamp) { |
| 487 DCHECK_GE(value, 0); | 499 DCHECK_GE(value, 0); |
| 488 DCHECK(!timestamp.is_null()); | 500 DCHECK(!timestamp.is_null()); |
| 489 } | 501 } |
| 490 | 502 |
| 491 NetworkQualityEstimator::Observation::~Observation() { | 503 NetworkQualityEstimator::Observation::~Observation() { |
| 492 } | 504 } |
| 493 | 505 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 } | 601 } |
| 590 | 602 |
| 591 // Computation may reach here due to floating point errors. This may happen | 603 // Computation may reach here due to floating point errors. This may happen |
| 592 // if |percentile| was 100 (or close to 100), and |desired_weight| was | 604 // if |percentile| was 100 (or close to 100), and |desired_weight| was |
| 593 // slightly larger than |total_weight| (due to floating point errors). | 605 // slightly larger than |total_weight| (due to floating point errors). |
| 594 // In this case, we return the highest |value| among all observations. | 606 // In this case, we return the highest |value| among all observations. |
| 595 // This is same as value of the last observation in the sorted vector. | 607 // This is same as value of the last observation in the sorted vector. |
| 596 return weighted_observations.at(weighted_observations.size() - 1).value; | 608 return weighted_observations.at(weighted_observations.size() - 1).value; |
| 597 } | 609 } |
| 598 | 610 |
| 611 NetworkQualityEstimator::NetworkID | |
| 612 NetworkQualityEstimator::GetCurrentNetworkID() const { | |
| 613 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 614 | |
| 615 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class | |
| 616 // that overrides this method on the Android platform. | |
| 617 | |
| 618 // It is possible that the connection type changed between when | |
| 619 // GetConnectionType() was called and when the API to determine the | |
| 620 // network name was called. Check if that happened and retry until the | |
| 621 // connection type stabilizes. This is an imperfect solution but should | |
| 622 // capture majority of cases, and should not significantly affect estimates | |
| 623 // (that are approximate to begin with). | |
| 624 while (true) { | |
| 625 NetworkQualityEstimator::NetworkID network_id( | |
| 626 NetworkChangeNotifier::GetConnectionType(), std::string()); | |
| 627 | |
| 628 switch (network_id.type) { | |
| 629 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN: | |
| 630 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE: | |
| 631 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH: | |
| 632 break; | |
| 633 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET: | |
| 634 network_id.id = "Ethernet"; | |
| 635 break; | |
| 636 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI: | |
| 637 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) | |
| 638 network_id.id = GetWifiSSID(); | |
| 639 break; | |
| 640 #else | |
| 641 break; | |
| 642 #endif | |
|
pauljensen
2015/07/14 11:59:03
#if ...
...
break;
#else
break;
#endif
->
tbansal1
2015/07/14 19:51:48
Done.
| |
| 643 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G: | |
| 644 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G: | |
| 645 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G: | |
| 646 #if defined(OS_ANDROID) | |
| 647 network_id.id = android::GetTelephonyNetworkOperator(); | |
| 648 break; | |
| 649 #else | |
| 650 break; | |
| 651 #endif | |
|
pauljensen
2015/07/14 11:59:02
ditto
tbansal1
2015/07/14 19:51:47
Done.
| |
| 652 default: | |
| 653 NOTREACHED() << "Unexpected connection type = " << network_id.type; | |
| 654 } | |
|
pauljensen
2015/07/14 11:59:03
break;
tbansal1
2015/07/14 19:51:48
Done.
| |
| 655 | |
| 656 if (network_id.type == NetworkChangeNotifier::GetConnectionType()) | |
| 657 return network_id; | |
| 658 } | |
| 659 NOTREACHED(); | |
| 660 } | |
| 661 | |
| 662 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() { | |
| 663 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 664 | |
| 665 // If the network name is unavailable, caching should not be performed. | |
| 666 if (current_network_id_.id.empty()) | |
| 667 return false; | |
| 668 | |
| 669 CachedNetworkQualities::iterator it = | |
| 670 cached_network_qualities_.find(current_network_id_); | |
| 671 | |
| 672 if (it == cached_network_qualities_.end()) | |
| 673 return false; | |
| 674 | |
| 675 NetworkQuality network_quality( | |
| 676 it->second->network_quality().rtt(), | |
| 677 it->second->network_quality().downstream_throughput_kbps()); | |
| 678 | |
| 679 DCHECK_NE(NetworkQuality::InvalidRTT(), network_quality.rtt()); | |
| 680 DCHECK_NE(NetworkQuality::kInvalidThroughput, | |
| 681 network_quality.downstream_throughput_kbps()); | |
| 682 | |
| 683 kbps_observations_.AddObservation(Observation( | |
| 684 network_quality.downstream_throughput_kbps(), base::TimeTicks::Now())); | |
| 685 rtt_msec_observations_.AddObservation(Observation( | |
| 686 network_quality.rtt().InMilliseconds(), base::TimeTicks::Now())); | |
| 687 return true; | |
| 688 } | |
| 689 | |
| 690 void NetworkQualityEstimator::CacheNetworkQualityEstimate() { | |
| 691 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 692 DCHECK_LE(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize); | |
| 693 | |
| 694 // If the network name is unavailable, caching should not be performed. | |
| 695 if (current_network_id_.id.empty()) | |
| 696 return; | |
| 697 | |
| 698 NetworkQuality network_quality; | |
| 699 if (!GetEstimate(&network_quality)) | |
| 700 return; | |
| 701 | |
| 702 DCHECK_NE(NetworkQuality::InvalidRTT(), network_quality.rtt()); | |
| 703 DCHECK_NE(NetworkQuality::kInvalidThroughput, | |
| 704 network_quality.downstream_throughput_kbps()); | |
| 705 | |
| 706 if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) { | |
| 707 // Remove the oldest entry. | |
| 708 CachedNetworkQualities::iterator oldest_entry_iterator = | |
| 709 cached_network_qualities_.begin(); | |
| 710 | |
| 711 for (CachedNetworkQualities::iterator it = | |
| 712 cached_network_qualities_.begin(); | |
| 713 it != cached_network_qualities_.end(); ++it) { | |
| 714 if ((it->second)->OlderThan(*(oldest_entry_iterator->second.get()))) | |
| 715 oldest_entry_iterator = it; | |
| 716 } | |
| 717 cached_network_qualities_.erase(oldest_entry_iterator); | |
| 718 } | |
| 719 DCHECK_LT(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize); | |
| 720 | |
| 721 cached_network_qualities_[current_network_id_].reset( | |
| 722 new CachedNetworkQuality(network_quality)); | |
| 723 DCHECK_LE(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize); | |
| 724 } | |
| 725 | |
| 726 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality( | |
| 727 const NetworkQuality& network_quality) | |
| 728 : last_update_time_(base::TimeTicks::Now()), | |
| 729 network_quality_(network_quality) { | |
| 730 } | |
| 731 | |
| 732 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() { | |
| 733 } | |
| 734 | |
| 735 bool NetworkQualityEstimator::CachedNetworkQuality::OlderThan( | |
| 736 const CachedNetworkQuality& cached_network_quality) const { | |
| 737 return last_update_time_ < cached_network_quality.last_update_time_; | |
| 738 } | |
| 739 | |
| 599 } // namespace net | 740 } // namespace net |
| OLD | NEW |