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

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> 7 #include "base/logging.h"
8
9 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "build/build_config.h"
10 #include "net/base/net_util.h" 10 #include "net/base/net_util.h"
11 #include "net/base/network_quality.h" 11 #include "net/base/network_quality.h"
12 #include "net/url_request/url_request.h" 12 #include "net/url_request/url_request.h"
13 #include "url/gurl.h" 13 #include "url/gurl.h"
14 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
15 namespace net { 28 namespace net {
16 29
17 NetworkQualityEstimator::NetworkQualityEstimator() 30 NetworkQualityEstimator::NetworkQualityEstimator()
18 : NetworkQualityEstimator(false) { 31 : NetworkQualityEstimator(false) {
19 } 32 }
20 33
21 NetworkQualityEstimator::NetworkQualityEstimator( 34 NetworkQualityEstimator::NetworkQualityEstimator(
22 bool allow_local_host_requests_for_tests) 35 bool allow_local_host_requests_for_tests)
23 : allow_localhost_requests_(allow_local_host_requests_for_tests), 36 : allow_localhost_requests_(allow_local_host_requests_for_tests),
24 last_connection_change_(base::TimeTicks::Now()), 37 last_connection_change_(base::TimeTicks::Now()),
25 current_connection_type_(NetworkChangeNotifier::GetConnectionType()), 38 current_connection_type_(NetworkChangeNotifier::GetConnectionType()),
26 bytes_read_since_last_connection_change_(false), 39 bytes_read_since_last_connection_change_(false),
27 peak_kbps_since_last_connection_change_(0) { 40 peak_kbps_since_last_connection_change_(0) {
28 static_assert(kMinRequestDurationMicroseconds > 0, 41 static_assert(kMinRequestDurationMicroseconds > 0,
29 "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");
30 NetworkChangeNotifier::AddConnectionTypeObserver(this); 45 NetworkChangeNotifier::AddConnectionTypeObserver(this);
46 UpdateCurrentNetworkName();
31 } 47 }
32 48
33 NetworkQualityEstimator::~NetworkQualityEstimator() { 49 NetworkQualityEstimator::~NetworkQualityEstimator() {
34 DCHECK(thread_checker_.CalledOnValidThread()); 50 DCHECK(thread_checker_.CalledOnValidThread());
35 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); 51 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
36 } 52 }
37 53
38 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request, 54 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request,
39 int64_t prefilter_bytes_read) { 55 int64_t prefilter_bytes_read) {
40 DCHECK(thread_checker_.CalledOnValidThread()); 56 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 break; 118 break;
103 case NetworkChangeNotifier::CONNECTION_NONE: 119 case NetworkChangeNotifier::CONNECTION_NONE:
104 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", 120 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None",
105 fastest_RTT_since_last_connection_change_); 121 fastest_RTT_since_last_connection_change_);
106 break; 122 break;
107 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 123 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
108 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", 124 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth",
109 fastest_RTT_since_last_connection_change_); 125 fastest_RTT_since_last_connection_change_);
110 break; 126 break;
111 default: 127 default:
112 NOTREACHED(); 128 NOTREACHED() << "Unexpected connection type = "
129 << current_connection_type_;
113 break; 130 break;
114 } 131 }
115 } 132 }
116 133
117 if (peak_kbps_since_last_connection_change_) { 134 if (peak_kbps_since_last_connection_change_) {
118 switch (current_connection_type_) { 135 switch (current_connection_type_) {
119 case NetworkChangeNotifier::CONNECTION_UNKNOWN: 136 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
120 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", 137 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown",
121 peak_kbps_since_last_connection_change_); 138 peak_kbps_since_last_connection_change_);
122 break; 139 break;
(...skipping 19 matching lines...) Expand all
142 break; 159 break;
143 case NetworkChangeNotifier::CONNECTION_NONE: 160 case NetworkChangeNotifier::CONNECTION_NONE:
144 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", 161 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None",
145 peak_kbps_since_last_connection_change_); 162 peak_kbps_since_last_connection_change_);
146 break; 163 break;
147 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 164 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
148 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", 165 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth",
149 peak_kbps_since_last_connection_change_); 166 peak_kbps_since_last_connection_change_);
150 break; 167 break;
151 default: 168 default:
152 NOTREACHED(); 169 NOTREACHED() << "Unexpected connection type = "
170 << current_connection_type_;
153 break; 171 break;
154 } 172 }
155 } 173 }
156 174
175 // Write the estimates of the previous network to the cache.
176 CacheNetworkQualityEstimate();
177
157 last_connection_change_ = base::TimeTicks::Now(); 178 last_connection_change_ = base::TimeTicks::Now();
158 bytes_read_since_last_connection_change_ = false; 179 bytes_read_since_last_connection_change_ = false;
159 peak_kbps_since_last_connection_change_ = 0; 180 peak_kbps_since_last_connection_change_ = 0;
160 current_connection_type_ = type; 181 current_connection_type_ = type;
182 UpdateCurrentNetworkName();
183
184 // Read any cached estimates for the new network.
185 ReadCachedNetworkQualityEstimate();
186 }
187
188 uint32_t NetworkQualityEstimator::GetCacheSizeForTests() const {
189 return cached_network_quality_.size();
190 }
191
192 void NetworkQualityEstimator::SetCurrentNetworkNameForTests(
193 const std::string& network_name) {
194 current_network_name_ = network_name;
161 } 195 }
162 196
163 NetworkQuality NetworkQualityEstimator::GetEstimate() const { 197 NetworkQuality NetworkQualityEstimator::GetEstimate() const {
164 DCHECK(thread_checker_.CalledOnValidThread()); 198 DCHECK(thread_checker_.CalledOnValidThread());
165 199
166 if (!bytes_read_since_last_connection_change_) { 200 if (!bytes_read_since_last_connection_change_) {
167 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0, 201 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0,
168 peak_kbps_since_last_connection_change_, 0); 202 peak_kbps_since_last_connection_change_, 0);
169 } 203 }
170 if (!peak_kbps_since_last_connection_change_) { 204 if (!peak_kbps_since_last_connection_change_) {
171 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, 205 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1,
172 peak_kbps_since_last_connection_change_, 0); 206 peak_kbps_since_last_connection_change_, 0);
173 } 207 }
174 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, 208 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1,
175 peak_kbps_since_last_connection_change_, 0.1); 209 peak_kbps_since_last_connection_change_, 0.1);
176 } 210 }
177 211
212 void NetworkQualityEstimator::UpdateCurrentNetworkName() {
213 DCHECK(thread_checker_.CalledOnValidThread());
214
215 current_network_name_ = std::string();
216 switch (current_connection_type_) {
217 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
218 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
219 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
220 return;
221 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
222 current_network_name_ = "ethernet";
223 return;
224 #if defined(OS_ANDROID)
225 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
226 current_network_name_ = GetWifiSSID();
227 return;
228 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
229 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
230 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
231 current_network_name_ = android::GetTelephonyNetworkOperator();
232 return;
233 #endif // OS_ANDROID
234 default:
235 #if defined(OS_ANDROID)
236 NOTREACHED() << "Unexpected connection type = "
237 << current_connection_type_;
238 #endif // OS_ANDROID
239 return;
240 }
241 }
242
243 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
244 DCHECK(thread_checker_.CalledOnValidThread());
245
246 if (current_network_name_.empty())
247 return false;
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 return true;
261 }
262
263 return false;
264 }
265
266 void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
267 DCHECK(thread_checker_.CalledOnValidThread());
268
269 if (current_network_name_.empty())
270 return;
271
272 // TODO(tbansal): Following variables should be initialized using the median
273 /// values reported by NetworkQualityEstimator.
274 int median_kbps = 0;
275 base::TimeDelta median_rtt = base::TimeDelta();
bengr 2015/06/01 20:39:34 No need to initialize. The default constructor wil
tbansal1 2015/06/01 21:56:51 Done.
276
277 // If this network is already in the cache, overwrite that entry.
278 for (auto& network_quality : cached_network_quality_) {
279 if (!network_quality.MatchesNetwork(current_connection_type_,
280 current_network_name_)) {
281 continue;
282 }
283
284 network_quality.UpdateNetworkQuality(median_kbps, median_rtt);
285 return;
286 }
287
288 if (cached_network_quality_.size() < kMaximumNetworkQualityCacheSize) {
289 cached_network_quality_.push_back(
290 CachedNetworkQuality(current_connection_type_, current_network_name_,
291 median_kbps, median_rtt));
292 return;
293 }
294
295 DCHECK_EQ(kMaximumNetworkQualityCacheSize, cached_network_quality_.size());
296
297 // Overwrite the oldest entry.
298 int oldest_entry_index = 0;
299 for (size_t i = 0; i < cached_network_quality_.size(); ++i) {
300 if (cached_network_quality_[i].last_updated_ <
301 cached_network_quality_[oldest_entry_index].last_updated_)
302 oldest_entry_index = i;
303 }
304
305 cached_network_quality_[oldest_entry_index] = CachedNetworkQuality(
306 current_connection_type_, current_network_name_, median_kbps, median_rtt);
307
308 DCHECK_EQ(kMaximumNetworkQualityCacheSize, cached_network_quality_.size());
309 }
310
311 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
312 NetworkChangeNotifier::ConnectionType connection_type,
313 const std::string& network_name,
314 int median_kbps,
315 const base::TimeDelta& median_rtt)
316 : median_kbps_(median_kbps),
317 median_rtt_(median_rtt),
318 last_updated_(base::TimeTicks::Now()),
319 connection_type_(connection_type),
320 network_name_(network_name) {
321 // Networks with empty names should not be cached since they are harder to
bengr 2015/06/01 20:39:34 I disagree. I think a cached entry is helpful rega
tbansal1 2015/06/01 21:56:51 Done.
322 // disambiguate.
323 DCHECK_NE(network_name_, std::string());
324 }
325
326 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() {
327 }
328
329 void NetworkQualityEstimator::CachedNetworkQuality::UpdateNetworkQuality(
330 int median_kbps,
331 const base::TimeDelta& median_rtt) {
bengr 2015/06/01 20:39:34 Would be good to sanity check the parameters, e.g.
tbansal1 2015/06/01 21:56:51 Added a TODO in ReadCachedNetworkQualityEstimate()
bengr 2015/06/01 23:21:10 I'm not sure what you mean. rtt and kbps should ne
tbansal1 2015/06/02 18:18:05 Added DCHECKs. Also, added filters in NotifyDataRe
332 median_kbps_ = median_kbps;
333 median_rtt_ = median_rtt;
334 last_updated_ = base::TimeTicks::Now();
335 }
336
337 bool NetworkQualityEstimator::CachedNetworkQuality::MatchesNetwork(
338 NetworkChangeNotifier::ConnectionType connection_type,
339 const std::string& network_name) const {
340 return connection_type == connection_type_ && network_name == network_name_;
341 }
342
178 } // namespace net 343 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698