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

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

Powered by Google App Engine
This is Rietveld 408576698