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

Side by Side Diff: chrome/browser/net/predictor.cc

Issue 16514008: Add metrics for calculating precision/recall of link navigation pre-connect triggers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: styling only (no logic change) Created 7 years, 4 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 (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>
11 11
12 #include "base/basictypes.h"
12 #include "base/bind.h" 13 #include "base/bind.h"
13 #include "base/command_line.h" 14 #include "base/command_line.h"
14 #include "base/compiler_specific.h" 15 #include "base/compiler_specific.h"
16 #include "base/containers/mru_cache.h"
15 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
16 #include "base/prefs/pref_service.h" 18 #include "base/prefs/pref_service.h"
17 #include "base/stl_util.h" 19 #include "base/stl_util.h"
18 #include "base/strings/string_split.h" 20 #include "base/strings/string_split.h"
19 #include "base/strings/string_util.h" 21 #include "base/strings/string_util.h"
20 #include "base/strings/stringprintf.h" 22 #include "base/strings/stringprintf.h"
21 #include "base/synchronization/waitable_event.h" 23 #include "base/synchronization/waitable_event.h"
22 #include "base/threading/thread_restrictions.h" 24 #include "base/threading/thread_restrictions.h"
23 #include "base/time/time.h" 25 #include "base/time/time.h"
24 #include "base/values.h" 26 #include "base/values.h"
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 120
119 Predictor* predictor_; // The predictor which started us. 121 Predictor* predictor_; // The predictor which started us.
120 122
121 const GURL url_; // Hostname to resolve. 123 const GURL url_; // Hostname to resolve.
122 net::SingleRequestHostResolver resolver_; 124 net::SingleRequestHostResolver resolver_;
123 net::AddressList addresses_; 125 net::AddressList addresses_;
124 126
125 DISALLOW_COPY_AND_ASSIGN(LookupRequest); 127 DISALLOW_COPY_AND_ASSIGN(LookupRequest);
126 }; 128 };
127 129
130 // This records UMAs for preconnect usage based on navigation URLs to
jar (doing other things) 2013/08/01 22:56:47 FWIW: The long standing bug in this algorithm is t
kouhei (in TOK) 2013/08/02 06:18:03 My understanding is that per-socket utilization co
131 // gather precision/recall for user-event based preconnect triggers.
132 // Stats are gathered via a LRU cach that remembers all preconnect within the
jar (doing other things) 2013/08/01 22:56:47 nit: cache-->cache
kouhei (in TOK) 2013/08/02 06:18:03 Done.
133 // last N seconds.
134 // A preconnect trigger is considered as used iff a navigation including
135 // access to the preconnected host occurs within a time period specified by
jar (doing other things) 2013/08/01 22:56:47 Per comment: We count access (still), and not simu
136 // kMaxUnusedSocketLifetimeSecondsWithoutAGet.
137 class Predictor::PreconnectUsage {
138 public:
139 PreconnectUsage();
140 ~PreconnectUsage();
141
142 // Record a preconnect trigger to |url|.
143 void ObservePreconnect(const GURL& url);
144
145 // Record a user navigation with its redirect history, |url_chain|.
146 // We are uncertain if this is actually a link navigation.
147 void ObserveNavigationChain(const std::vector<GURL>& url_chain,
148 bool is_subresource);
149
150 // Record a user link navigation to |final_url|.
151 // We are certain that this is a user-triggered link navigation.
152 void ObserveLinkNavigation(const GURL& final_url);
153
154 private:
155 // This tracks whether a preconnect was used in some navigation or not
156 class PreconnectPrecisionStat {
157 public:
158 PreconnectPrecisionStat()
159 : timestamp_(base::TimeTicks::Now()),
160 was_used_(false) {
161 }
162
163 const base::TimeTicks& timestamp() { return timestamp_; }
164
165 void set_was_used() { was_used_ = true; }
166 bool was_used() const { return was_used_; }
167
168 private:
169 base::TimeTicks timestamp_;
170 bool was_used_;
171 };
172
173 typedef base::MRUCache<GURL, PreconnectPrecisionStat> MRUPreconnects;
174 MRUPreconnects mru_preconnects_;
175
176 // The longest time an entry can persist in mru_preconnect_
177 const base::TimeDelta max_duration_;
178
179 std::vector<GURL> recent_navigation_chain_;
180
181 DISALLOW_COPY_AND_ASSIGN(PreconnectUsage);
182 };
183
184 Predictor::PreconnectUsage::PreconnectUsage()
185 : mru_preconnects_(MRUPreconnects::NO_AUTO_EVICT),
186 max_duration_(base::TimeDelta::FromSeconds(
187 Predictor::kMaxUnusedSocketLifetimeSecondsWithoutAGet)) {
188 }
189
190 Predictor::PreconnectUsage::~PreconnectUsage() {}
191
192 void Predictor::PreconnectUsage::ObservePreconnect(const GURL& url) {
193 // Evict any overly old entries and record stats
jar (doing other things) 2013/08/01 22:56:47 nit: Period at end of sentences.
kouhei (in TOK) 2013/08/02 06:18:03 Done.
194 base::TimeTicks now = base::TimeTicks::Now();
195
196 MRUPreconnects::reverse_iterator eldest_preconnect =
197 mru_preconnects_.rbegin();
198 while (!mru_preconnects_.empty()) {
199 DCHECK(eldest_preconnect == mru_preconnects_.rbegin());
200 if (now - eldest_preconnect->second.timestamp() < max_duration_)
201 break;
202
203 UMA_HISTOGRAM_BOOLEAN("Net.PreconnectTriggerUsed",
204 eldest_preconnect->second.was_used());
205 eldest_preconnect = mru_preconnects_.Erase(eldest_preconnect);
206 }
207
208 // Add new entry
jar (doing other things) 2013/08/01 22:56:47 nit: period
kouhei (in TOK) 2013/08/02 06:18:03 Done.
209 GURL canonical_url(Predictor::CanonicalizeUrl(url));
210 mru_preconnects_.Put(canonical_url, PreconnectPrecisionStat());
211 }
212
213 void Predictor::PreconnectUsage::ObserveNavigationChain(
214 const std::vector<GURL>& url_chain, bool is_subresource) {
jar (doing other things) 2013/08/01 22:56:47 nit: one arg per line.
kouhei (in TOK) 2013/08/02 06:18:03 Done.
215 if (url_chain.empty())
216 return;
217
218 if (!is_subresource)
219 recent_navigation_chain_ = url_chain;
220
221 GURL canonical_url(Predictor::CanonicalizeUrl(url_chain.back()));
222
223 // Record the preconnect trigger for the url as used if exist
224 MRUPreconnects::iterator itPreconnect = mru_preconnects_.Peek(canonical_url);
225 bool was_preconnected = (itPreconnect != mru_preconnects_.end());
226 if (was_preconnected)
227 itPreconnect->second.set_was_used();
228
229 // This is an UMA which was named incorrectly. This actually measures the
230 // ratio of URLRequests which have used a preconnected session.
231 UMA_HISTOGRAM_BOOLEAN("Net.PreconnectedNavigation", was_preconnected);
232 }
233
234 void Predictor::PreconnectUsage::ObserveLinkNavigation(const GURL& url) {
235 if (recent_navigation_chain_.empty() ||
236 url != recent_navigation_chain_.back()) {
237 // The navigation chain is not available for this navigation.
238 recent_navigation_chain_.clear();
239 recent_navigation_chain_.push_back(url);
240 }
241
242 // See if the link navigation involved preconnected session.
243 bool did_use_preconnect = false;
244 for (std::vector<GURL>::const_iterator it = recent_navigation_chain_.begin();
245 it != recent_navigation_chain_.end();
246 ++it) {
247 GURL canonical_url(Predictor::CanonicalizeUrl(*it));
248
249 // Record the preconnect trigger for the url as used if exist
250 MRUPreconnects::iterator itPreconnect =
251 mru_preconnects_.Peek(canonical_url);
252 bool was_preconnected = (itPreconnect != mru_preconnects_.end());
253 if (was_preconnected)
254 did_use_preconnect = true;
255 }
256
257 UMA_HISTOGRAM_BOOLEAN("Net.PreconnectedLinkNavigations", did_use_preconnect);
258 }
259
128 Predictor::Predictor(bool preconnect_enabled) 260 Predictor::Predictor(bool preconnect_enabled)
129 : url_request_context_getter_(NULL), 261 : url_request_context_getter_(NULL),
130 predictor_enabled_(true), 262 predictor_enabled_(true),
131 peak_pending_lookups_(0), 263 peak_pending_lookups_(0),
132 shutdown_(false), 264 shutdown_(false),
133 max_concurrent_dns_lookups_(g_max_parallel_resolves), 265 max_concurrent_dns_lookups_(g_max_parallel_resolves),
134 max_dns_queue_delay_( 266 max_dns_queue_delay_(
135 TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)), 267 TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)),
136 host_resolver_(NULL), 268 host_resolver_(NULL),
137 preconnect_enabled_(preconnect_enabled), 269 preconnect_enabled_(preconnect_enabled),
138 consecutive_omnibox_preconnect_count_(0), 270 consecutive_omnibox_preconnect_count_(0),
139 recent_preconnects_(
140 TimeDelta::FromSeconds(kMaxUnusedSocketLifetimeSecondsWithoutAGet)),
141 next_trim_time_(base::TimeTicks::Now() + 271 next_trim_time_(base::TimeTicks::Now() +
142 TimeDelta::FromHours(kDurationBetweenTrimmingsHours)) { 272 TimeDelta::FromHours(kDurationBetweenTrimmingsHours)) {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144 } 274 }
145 275
146 Predictor::~Predictor() { 276 Predictor::~Predictor() {
147 // TODO(rlp): Add DCHECK for CurrentlyOn(BrowserThread::IO) when the 277 // TODO(rlp): Add DCHECK for CurrentlyOn(BrowserThread::IO) when the
148 // ProfileManagerTest has been updated with a mock profile. 278 // ProfileManagerTest has been updated with a mock profile.
149 DCHECK(shutdown_); 279 DCHECK(shutdown_);
150 } 280 }
(...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 void Predictor::FinalizeInitializationOnIOThread( 791 void Predictor::FinalizeInitializationOnIOThread(
662 const UrlList& startup_urls, 792 const UrlList& startup_urls,
663 base::ListValue* referral_list, 793 base::ListValue* referral_list,
664 IOThread* io_thread, 794 IOThread* io_thread,
665 bool predictor_enabled) { 795 bool predictor_enabled) {
666 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 796 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
667 797
668 predictor_enabled_ = predictor_enabled; 798 predictor_enabled_ = predictor_enabled;
669 initial_observer_.reset(new InitialObserver()); 799 initial_observer_.reset(new InitialObserver());
670 host_resolver_ = io_thread->globals()->host_resolver.get(); 800 host_resolver_ = io_thread->globals()->host_resolver.get();
801 preconnect_usage_.reset(new PreconnectUsage());
671 802
672 // base::WeakPtrFactory instances need to be created and destroyed 803 // base::WeakPtrFactory instances need to be created and destroyed
673 // on the same thread. The predictor lives on the IO thread and will die 804 // on the same thread. The predictor lives on the IO thread and will die
674 // from there so now that we're on the IO thread we need to properly 805 // from there so now that we're on the IO thread we need to properly
675 // initialize the base::WeakPtrFactory. 806 // initialize the base::WeakPtrFactory.
676 // TODO(groby): Check if WeakPtrFactory has the same constraint. 807 // TODO(groby): Check if WeakPtrFactory has the same constraint.
677 weak_factory_.reset(new base::WeakPtrFactory<Predictor>(this)); 808 weak_factory_.reset(new base::WeakPtrFactory<Predictor>(this));
678 809
679 // Prefetch these hostnames on startup. 810 // Prefetch these hostnames on startup.
680 DnsPrefetchMotivatedList(startup_urls, UrlInfo::STARTUP_LIST_MOTIVATED); 811 DnsPrefetchMotivatedList(startup_urls, UrlInfo::STARTUP_LIST_MOTIVATED);
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
837 BrowserThread::PostTask( 968 BrowserThread::PostTask(
838 BrowserThread::IO, 969 BrowserThread::IO,
839 FROM_HERE, 970 FROM_HERE,
840 base::Bind(&Predictor::PreconnectUrlOnIOThread, 971 base::Bind(&Predictor::PreconnectUrlOnIOThread,
841 base::Unretained(this), url, first_party_for_cookies, 972 base::Unretained(this), url, first_party_for_cookies,
842 motivation, count)); 973 motivation, count));
843 } 974 }
844 } 975 }
845 976
846 void Predictor::PreconnectUrlOnIOThread( 977 void Predictor::PreconnectUrlOnIOThread(
847 const GURL& url, const GURL& first_party_for_cookies, 978 const GURL& url,
848 UrlInfo::ResolutionMotivation motivation, int count) { 979 const GURL& first_party_for_cookies,
849 GURL canonical_url(CanonicalizeUrl(url)); 980 UrlInfo::ResolutionMotivation motivation,
850 recent_preconnects_.SetRecentlySeen(canonical_url); 981 int count) {
851
852 PreconnectOnIOThread(url, 982 PreconnectOnIOThread(url,
853 first_party_for_cookies, 983 first_party_for_cookies,
854 motivation, 984 motivation,
855 count, 985 count,
856 url_request_context_getter_.get()); 986 url_request_context_getter_.get());
857 } 987 }
858 988
859 void Predictor::RecordPreconnectNavigationStats(const GURL& url) { 989 void Predictor::RecordPreconnectTrigger(const GURL& url) {
860 UMA_HISTOGRAM_BOOLEAN( 990 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
861 "Net.PreconnectedNavigation", 991 BrowserThread::CurrentlyOn(BrowserThread::IO));
862 recent_preconnects_.WasRecentlySeen(url)); 992
993 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
994 RecordPreconnectTriggerOnIOThread(url);
995 } else {
996 BrowserThread::PostTask(
997 BrowserThread::IO,
998 FROM_HERE,
999 base::Bind(&Predictor::RecordPreconnectTriggerOnIOThread,
1000 base::Unretained(this), url));
1001 }
1002 }
1003
1004 void Predictor::RecordPreconnectTriggerOnIOThread(const GURL& url) {
1005 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1006 if (preconnect_usage_)
1007 preconnect_usage_->ObservePreconnect(url);
1008 }
1009
1010 void Predictor::RecordPreconnectNavigationStat(
1011 const std::vector<GURL>& url_chain, bool is_subresource) {
jar (doing other things) 2013/08/01 22:56:47 nit: one arg per line.
kouhei (in TOK) 2013/08/02 06:18:03 Done.
1012 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1013
1014 if (preconnect_usage_)
1015 preconnect_usage_->ObserveNavigationChain(url_chain, is_subresource);
1016 }
1017
1018 void Predictor::RecordLinkNavigation(const GURL& url) {
1019 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
1020 BrowserThread::CurrentlyOn(BrowserThread::IO));
1021
1022 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
1023 RecordLinkNavigationOnIOThread(url);
1024 } else {
1025 BrowserThread::PostTask(
1026 BrowserThread::IO,
1027 FROM_HERE,
1028 base::Bind(&Predictor::RecordLinkNavigationOnIOThread,
1029 base::Unretained(this), url));
1030 }
1031 }
1032
1033 void Predictor::RecordLinkNavigationOnIOThread(const GURL& url) {
1034 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1035 if (preconnect_usage_)
1036 preconnect_usage_->ObserveLinkNavigation(url);
863 } 1037 }
864 1038
865 void Predictor::PredictFrameSubresources(const GURL& url, 1039 void Predictor::PredictFrameSubresources(const GURL& url,
866 const GURL& first_party_for_cookies) { 1040 const GURL& first_party_for_cookies) {
867 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || 1041 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
868 BrowserThread::CurrentlyOn(BrowserThread::IO)); 1042 BrowserThread::CurrentlyOn(BrowserThread::IO));
869 if (!predictor_enabled_) 1043 if (!predictor_enabled_)
870 return; 1044 return;
871 DCHECK_EQ(url.GetWithEmptyPath(), url); 1045 DCHECK_EQ(url.GetWithEmptyPath(), url);
872 // Add one pass through the message loop to allow current navigation to 1046 // Add one pass through the message loop to allow current navigation to
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
1227 IOThread* io_thread, 1401 IOThread* io_thread,
1228 net::URLRequestContextGetter* getter) { 1402 net::URLRequestContextGetter* getter) {
1229 // Empty function for unittests. 1403 // Empty function for unittests.
1230 } 1404 }
1231 1405
1232 void SimplePredictor::ShutdownOnUIThread(PrefService* user_prefs) { 1406 void SimplePredictor::ShutdownOnUIThread(PrefService* user_prefs) {
1233 SetShutdown(true); 1407 SetShutdown(true);
1234 } 1408 }
1235 1409
1236 } // namespace chrome_browser_net 1410 } // namespace chrome_browser_net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698