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

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: rebased again 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
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;
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698