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

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

Powered by Google App Engine
This is Rietveld 408576698