OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/net/predictor.h" | 5 #include "chrome/browser/net/predictor.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <set> | 9 #include <set> |
10 #include <sstream> | 10 #include <sstream> |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 // connections. Once this falls below kDiscardableExpectedValue the referrer | 57 // connections. Once this falls below kDiscardableExpectedValue the referrer |
58 // will be discarded. | 58 // will be discarded. |
59 // TODO(jar): Measure size of referrer lists in the field. Consider an adaptive | 59 // TODO(jar): Measure size of referrer lists in the field. Consider an adaptive |
60 // system that uses a higher trim ratio when the list is large. | 60 // system that uses a higher trim ratio when the list is large. |
61 // static | 61 // static |
62 const double Predictor::kReferrerTrimRatio = 0.97153; | 62 const double Predictor::kReferrerTrimRatio = 0.97153; |
63 const int64 Predictor::kDurationBetweenTrimmingsHours = 1; | 63 const int64 Predictor::kDurationBetweenTrimmingsHours = 1; |
64 const int64 Predictor::kDurationBetweenTrimmingIncrementsSeconds = 15; | 64 const int64 Predictor::kDurationBetweenTrimmingIncrementsSeconds = 15; |
65 const size_t Predictor::kUrlsTrimmedPerIncrement = 5u; | 65 const size_t Predictor::kUrlsTrimmedPerIncrement = 5u; |
66 const size_t Predictor::kMaxSpeculativeParallelResolves = 3; | 66 const size_t Predictor::kMaxSpeculativeParallelResolves = 3; |
| 67 const int Predictor::kMaxUnusedSocketLifetimeSecondsWithoutAGet = 10; |
67 // To control our congestion avoidance system, which discards a queue when | 68 // To control our congestion avoidance system, which discards a queue when |
68 // resolutions are "taking too long," we need an expected resolution time. | 69 // resolutions are "taking too long," we need an expected resolution time. |
69 // Common average is in the range of 300-500ms. | 70 // Common average is in the range of 300-500ms. |
70 const int kExpectedResolutionTimeMs = 500; | 71 const int kExpectedResolutionTimeMs = 500; |
71 const int Predictor::kTypicalSpeculativeGroupSize = 8; | 72 const int Predictor::kTypicalSpeculativeGroupSize = 8; |
72 const int Predictor::kMaxSpeculativeResolveQueueDelayMs = | 73 const int Predictor::kMaxSpeculativeResolveQueueDelayMs = |
73 (kExpectedResolutionTimeMs * Predictor::kTypicalSpeculativeGroupSize) / | 74 (kExpectedResolutionTimeMs * Predictor::kTypicalSpeculativeGroupSize) / |
74 Predictor::kMaxSpeculativeParallelResolves; | 75 Predictor::kMaxSpeculativeParallelResolves; |
75 | 76 |
76 static int g_max_queueing_delay_ms = | 77 static int g_max_queueing_delay_ms = |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
129 url_request_context_getter_(NULL), | 130 url_request_context_getter_(NULL), |
130 predictor_enabled_(true), | 131 predictor_enabled_(true), |
131 peak_pending_lookups_(0), | 132 peak_pending_lookups_(0), |
132 shutdown_(false), | 133 shutdown_(false), |
133 max_concurrent_dns_lookups_(g_max_parallel_resolves), | 134 max_concurrent_dns_lookups_(g_max_parallel_resolves), |
134 max_dns_queue_delay_( | 135 max_dns_queue_delay_( |
135 TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)), | 136 TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)), |
136 host_resolver_(NULL), | 137 host_resolver_(NULL), |
137 preconnect_enabled_(preconnect_enabled), | 138 preconnect_enabled_(preconnect_enabled), |
138 consecutive_omnibox_preconnect_count_(0), | 139 consecutive_omnibox_preconnect_count_(0), |
| 140 recent_preconnects_( |
| 141 TimeDelta::FromSeconds(kMaxUnusedSocketLifetimeSecondsWithoutAGet)), |
139 next_trim_time_(base::TimeTicks::Now() + | 142 next_trim_time_(base::TimeTicks::Now() + |
140 TimeDelta::FromHours(kDurationBetweenTrimmingsHours)) { | 143 TimeDelta::FromHours(kDurationBetweenTrimmingsHours)) { |
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
142 } | 145 } |
143 | 146 |
144 Predictor::~Predictor() { | 147 Predictor::~Predictor() { |
145 // TODO(rlp): Add DCHECK for CurrentlyOn(BrowserThread::IO) when the | 148 // TODO(rlp): Add DCHECK for CurrentlyOn(BrowserThread::IO) when the |
146 // ProfileManagerTest has been updated with a mock profile. | 149 // ProfileManagerTest has been updated with a mock profile. |
147 DCHECK(shutdown_); | 150 DCHECK(shutdown_); |
148 } | 151 } |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 // pool. Currently, we just do a connect, which MAY be reset if we | 239 // pool. Currently, we just do a connect, which MAY be reset if we |
237 // don't use it in 10 secondes!!! As a result, we may do more | 240 // don't use it in 10 secondes!!! As a result, we may do more |
238 // connections, and actually cost the server more than if we did a real | 241 // connections, and actually cost the server more than if we did a real |
239 // get with a fake request (/gen_204 might be the good path on Google). | 242 // get with a fake request (/gen_204 might be the good path on Google). |
240 const int kMaxSearchKeepaliveSeconds(10); | 243 const int kMaxSearchKeepaliveSeconds(10); |
241 if ((now - last_omnibox_preconnect_).InSeconds() < | 244 if ((now - last_omnibox_preconnect_).InSeconds() < |
242 kMaxSearchKeepaliveSeconds) | 245 kMaxSearchKeepaliveSeconds) |
243 return; // We've done a preconnect recently. | 246 return; // We've done a preconnect recently. |
244 last_omnibox_preconnect_ = now; | 247 last_omnibox_preconnect_ = now; |
245 const int kConnectionsNeeded = 1; | 248 const int kConnectionsNeeded = 1; |
246 PreconnectOnUIThread(CanonicalizeUrl(url), GURL(), motivation, | 249 PreconnectUrl(CanonicalizeUrl(url), GURL(), motivation, |
247 kConnectionsNeeded, | 250 kConnectionsNeeded); |
248 url_request_context_getter_); | |
249 return; // Skip pre-resolution, since we'll open a connection. | 251 return; // Skip pre-resolution, since we'll open a connection. |
250 } | 252 } |
251 } else { | 253 } else { |
252 consecutive_omnibox_preconnect_count_ = 0; | 254 consecutive_omnibox_preconnect_count_ = 0; |
253 } | 255 } |
254 } | 256 } |
255 | 257 |
256 // Fall through and consider pre-resolution. | 258 // Fall through and consider pre-resolution. |
257 | 259 |
258 // Omnibox tends to call in pairs (just a few milliseconds apart), and we | 260 // Omnibox tends to call in pairs (just a few milliseconds apart), and we |
(...skipping 18 matching lines...) Expand all Loading... |
277 const GURL& first_party_for_cookies) { | 279 const GURL& first_party_for_cookies) { |
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || | 280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || |
279 BrowserThread::CurrentlyOn(BrowserThread::IO)); | 281 BrowserThread::CurrentlyOn(BrowserThread::IO)); |
280 if (!predictor_enabled_ || !preconnect_enabled() || | 282 if (!predictor_enabled_ || !preconnect_enabled() || |
281 !url.is_valid() || !url.has_host()) | 283 !url.is_valid() || !url.has_host()) |
282 return; | 284 return; |
283 | 285 |
284 std::string host = url.HostNoBrackets(); | 286 std::string host = url.HostNoBrackets(); |
285 UrlInfo::ResolutionMotivation motivation(UrlInfo::EARLY_LOAD_MOTIVATED); | 287 UrlInfo::ResolutionMotivation motivation(UrlInfo::EARLY_LOAD_MOTIVATED); |
286 const int kConnectionsNeeded = 1; | 288 const int kConnectionsNeeded = 1; |
287 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 289 PreconnectUrl(CanonicalizeUrl(url), first_party_for_cookies, |
288 PreconnectOnUIThread(CanonicalizeUrl(url), first_party_for_cookies, | 290 motivation, kConnectionsNeeded); |
289 motivation, kConnectionsNeeded, | |
290 url_request_context_getter_); | |
291 } else { | |
292 PreconnectOnIOThread(CanonicalizeUrl(url), first_party_for_cookies, | |
293 motivation, kConnectionsNeeded, | |
294 url_request_context_getter_); | |
295 } | |
296 PredictFrameSubresources(url.GetWithEmptyPath(), first_party_for_cookies); | 291 PredictFrameSubresources(url.GetWithEmptyPath(), first_party_for_cookies); |
297 } | 292 } |
298 | 293 |
299 UrlList Predictor::GetPredictedUrlListAtStartup( | 294 UrlList Predictor::GetPredictedUrlListAtStartup( |
300 PrefService* user_prefs, | 295 PrefService* user_prefs, |
301 PrefService* local_state) { | 296 PrefService* local_state) { |
302 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
303 UrlList urls; | 298 UrlList urls; |
304 // Recall list of URLs we learned about during last session. | 299 // Recall list of URLs we learned about during last session. |
305 // This may catch secondary hostnames, pulled in by the homepages. It will | 300 // This may catch secondary hostnames, pulled in by the homepages. It will |
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
822 base::Bind(&Predictor::EnablePredictorOnIOThread, | 817 base::Bind(&Predictor::EnablePredictorOnIOThread, |
823 base::Unretained(this), enable)); | 818 base::Unretained(this), enable)); |
824 } | 819 } |
825 } | 820 } |
826 | 821 |
827 void Predictor::EnablePredictorOnIOThread(bool enable) { | 822 void Predictor::EnablePredictorOnIOThread(bool enable) { |
828 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 823 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
829 predictor_enabled_ = enable; | 824 predictor_enabled_ = enable; |
830 } | 825 } |
831 | 826 |
| 827 void Predictor::PreconnectUrl(const GURL& url, |
| 828 const GURL& first_party_for_cookies, |
| 829 UrlInfo::ResolutionMotivation motivation, |
| 830 int count) { |
| 831 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || |
| 832 BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 833 |
| 834 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 835 PreconnectUrlOnIOThread(url, first_party_for_cookies, motivation, count); |
| 836 } else { |
| 837 BrowserThread::PostTask( |
| 838 BrowserThread::IO, |
| 839 FROM_HERE, |
| 840 base::Bind(&Predictor::PreconnectUrlOnIOThread, |
| 841 base::Unretained(this), url, first_party_for_cookies, |
| 842 motivation, count)); |
| 843 } |
| 844 } |
| 845 |
| 846 void Predictor::PreconnectUrlOnIOThread( |
| 847 const GURL& url, const GURL& first_party_for_cookies, |
| 848 UrlInfo::ResolutionMotivation motivation, int count) { |
| 849 GURL canonical_url(CanonicalizeUrl(url)); |
| 850 recent_preconnects_.SetRecentlySeen(canonical_url); |
| 851 |
| 852 PreconnectOnIOThread(url, first_party_for_cookies, motivation, count, |
| 853 url_request_context_getter_); |
| 854 } |
| 855 |
| 856 void Predictor::RecordPreconnectNavigationStats(const GURL& url) { |
| 857 UMA_HISTOGRAM_BOOLEAN( |
| 858 "Net.PreconnectedNavigation", |
| 859 recent_preconnects_.WasRecentlySeen(url)); |
| 860 } |
| 861 |
832 void Predictor::PredictFrameSubresources(const GURL& url, | 862 void Predictor::PredictFrameSubresources(const GURL& url, |
833 const GURL& first_party_for_cookies) { | 863 const GURL& first_party_for_cookies) { |
834 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || | 864 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || |
835 BrowserThread::CurrentlyOn(BrowserThread::IO)); | 865 BrowserThread::CurrentlyOn(BrowserThread::IO)); |
836 if (!predictor_enabled_) | 866 if (!predictor_enabled_) |
837 return; | 867 return; |
838 DCHECK_EQ(url.GetWithEmptyPath(), url); | 868 DCHECK_EQ(url.GetWithEmptyPath(), url); |
839 // Add one pass through the message loop to allow current navigation to | 869 // Add one pass through the message loop to allow current navigation to |
840 // proceed. | 870 // proceed. |
841 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | 871 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
(...skipping 20 matching lines...) Expand all Loading... |
862 DCHECK_EQ(url.GetWithEmptyPath(), url); | 892 DCHECK_EQ(url.GetWithEmptyPath(), url); |
863 Referrers::iterator it = referrers_.find(url); | 893 Referrers::iterator it = referrers_.find(url); |
864 if (referrers_.end() == it) { | 894 if (referrers_.end() == it) { |
865 // Only when we don't know anything about this url, make 2 connections | 895 // Only when we don't know anything about this url, make 2 connections |
866 // available. We could do this completely via learning (by prepopulating | 896 // available. We could do this completely via learning (by prepopulating |
867 // the referrer_ list with this expected value), but it would swell the | 897 // the referrer_ list with this expected value), but it would swell the |
868 // size of the list with all the "Leaf" nodes in the tree (nodes that don't | 898 // size of the list with all the "Leaf" nodes in the tree (nodes that don't |
869 // load any subresources). If we learn about this resource, we will instead | 899 // load any subresources). If we learn about this resource, we will instead |
870 // provide a more carefully estimated preconnection count. | 900 // provide a more carefully estimated preconnection count. |
871 if (preconnect_enabled_) { | 901 if (preconnect_enabled_) { |
872 PreconnectOnIOThread(url, first_party_for_cookies, | 902 PreconnectUrlOnIOThread(url, first_party_for_cookies, |
873 UrlInfo::SELF_REFERAL_MOTIVATED, 2, | 903 UrlInfo::SELF_REFERAL_MOTIVATED, 2); |
874 url_request_context_getter_); | |
875 } | 904 } |
876 return; | 905 return; |
877 } | 906 } |
878 | 907 |
879 Referrer* referrer = &(it->second); | 908 Referrer* referrer = &(it->second); |
880 referrer->IncrementUseCount(); | 909 referrer->IncrementUseCount(); |
881 const UrlInfo::ResolutionMotivation motivation = | 910 const UrlInfo::ResolutionMotivation motivation = |
882 UrlInfo::LEARNED_REFERAL_MOTIVATED; | 911 UrlInfo::LEARNED_REFERAL_MOTIVATED; |
883 for (Referrer::iterator future_url = referrer->begin(); | 912 for (Referrer::iterator future_url = referrer->begin(); |
884 future_url != referrer->end(); ++future_url) { | 913 future_url != referrer->end(); ++future_url) { |
885 SubresourceValue evalution(TOO_NEW); | 914 SubresourceValue evalution(TOO_NEW); |
886 double connection_expectation = future_url->second.subresource_use_rate(); | 915 double connection_expectation = future_url->second.subresource_use_rate(); |
887 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation", | 916 UMA_HISTOGRAM_CUSTOM_COUNTS("Net.PreconnectSubresourceExpectation", |
888 static_cast<int>(connection_expectation * 100), | 917 static_cast<int>(connection_expectation * 100), |
889 10, 5000, 50); | 918 10, 5000, 50); |
890 future_url->second.ReferrerWasObserved(); | 919 future_url->second.ReferrerWasObserved(); |
891 if (preconnect_enabled_ && | 920 if (preconnect_enabled_ && |
892 connection_expectation > kPreconnectWorthyExpectedValue) { | 921 connection_expectation > kPreconnectWorthyExpectedValue) { |
893 evalution = PRECONNECTION; | 922 evalution = PRECONNECTION; |
894 future_url->second.IncrementPreconnectionCount(); | 923 future_url->second.IncrementPreconnectionCount(); |
895 int count = static_cast<int>(std::ceil(connection_expectation)); | 924 int count = static_cast<int>(std::ceil(connection_expectation)); |
896 if (url.host() == future_url->first.host()) | 925 if (url.host() == future_url->first.host()) |
897 ++count; | 926 ++count; |
898 PreconnectOnIOThread(future_url->first, first_party_for_cookies, | 927 PreconnectUrlOnIOThread(future_url->first, first_party_for_cookies, |
899 motivation, count, url_request_context_getter_); | 928 motivation, count); |
900 } else if (connection_expectation > kDNSPreresolutionWorthyExpectedValue) { | 929 } else if (connection_expectation > kDNSPreresolutionWorthyExpectedValue) { |
901 evalution = PRERESOLUTION; | 930 evalution = PRERESOLUTION; |
902 future_url->second.preresolution_increment(); | 931 future_url->second.preresolution_increment(); |
903 UrlInfo* queued_info = AppendToResolutionQueue(future_url->first, | 932 UrlInfo* queued_info = AppendToResolutionQueue(future_url->first, |
904 motivation); | 933 motivation); |
905 if (queued_info) | 934 if (queued_info) |
906 queued_info->SetReferringHostname(url); | 935 queued_info->SetReferringHostname(url); |
907 } | 936 } |
908 UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution, | 937 UMA_HISTOGRAM_ENUMERATION("Net.PreconnectSubresourceEval", evalution, |
909 SUBRESOURCE_VALUE_MAX); | 938 SUBRESOURCE_VALUE_MAX); |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1195 IOThread* io_thread, | 1224 IOThread* io_thread, |
1196 net::URLRequestContextGetter* getter) { | 1225 net::URLRequestContextGetter* getter) { |
1197 // Empty function for unittests. | 1226 // Empty function for unittests. |
1198 } | 1227 } |
1199 | 1228 |
1200 void SimplePredictor::ShutdownOnUIThread(PrefService* user_prefs) { | 1229 void SimplePredictor::ShutdownOnUIThread(PrefService* user_prefs) { |
1201 SetShutdown(true); | 1230 SetShutdown(true); |
1202 } | 1231 } |
1203 | 1232 |
1204 } // namespace chrome_browser_net | 1233 } // namespace chrome_browser_net |
OLD | NEW |