Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(318)

Side by Side Diff: net/base/network_quality_estimator.cc

Issue 1144163008: Add in-memory caching of network quality estimates across network changes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed Paul's comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/network_quality_estimator.h ('k') | net/base/network_quality_estimator_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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;
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::ConnectionType::CONNECTION_UNKNOWN,
47 std::string())),
38 fastest_rtt_since_last_connection_change_(base::TimeDelta::Max()), 48 fastest_rtt_since_last_connection_change_(base::TimeDelta::Max()),
39 peak_kbps_since_last_connection_change_(0) { 49 peak_kbps_since_last_connection_change_(0) {
40 static_assert(kMinRequestDurationMicroseconds > 0, 50 static_assert(kMinRequestDurationMicroseconds > 0,
41 "Minimum request duration must be > 0"); 51 "Minimum request duration must be > 0");
52 static_assert(kMaximumNetworkQualityCacheSize > 0,
53 "Size of the network quality cache must be > 0");
54
55 // This limit should not be increased unless the logic for removing the
56 // oldest cache entry is rewritten to use a doubly-linked-list LRU queue.
57 static_assert(kMaximumNetworkQualityCacheSize <= 10,
58 "Size of the network quality cache must <= 10");
42 NetworkChangeNotifier::AddConnectionTypeObserver(this); 59 NetworkChangeNotifier::AddConnectionTypeObserver(this);
60 current_network_id_ = GetCurrentNetworkID();
43 } 61 }
44 62
45 NetworkQualityEstimator::~NetworkQualityEstimator() { 63 NetworkQualityEstimator::~NetworkQualityEstimator() {
46 DCHECK(thread_checker_.CalledOnValidThread()); 64 DCHECK(thread_checker_.CalledOnValidThread());
47 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); 65 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
48 } 66 }
49 67
50 void NetworkQualityEstimator::NotifyDataReceived( 68 void NetworkQualityEstimator::NotifyDataReceived(
51 const URLRequest& request, 69 const URLRequest& request,
52 int64_t cumulative_prefilter_bytes_read, 70 int64_t cumulative_prefilter_bytes_read,
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 147
130 kbps_observations_.AddObservation(Observation(kbps, now)); 148 kbps_observations_.AddObservation(Observation(kbps, now));
131 } 149 }
132 } 150 }
133 } 151 }
134 152
135 void NetworkQualityEstimator::OnConnectionTypeChanged( 153 void NetworkQualityEstimator::OnConnectionTypeChanged(
136 NetworkChangeNotifier::ConnectionType type) { 154 NetworkChangeNotifier::ConnectionType type) {
137 DCHECK(thread_checker_.CalledOnValidThread()); 155 DCHECK(thread_checker_.CalledOnValidThread());
138 if (fastest_rtt_since_last_connection_change_ != base::TimeDelta::Max()) { 156 if (fastest_rtt_since_last_connection_change_ != base::TimeDelta::Max()) {
139 switch (current_connection_type_) { 157 switch (current_network_id_.type) {
140 case NetworkChangeNotifier::CONNECTION_UNKNOWN: 158 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
141 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", 159 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown",
142 fastest_rtt_since_last_connection_change_); 160 fastest_rtt_since_last_connection_change_);
143 break; 161 break;
144 case NetworkChangeNotifier::CONNECTION_ETHERNET: 162 case NetworkChangeNotifier::CONNECTION_ETHERNET:
145 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", 163 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet",
146 fastest_rtt_since_last_connection_change_); 164 fastest_rtt_since_last_connection_change_);
147 break; 165 break;
148 case NetworkChangeNotifier::CONNECTION_WIFI: 166 case NetworkChangeNotifier::CONNECTION_WIFI:
149 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", 167 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi",
(...skipping 13 matching lines...) Expand all
163 break; 181 break;
164 case NetworkChangeNotifier::CONNECTION_NONE: 182 case NetworkChangeNotifier::CONNECTION_NONE:
165 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", 183 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None",
166 fastest_rtt_since_last_connection_change_); 184 fastest_rtt_since_last_connection_change_);
167 break; 185 break;
168 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 186 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
169 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", 187 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth",
170 fastest_rtt_since_last_connection_change_); 188 fastest_rtt_since_last_connection_change_);
171 break; 189 break;
172 default: 190 default:
173 NOTREACHED(); 191 NOTREACHED() << "Unexpected connection type = "
192 << current_network_id_.type;
174 break; 193 break;
175 } 194 }
176 } 195 }
177 196
178 if (peak_kbps_since_last_connection_change_) { 197 if (peak_kbps_since_last_connection_change_) {
179 switch (current_connection_type_) { 198 switch (current_network_id_.type) {
180 case NetworkChangeNotifier::CONNECTION_UNKNOWN: 199 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
181 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", 200 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown",
182 peak_kbps_since_last_connection_change_); 201 peak_kbps_since_last_connection_change_);
183 break; 202 break;
184 case NetworkChangeNotifier::CONNECTION_ETHERNET: 203 case NetworkChangeNotifier::CONNECTION_ETHERNET:
185 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet", 204 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet",
186 peak_kbps_since_last_connection_change_); 205 peak_kbps_since_last_connection_change_);
187 break; 206 break;
188 case NetworkChangeNotifier::CONNECTION_WIFI: 207 case NetworkChangeNotifier::CONNECTION_WIFI:
189 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi", 208 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi",
(...skipping 13 matching lines...) Expand all
203 break; 222 break;
204 case NetworkChangeNotifier::CONNECTION_NONE: 223 case NetworkChangeNotifier::CONNECTION_NONE:
205 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", 224 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None",
206 peak_kbps_since_last_connection_change_); 225 peak_kbps_since_last_connection_change_);
207 break; 226 break;
208 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 227 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
209 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", 228 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth",
210 peak_kbps_since_last_connection_change_); 229 peak_kbps_since_last_connection_change_);
211 break; 230 break;
212 default: 231 default:
213 NOTREACHED(); 232 NOTREACHED() << "Unexpected connection type = "
233 << current_network_id_.type;
214 break; 234 break;
215 } 235 }
216 } 236 }
217 237
238 // Write the estimates of the previous network to the cache.
239 CacheNetworkQualityEstimate();
240
241 // Clear the local state.
218 last_connection_change_ = base::TimeTicks::Now(); 242 last_connection_change_ = base::TimeTicks::Now();
219 peak_kbps_since_last_connection_change_ = 0; 243 peak_kbps_since_last_connection_change_ = 0;
220 fastest_rtt_since_last_connection_change_ = base::TimeDelta::Max(); 244 fastest_rtt_since_last_connection_change_ = base::TimeDelta::Max();
221 kbps_observations_.Clear(); 245 kbps_observations_.Clear();
222 rtt_msec_observations_.Clear(); 246 rtt_msec_observations_.Clear();
223 current_connection_type_ = type; 247
248 // Update the current network ID.
249 current_network_id_ = GetCurrentNetworkID();
250
251 // Read any cached estimates for the new network.
252 ReadCachedNetworkQualityEstimate();
253 }
254
255 size_t NetworkQualityEstimator::GetNetworkQualityCacheSizeForTests() const {
256 DCHECK(thread_checker_.CalledOnValidThread());
257 return cached_network_qualities_.size();
224 } 258 }
225 259
226 NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const { 260 NetworkQuality NetworkQualityEstimator::GetPeakEstimate() const {
227 DCHECK(thread_checker_.CalledOnValidThread()); 261 DCHECK(thread_checker_.CalledOnValidThread());
228 262
229 return NetworkQuality(fastest_rtt_since_last_connection_change_, 263 return NetworkQuality(fastest_rtt_since_last_connection_change_,
230 peak_kbps_since_last_connection_change_); 264 peak_kbps_since_last_connection_change_);
231 } 265 }
232 266
233 size_t NetworkQualityEstimator::GetMaximumObservationBufferSizeForTests() 267 size_t NetworkQualityEstimator::GetMaximumObservationBufferSizeForTests()
234 const { 268 const {
269 DCHECK(thread_checker_.CalledOnValidThread());
235 return kMaximumObservationsBufferSize; 270 return kMaximumObservationsBufferSize;
236 } 271 }
237 272
238 bool NetworkQualityEstimator::VerifyBufferSizeForTests( 273 size_t NetworkQualityEstimator::GetKbpsObservationBufferSizeForTests() const {
239 size_t expected_size) const { 274 DCHECK(thread_checker_.CalledOnValidThread());
240 return kbps_observations_.Size() == expected_size && 275 return kbps_observations_.Size();
241 rtt_msec_observations_.Size() == expected_size; 276 }
277
278 size_t NetworkQualityEstimator::GetRTTObservationBufferSizeForTests() const {
279 DCHECK(thread_checker_.CalledOnValidThread());
280 return rtt_msec_observations_.Size();
242 } 281 }
243 282
244 NetworkQualityEstimator::Observation::Observation(int32_t value, 283 NetworkQualityEstimator::Observation::Observation(int32_t value,
245 base::TimeTicks timestamp) 284 base::TimeTicks timestamp)
246 : value(value), timestamp(timestamp) { 285 : value(value), timestamp(timestamp) {
247 DCHECK_GE(value, 0); 286 DCHECK_GE(value, 0);
248 DCHECK(!timestamp.is_null()); 287 DCHECK(!timestamp.is_null());
249 } 288 }
250 289
251 NetworkQualityEstimator::Observation::~Observation() { 290 NetworkQualityEstimator::Observation::~Observation() {
(...skipping 20 matching lines...) Expand all
272 311
273 size_t NetworkQualityEstimator::ObservationBuffer::Size() const { 312 size_t NetworkQualityEstimator::ObservationBuffer::Size() const {
274 return observations_.size(); 313 return observations_.size();
275 } 314 }
276 315
277 void NetworkQualityEstimator::ObservationBuffer::Clear() { 316 void NetworkQualityEstimator::ObservationBuffer::Clear() {
278 observations_.clear(); 317 observations_.clear();
279 DCHECK(observations_.empty()); 318 DCHECK(observations_.empty());
280 } 319 }
281 320
321 NetworkQualityEstimator::NetworkID
322 NetworkQualityEstimator::GetCurrentNetworkID() const {
323 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class
324 // that overrides this method on the Android platform.
325
326 // It is possible that the connection type changed between when
327 // GetCurrentConnectionType() was called and when the API to determine the
pauljensen 2015/06/19 03:10:07 GetCurrent->Get
tbansal1 2015/06/19 23:34:40 Thanks for the catch. Done.
328 // network name was called. Check if that happened and retry until the
329 // connection type stabilizes. This is an imperfect solution but should
330 // capture majority of cases, and should not significantly affect estimates
331 // (that are approximate to begin with).
332 while (true) {
333 NetworkQualityEstimator::NetworkID network_id(
334 NetworkChangeNotifier::GetConnectionType(), std::string());
335
336 DCHECK(thread_checker_.CalledOnValidThread());
337
338 switch (network_id.type) {
339 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
340 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
341 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
342 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
343 break;
344 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
345 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
346 network_id.id = GetWifiSSID();
347 break;
348 #else
349 break;
350 #endif
351 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
352 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
353 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
354 #if defined(OS_ANDROID)
355 network_id.id = android::GetTelephonyNetworkOperator();
356 break;
357 #else
358 break;
359 #endif
360 default:
361 NOTREACHED() << "Unexpected connection type = " << network_id.type;
362 }
363
364 if (network_id.type == NetworkChangeNotifier::GetConnectionType())
365 return network_id;
366 }
367 NOTREACHED();
368 }
369
370 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
371 DCHECK(thread_checker_.CalledOnValidThread());
372
373 // If the network name is unavailable, caching should not be performed.
374 if (current_network_id_.id.empty())
375 return false;
376
377 CachedNetworkQualities::iterator it =
378 cached_network_qualities_.find(current_network_id_);
379 if (it != cached_network_qualities_.end()) {
380 // TOOD(tbansal): Populate these values back into the median computing
381 // algorithm.
382 // Add UMA to record how frequently matches happen.
383 // Ensure that the estimates read are non-zero before populating them into
384 // the median computing algorithm.
385 peak_kbps_since_last_connection_change_ =
386 it->second->network_quality().downstream_throughput_kbps();
387 fastest_rtt_since_last_connection_change_ =
388 it->second->network_quality().rtt();
389 return true;
390 }
391 return false;
392 }
393
394 void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
395 DCHECK(thread_checker_.CalledOnValidThread());
396 DCHECK_LE(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize);
397
398 // If the network name is unavailable, caching should not be performed.
399 if (current_network_id_.id.empty())
400 return;
401
402 // TODO(tbansal): The following variables should be initialized using the
403 // median values reported by the NetworkQualityEstimator.
404 int median_kbps = peak_kbps_since_last_connection_change_;
405 base::TimeDelta median_rtt = fastest_rtt_since_last_connection_change_;
406
407 // If this network is already in the cache, overwrite that entry.
408 CachedNetworkQualities::iterator it =
409 cached_network_qualities_.find(current_network_id_);
410 if (it != cached_network_qualities_.end()) {
411 (it->second)->UpdateNetworkQuality(median_kbps, median_rtt);
412 return;
413 }
414
415 if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) {
416 // Remove the oldest entry.
417 CachedNetworkQualities::iterator oldest_entry_iterator =
418 cached_network_qualities_.begin();
419
420 for (CachedNetworkQualities::iterator it =
421 cached_network_qualities_.begin();
422 it != cached_network_qualities_.end(); ++it) {
423 if ((it->second)->OlderThan(*(oldest_entry_iterator->second.get())))
424 oldest_entry_iterator = it;
425 }
426 cached_network_qualities_.erase(oldest_entry_iterator);
427 }
428
429 DCHECK_LT(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize);
430 cached_network_qualities_.insert(std::make_pair(
431 current_network_id_, make_scoped_ptr(new CachedNetworkQuality(
432 NetworkQuality(median_rtt, median_kbps)))));
433 DCHECK_LE(cached_network_qualities_.size(), kMaximumNetworkQualityCacheSize);
434 }
435
436 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
437 const NetworkQuality& network_quality)
438 : last_update_time_(base::TimeTicks::Now()),
439 network_quality_(network_quality) {
440 }
441
442 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() {
443 }
444
445 bool NetworkQualityEstimator::CachedNetworkQuality::OlderThan(
446 const CachedNetworkQuality& cached_network_quality) const {
447 return last_update_time_ < cached_network_quality.last_update_time_;
448 }
449
450 void NetworkQualityEstimator::CachedNetworkQuality::UpdateNetworkQuality(
451 int32_t median_kbps,
452 const base::TimeDelta& median_rtt) {
453 DCHECK_GE(median_kbps, 0);
454 DCHECK_GE(median_rtt, base::TimeDelta());
455 last_update_time_ = base::TimeTicks::Now();
456
457 network_quality_ = NetworkQuality(median_rtt, median_kbps);
458 }
459
282 } // namespace net 460 } // namespace net
OLDNEW
« no previous file with comments | « net/base/network_quality_estimator.h ('k') | net/base/network_quality_estimator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698