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

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 and style fixes 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 <string>
8
9 #include "base/logging.h" 7 #include "base/logging.h"
10 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "build/build_config.h"
11 #include "net/base/net_util.h" 10 #include "net/base/net_util.h"
12 #include "net/base/network_quality.h" 11 #include "net/base/network_quality.h"
13 #include "net/url_request/url_request.h" 12 #include "net/url_request/url_request.h"
14 #include "url/gurl.h" 13 #include "url/gurl.h"
15 14
15 #if defined(OS_ANDROID)
16 #include "net/android/network_library.h"
17 #endif // OS_ANDROID
18
19 namespace {
20
21 // Maximum size of the cache that holds network quality estimates.
22 // Smaller size may reduce the cache hit rate due to frequent evictions.
23 // Larger size may affect performance.
24 const uint32_t kMaximumNetworkQualityCacheSize = 10;
25
26 } // namespace
27
16 namespace net { 28 namespace net {
17 29
18 NetworkQualityEstimator::NetworkQualityEstimator() 30 NetworkQualityEstimator::NetworkQualityEstimator()
19 : NetworkQualityEstimator(false) { 31 : NetworkQualityEstimator(false) {
20 } 32 }
21 33
22 NetworkQualityEstimator::NetworkQualityEstimator( 34 NetworkQualityEstimator::NetworkQualityEstimator(
23 bool allow_local_host_requests_for_tests) 35 bool allow_local_host_requests_for_tests)
24 : allow_localhost_requests_(allow_local_host_requests_for_tests), 36 : allow_localhost_requests_(allow_local_host_requests_for_tests),
25 last_connection_change_(base::TimeTicks::Now()), 37 last_connection_change_(base::TimeTicks::Now()),
26 current_connection_type_(NetworkChangeNotifier::GetConnectionType()), 38 current_connection_type_(NetworkChangeNotifier::GetConnectionType()),
27 bytes_read_since_last_connection_change_(false), 39 bytes_read_since_last_connection_change_(false),
28 peak_kbps_since_last_connection_change_(0) { 40 peak_kbps_since_last_connection_change_(0) {
29 static_assert(kMinRequestDurationMicroseconds > 0, 41 static_assert(kMinRequestDurationMicroseconds > 0,
30 "Minimum request duration must be > 0"); 42 "Minimum request duration must be > 0");
43 static_assert(kMaximumNetworkQualityCacheSize > 0,
44 "Size of the network quality cache must be > 0");
31 NetworkChangeNotifier::AddConnectionTypeObserver(this); 45 NetworkChangeNotifier::AddConnectionTypeObserver(this);
46 UpdateCurrentNetworkName();
32 } 47 }
33 48
34 NetworkQualityEstimator::~NetworkQualityEstimator() { 49 NetworkQualityEstimator::~NetworkQualityEstimator() {
35 DCHECK(thread_checker_.CalledOnValidThread()); 50 DCHECK(thread_checker_.CalledOnValidThread());
36 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); 51 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
37 } 52 }
38 53
39 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request, 54 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request,
40 int64_t prefilter_bytes_read) { 55 int64_t prefilter_bytes_read) {
41 DCHECK(thread_checker_.CalledOnValidThread()); 56 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 break; 119 break;
105 case NetworkChangeNotifier::CONNECTION_NONE: 120 case NetworkChangeNotifier::CONNECTION_NONE:
106 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", 121 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None",
107 fastest_RTT_since_last_connection_change_); 122 fastest_RTT_since_last_connection_change_);
108 break; 123 break;
109 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 124 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
110 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", 125 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth",
111 fastest_RTT_since_last_connection_change_); 126 fastest_RTT_since_last_connection_change_);
112 break; 127 break;
113 default: 128 default:
114 NOTREACHED(); 129 NOTREACHED() << "Unexpected connection type = "
130 << current_connection_type_;
115 break; 131 break;
116 } 132 }
117 } 133 }
118 134
119 if (peak_kbps_since_last_connection_change_) { 135 if (peak_kbps_since_last_connection_change_) {
120 switch (current_connection_type_) { 136 switch (current_connection_type_) {
121 case NetworkChangeNotifier::CONNECTION_UNKNOWN: 137 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
122 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", 138 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown",
123 peak_kbps_since_last_connection_change_); 139 peak_kbps_since_last_connection_change_);
124 break; 140 break;
(...skipping 19 matching lines...) Expand all
144 break; 160 break;
145 case NetworkChangeNotifier::CONNECTION_NONE: 161 case NetworkChangeNotifier::CONNECTION_NONE:
146 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", 162 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None",
147 peak_kbps_since_last_connection_change_); 163 peak_kbps_since_last_connection_change_);
148 break; 164 break;
149 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 165 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
150 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", 166 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth",
151 peak_kbps_since_last_connection_change_); 167 peak_kbps_since_last_connection_change_);
152 break; 168 break;
153 default: 169 default:
154 NOTREACHED(); 170 NOTREACHED() << "Unexpected connection type = "
171 << current_connection_type_;
155 break; 172 break;
156 } 173 }
157 } 174 }
158 175
176 // Write the estimates of the previous network to the cache.
177 CacheNetworkQualityEstimate();
178
159 last_connection_change_ = base::TimeTicks::Now(); 179 last_connection_change_ = base::TimeTicks::Now();
160 bytes_read_since_last_connection_change_ = false; 180 bytes_read_since_last_connection_change_ = false;
161 peak_kbps_since_last_connection_change_ = 0; 181 peak_kbps_since_last_connection_change_ = 0;
162 current_connection_type_ = type; 182 current_connection_type_ = type;
183 UpdateCurrentNetworkName();
184
185 // Read any cached estimates for the new network.
186 ReadCachedNetworkQualityEstimate();
187 }
188
189 size_t NetworkQualityEstimator::GetCacheSizeForTests() const {
190 return cached_network_quality_.size();
191 }
192
193 void NetworkQualityEstimator::SetCurrentNetworkNameForTests(
194 const std::string& network_name) {
195 current_network_name_ = network_name;
163 } 196 }
164 197
165 NetworkQuality NetworkQualityEstimator::GetEstimate() const { 198 NetworkQuality NetworkQualityEstimator::GetEstimate() const {
166 DCHECK(thread_checker_.CalledOnValidThread()); 199 DCHECK(thread_checker_.CalledOnValidThread());
167 200
168 if (!bytes_read_since_last_connection_change_) { 201 if (!bytes_read_since_last_connection_change_) {
169 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0, 202 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0,
170 peak_kbps_since_last_connection_change_, 0); 203 peak_kbps_since_last_connection_change_, 0);
171 } 204 }
172 if (!peak_kbps_since_last_connection_change_) { 205 if (!peak_kbps_since_last_connection_change_) {
173 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, 206 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1,
174 peak_kbps_since_last_connection_change_, 0); 207 peak_kbps_since_last_connection_change_, 0);
175 } 208 }
176 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, 209 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1,
177 peak_kbps_since_last_connection_change_, 0.1); 210 peak_kbps_since_last_connection_change_, 0.1);
178 } 211 }
179 212
213 void NetworkQualityEstimator::UpdateCurrentNetworkName() {
214 DCHECK(thread_checker_.CalledOnValidThread());
215
216 current_network_name_ = std::string();
217 switch (current_connection_type_) {
218 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
219 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
220 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
221 return;
222 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
223 current_network_name_ = "ethernet";
224 return;
225 #if defined(OS_ANDROID)
bengr 2015/06/05 20:34:31 Could we have a NetworkQualityEstimatorAndroid tha
tbansal1 2015/06/06 01:03:14 Done. Added TODO
226 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
mmenke 2015/06/05 20:37:21 Erm...WIFI only on Android?
tbansal1 2015/06/06 01:03:14 Added Linux and ChromeOS. GetWiFiSSID() is only im
227 current_network_name_ = GetWifiSSID();
228 return;
229 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
230 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
231 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
232 current_network_name_ = android::GetTelephonyNetworkOperator();
233 return;
234 #endif // OS_ANDROID
mmenke 2015/06/05 20:37:20 Can't ChromeOS have cell connections? What about
tbansal1 2015/06/06 01:03:14 AFAIK, GetTelephonyNetworkOperator() would compile
mmenke 2015/06/08 20:34:19 There's not, but the old code defaulted to NOTREAC
235 default:
236 #if defined(OS_ANDROID)
237 NOTREACHED() << "Unexpected connection type = "
238 << current_connection_type_;
239 #endif // OS_ANDROID
240 return;
241 }
242 }
243
244 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
245 DCHECK(thread_checker_.CalledOnValidThread());
246
247 for (const auto& network_quality : cached_network_quality_) {
248 if (!network_quality->MatchesNetwork(current_connection_type_,
249 current_network_name_)) {
250 continue;
251 }
252
253 // TOOD(tbansal): Populate these values back into the median computing
254 // algorithm.
255 // Add UMA to record how frequently match happens.
256 // int64 median_kbps = network_quality.median_kbps;
257 // int64 median_rtt_msec = network_quality.median_rtt_milliseconds;
258 // Ensure that the estimates read are non-zero before populating them into
259 // the median computing algorithm.
260 return true;
261 }
262
263 return false;
264 }
265
266 void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
267 DCHECK(thread_checker_.CalledOnValidThread());
268
269 // TODO(tbansal): Following variables should be initialized using the median
270 /// values reported by NetworkQualityEstimator.
271 int median_kbps = 0;
272 base::TimeDelta median_rtt;
273
274 // If this network is already in the cache, overwrite that entry.
275 for (auto& network_quality : cached_network_quality_) {
276 if (!network_quality->MatchesNetwork(current_connection_type_,
277 current_network_name_)) {
278 continue;
279 }
280
281 network_quality->UpdateNetworkQuality(median_kbps, median_rtt);
282 return;
283 }
284
285 if (cached_network_quality_.size() < kMaximumNetworkQualityCacheSize) {
286 cached_network_quality_.push_back(new CachedNetworkQuality(
287 current_connection_type_, current_network_name_, median_kbps,
288 median_rtt));
289 return;
290 }
291
292 DCHECK_EQ(kMaximumNetworkQualityCacheSize, cached_network_quality_.size());
293
294 // Overwrite the oldest entry.
295 ScopedVector<CachedNetworkQuality>::iterator oldest_entry_iterator =
296 cached_network_quality_.begin();
297
298 for (ScopedVector<CachedNetworkQuality>::iterator iterator =
299 cached_network_quality_.begin();
300 iterator != cached_network_quality_.end(); ++iterator) {
301 if ((*oldest_entry_iterator)->GetLastUpdated() >
302 (*iterator)->GetLastUpdated()) {
303 oldest_entry_iterator = iterator;
304 }
305 }
306
307 cached_network_quality_.erase(oldest_entry_iterator);
308 cached_network_quality_.push_back(
309 new CachedNetworkQuality(current_connection_type_, current_network_name_,
310 median_kbps, median_rtt));
311
312 DCHECK_EQ(kMaximumNetworkQualityCacheSize, cached_network_quality_.size());
313 }
314
315 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
316 NetworkChangeNotifier::ConnectionType connection_type,
317 const std::string& network_name,
318 uint64_t median_kbps,
319 const base::TimeDelta& median_rtt)
320 : median_kbps_(median_kbps),
321 median_rtt_(median_rtt),
322 last_updated_(base::TimeTicks::Now()),
323 connection_type_(connection_type),
324 network_name_(network_name) {
325 DCHECK_GE(median_kbps_, 0U);
326 DCHECK_GE(median_rtt_, base::TimeDelta());
327 }
328
329 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() {
330 }
331
332 void NetworkQualityEstimator::CachedNetworkQuality::UpdateNetworkQuality(
333 uint64_t median_kbps,
334 const base::TimeDelta& median_rtt) {
335 median_kbps_ = median_kbps;
336 median_rtt_ = median_rtt;
337 last_updated_ = base::TimeTicks::Now();
338 DCHECK_GE(median_kbps_, 0U);
339 DCHECK_GE(median_rtt_, base::TimeDelta());
340 }
341
342 bool NetworkQualityEstimator::CachedNetworkQuality::MatchesNetwork(
343 NetworkChangeNotifier::ConnectionType connection_type,
344 const std::string& network_name) const {
345 return connection_type == connection_type_ && network_name == network_name_;
346 }
347
348 base::TimeTicks NetworkQualityEstimator::CachedNetworkQuality::GetLastUpdated()
bengr 2015/06/05 20:34:31 Can this be inlined in the .h and renamed last_upd
tbansal1 2015/06/06 01:03:14 Done.
349 const {
350 return last_updated_;
351 }
352
180 } // namespace net 353 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698