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

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: Using map instead of vector, added NetworkID struct 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"
8 #include "base/memory/scoped_ptr.h"
10 #include "base/metrics/histogram.h" 9 #include "base/metrics/histogram.h"
10 #include "build/build_config.h"
11 #include "net/base/net_util.h" 11 #include "net/base/net_util.h"
12 #include "net/base/network_quality.h" 12 #include "net/base/network_interfaces.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()),
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),
41 current_network_id_(NetworkID(NetworkChangeNotifier::GetConnectionType(),
42 std::string())) {
29 static_assert(kMinRequestDurationMicroseconds > 0, 43 static_assert(kMinRequestDurationMicroseconds > 0,
30 "Minimum request duration must be > 0"); 44 "Minimum request duration must be > 0");
45 static_assert(kMaximumNetworkQualityCacheSize > 0,
46 "Size of the network quality cache must be > 0");
31 NetworkChangeNotifier::AddConnectionTypeObserver(this); 47 NetworkChangeNotifier::AddConnectionTypeObserver(this);
48 current_network_id_.id = GetCurrentNetworkName();
32 } 49 }
33 50
34 NetworkQualityEstimator::~NetworkQualityEstimator() { 51 NetworkQualityEstimator::~NetworkQualityEstimator() {
35 DCHECK(thread_checker_.CalledOnValidThread()); 52 DCHECK(thread_checker_.CalledOnValidThread());
36 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); 53 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
37 } 54 }
38 55
39 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request, 56 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request,
40 int64_t prefilter_bytes_read) { 57 int64_t prefilter_bytes_read) {
41 DCHECK(thread_checker_.CalledOnValidThread()); 58 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 28 matching lines...) Expand all
70 request_duration.InMicroseconds()); 87 request_duration.InMicroseconds());
71 if (kbps > peak_kbps_since_last_connection_change_) 88 if (kbps > peak_kbps_since_last_connection_change_)
72 peak_kbps_since_last_connection_change_ = kbps; 89 peak_kbps_since_last_connection_change_ = kbps;
73 } 90 }
74 } 91 }
75 92
76 void NetworkQualityEstimator::OnConnectionTypeChanged( 93 void NetworkQualityEstimator::OnConnectionTypeChanged(
77 NetworkChangeNotifier::ConnectionType type) { 94 NetworkChangeNotifier::ConnectionType type) {
78 DCHECK(thread_checker_.CalledOnValidThread()); 95 DCHECK(thread_checker_.CalledOnValidThread());
79 if (bytes_read_since_last_connection_change_) { 96 if (bytes_read_since_last_connection_change_) {
80 switch (current_connection_type_) { 97 switch (current_network_id_.type) {
81 case NetworkChangeNotifier::CONNECTION_UNKNOWN: 98 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
82 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", 99 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown",
83 fastest_RTT_since_last_connection_change_); 100 fastest_RTT_since_last_connection_change_);
84 break; 101 break;
85 case NetworkChangeNotifier::CONNECTION_ETHERNET: 102 case NetworkChangeNotifier::CONNECTION_ETHERNET:
86 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", 103 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet",
87 fastest_RTT_since_last_connection_change_); 104 fastest_RTT_since_last_connection_change_);
88 break; 105 break;
89 case NetworkChangeNotifier::CONNECTION_WIFI: 106 case NetworkChangeNotifier::CONNECTION_WIFI:
90 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", 107 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi",
(...skipping 13 matching lines...) Expand all
104 break; 121 break;
105 case NetworkChangeNotifier::CONNECTION_NONE: 122 case NetworkChangeNotifier::CONNECTION_NONE:
106 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", 123 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None",
107 fastest_RTT_since_last_connection_change_); 124 fastest_RTT_since_last_connection_change_);
108 break; 125 break;
109 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 126 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
110 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", 127 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth",
111 fastest_RTT_since_last_connection_change_); 128 fastest_RTT_since_last_connection_change_);
112 break; 129 break;
113 default: 130 default:
114 NOTREACHED(); 131 NOTREACHED() << "Unexpected connection type = "
132 << current_network_id_.type;
115 break; 133 break;
116 } 134 }
117 } 135 }
118 136
119 if (peak_kbps_since_last_connection_change_) { 137 if (peak_kbps_since_last_connection_change_) {
120 switch (current_connection_type_) { 138 switch (current_network_id_.type) {
121 case NetworkChangeNotifier::CONNECTION_UNKNOWN: 139 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
122 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", 140 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown",
123 peak_kbps_since_last_connection_change_); 141 peak_kbps_since_last_connection_change_);
124 break; 142 break;
125 case NetworkChangeNotifier::CONNECTION_ETHERNET: 143 case NetworkChangeNotifier::CONNECTION_ETHERNET:
126 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet", 144 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet",
127 peak_kbps_since_last_connection_change_); 145 peak_kbps_since_last_connection_change_);
128 break; 146 break;
129 case NetworkChangeNotifier::CONNECTION_WIFI: 147 case NetworkChangeNotifier::CONNECTION_WIFI:
130 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi", 148 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi",
(...skipping 13 matching lines...) Expand all
144 break; 162 break;
145 case NetworkChangeNotifier::CONNECTION_NONE: 163 case NetworkChangeNotifier::CONNECTION_NONE:
146 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", 164 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None",
147 peak_kbps_since_last_connection_change_); 165 peak_kbps_since_last_connection_change_);
148 break; 166 break;
149 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: 167 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
150 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", 168 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth",
151 peak_kbps_since_last_connection_change_); 169 peak_kbps_since_last_connection_change_);
152 break; 170 break;
153 default: 171 default:
154 NOTREACHED(); 172 NOTREACHED() << "Unexpected connection type = "
173 << current_network_id_.type;
155 break; 174 break;
156 } 175 }
157 } 176 }
158 177
178 // Write the estimates of the previous network to the cache.
179 CacheNetworkQualityEstimate();
mmenke 2015/06/09 19:48:07 Should we verify that the network actually changed
tbansal1 2015/06/10 00:23:28 I think that would complicate the logic without mu
180
159 last_connection_change_ = base::TimeTicks::Now(); 181 last_connection_change_ = base::TimeTicks::Now();
160 bytes_read_since_last_connection_change_ = false; 182 bytes_read_since_last_connection_change_ = false;
161 peak_kbps_since_last_connection_change_ = 0; 183 peak_kbps_since_last_connection_change_ = 0;
162 current_connection_type_ = type; 184 current_network_id_.type = type;
185 current_network_id_.id = GetCurrentNetworkName();
186
187 // Read any cached estimates for the new network.
188 ReadCachedNetworkQualityEstimate();
189 }
190
191 size_t NetworkQualityEstimator::GetCacheSizeForTests() const {
192 return cached_network_quality_.size();
163 } 193 }
164 194
165 NetworkQuality NetworkQualityEstimator::GetEstimate() const { 195 NetworkQuality NetworkQualityEstimator::GetEstimate() const {
166 DCHECK(thread_checker_.CalledOnValidThread()); 196 DCHECK(thread_checker_.CalledOnValidThread());
167 197
168 if (!bytes_read_since_last_connection_change_) { 198 if (!bytes_read_since_last_connection_change_) {
169 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0, 199 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0,
170 peak_kbps_since_last_connection_change_, 0); 200 peak_kbps_since_last_connection_change_, 0);
171 } 201 }
172 if (!peak_kbps_since_last_connection_change_) { 202 if (!peak_kbps_since_last_connection_change_) {
173 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, 203 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1,
174 peak_kbps_since_last_connection_change_, 0); 204 peak_kbps_since_last_connection_change_, 0);
175 } 205 }
176 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, 206 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1,
177 peak_kbps_since_last_connection_change_, 0.1); 207 peak_kbps_since_last_connection_change_, 0.1);
178 } 208 }
179 209
210 std::string NetworkQualityEstimator::GetCurrentNetworkName() const {
211 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class
212 // that overrides this method on Android platform.
213 DCHECK(thread_checker_.CalledOnValidThread());
214
215 switch (current_network_id_.type) {
216 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
217 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
218 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
219 return std::string();
220 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
221 return std::string();
222 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
223 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
224 return GetWifiSSID();
225 #endif // defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
226 return std::string();
227 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
228 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
229 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
230 #if defined(OS_ANDROID)
231 return android::GetTelephonyNetworkOperator();
232 #endif // OS_ANDROID
233 return std::string();
234 default:
235 NOTREACHED() << "Unexpected connection type = "
236 << current_network_id_.type;
237 return std::string();
238 }
239 }
240
241 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
242 DCHECK(thread_checker_.CalledOnValidThread());
243
244 CachedQualities::iterator it =
245 cached_network_quality_.find(current_network_id_);
246 if (it != cached_network_quality_.end()) {
247 // TOOD(tbansal): Populate these values back into the median computing
248 // algorithm.
249 // Add UMA to record how frequently match happens.
250 // int64 median_kbps = network_quality.median_kbps;
251 // int64 median_rtt_msec = network_quality.median_rtt_milliseconds;
252 // Ensure that the estimates read are non-zero before populating them into
253 // the median computing algorithm.
254 return true;
255 }
256 return false;
257 }
258
259 void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
260 DCHECK(thread_checker_.CalledOnValidThread());
261 DCHECK_LE(cached_network_quality_.size(), kMaximumNetworkQualityCacheSize);
262
263 // TODO(tbansal): Following variables should be initialized using the median
264 /// values reported by NetworkQualityEstimator.
265 int median_kbps = 0;
266 base::TimeDelta median_rtt;
267
268 // If this network is already in the cache, overwrite that entry.
269 CachedQualities::iterator it =
270 cached_network_quality_.find(current_network_id_);
271 if (it != cached_network_quality_.end()) {
272 (it->second)->UpdateNetworkQuality(median_kbps, median_rtt);
273 return;
274 }
275
276 if (cached_network_quality_.size() == kMaximumNetworkQualityCacheSize) {
277 // Remove the oldest entry.
278 CachedQualities::iterator oldest_entry_iterator =
279 cached_network_quality_.begin();
280
281 for (CachedQualities::iterator iterator = cached_network_quality_.begin();
282 iterator != cached_network_quality_.end(); ++iterator) {
283 if ((oldest_entry_iterator->second)->last_update_time() >
284 (iterator->second)->last_update_time()) {
285 oldest_entry_iterator = iterator;
286 }
287 }
288 cached_network_quality_.erase(oldest_entry_iterator);
289 }
290
291 DCHECK_LT(cached_network_quality_.size(), kMaximumNetworkQualityCacheSize);
292 cached_network_quality_.insert(
293 std::make_pair(current_network_id_,
294 make_scoped_ptr(new CachedNetworkQuality(
295 NetworkQuality(median_rtt, 0.0, median_kbps, 0.0)))));
296 DCHECK_LE(cached_network_quality_.size(), kMaximumNetworkQualityCacheSize);
297 }
298
299 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
300 const NetworkQuality& network_quality)
301 : last_update_time_(base::TimeTicks::Now()),
302 network_quality_(network_quality) {
303 }
304
305 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() {
306 }
307
308 void NetworkQualityEstimator::CachedNetworkQuality::UpdateNetworkQuality(
309 uint64_t median_kbps,
310 const base::TimeDelta& median_rtt) {
311 DCHECK_GE(median_kbps, 0U);
312 DCHECK_GE(median_rtt, base::TimeDelta());
313 last_update_time_ = base::TimeTicks::Now();
314
315 network_quality_.fastest_rtt = median_rtt;
316 network_quality_.peak_throughput_kbps = median_kbps;
317 }
318
180 } // namespace net 319 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698