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

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: nits Created 7 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 (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.h" 25 #include "base/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
131 // gather precision/recall for user-event based preconnect triggers.
132 // Stats are gathered via two LRU caches that remembers all preconnect and
133 // user link navigations within the 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
136 // kMaxUnusedSocketLifetimeSecondsWithoutAGet.
137 class Predictor::PreconnectUsage {
138 public:
139 PreconnectUsage();
140 ~PreconnectUsage();
141
142 // Record a preconnect trigger to the url.
143 void ObservePreconnect(const GURL& url);
144
145 // Record a user link navigation to the url.
146 void ObserveNavigation(const GURL& url, const GURL& original_url);
147
148 private:
149 // This tracks whether a preconnect was used in some navigation or not
150 class PreconnectPrecisionStat {
151 public:
152 PreconnectPrecisionStat()
153 : timestamp_(base::TimeTicks::Now()),
154 was_used_(false) {
155 }
156
157 const base::TimeTicks& timestamp() { return timestamp_; }
158
159 void set_was_used() { was_used_ = true; }
160 bool was_used() const { return was_used_; }
161
162 private:
163 base::TimeTicks timestamp_;
164 bool was_used_;
165 };
166
167 typedef base::MRUCache<GURL, PreconnectPrecisionStat> MRUPreconnects;
168 MRUPreconnects mru_preconnects_;
169
170 // This tracks whether a navigation used a preconnected session or not
171 class PreconnectRecallStat {
172 public:
173 PreconnectRecallStat()
174 : timestamp_(base::TimeTicks::Now()),
175 did_use_preconnect_(false) {
176 }
177
178 const base::TimeTicks& timestamp() { return timestamp_; }
179
180 void set_did_use_preconnect() { did_use_preconnect_ = true; }
181 bool did_use_preconnect() const { return did_use_preconnect_; }
182
183 private:
184 base::TimeTicks timestamp_;
185 bool did_use_preconnect_;
186 };
187
188 typedef base::MRUCache<GURL, PreconnectRecallStat> MRUNavigations;
189 MRUNavigations mru_navigations_;
190
191 // The longest time an entry can persist in mru_preconnect_/mru_navigations_
192 const base::TimeDelta max_duration_;
193
194 DISALLOW_COPY_AND_ASSIGN(PreconnectUsage);
195 };
196
197 Predictor::PreconnectUsage::PreconnectUsage()
198 : mru_preconnects_(MRUPreconnects::NO_AUTO_EVICT),
199 mru_navigations_(MRUNavigations::NO_AUTO_EVICT),
200 max_duration_(base::TimeDelta::FromSeconds(
201 Predictor::kMaxUnusedSocketLifetimeSecondsWithoutAGet)) {
202 }
203
204 Predictor::PreconnectUsage::~PreconnectUsage() {}
205
206 void Predictor::PreconnectUsage::ObservePreconnect(const GURL& url) {
207 GURL canonical_url(Predictor::CanonicalizeUrl(url));
208 mru_preconnects_.Put(canonical_url, PreconnectPrecisionStat());
209 }
210
211 void Predictor::PreconnectUsage::ObserveNavigation(const GURL& url,
212 const GURL& original_url) {
213 GURL canonical_url(Predictor::CanonicalizeUrl(url));
214
215 // Evict any overly old entries and record stats
216 base::TimeTicks now = base::TimeTicks::Now();
217
218 MRUPreconnects::reverse_iterator eldestPreconnect = mru_preconnects_.rbegin();
219 while (!mru_preconnects_.empty()) {
220 DCHECK(eldestPreconnect == mru_preconnects_.rbegin());
221 if (now - eldestPreconnect->second.timestamp() < max_duration_)
222 break;
223
224 UMA_HISTOGRAM_BOOLEAN("Net.PreconnectTriggerUsed",
225 eldestPreconnect->second.was_used());
226 eldestPreconnect = mru_preconnects_.Erase(eldestPreconnect);
227 }
228
229 MRUNavigations::reverse_iterator eldestNavigation = mru_navigations_.rbegin();
230 while (!mru_navigations_.empty()) {
231 DCHECK(eldestNavigation == mru_navigations_.rbegin());
232 if (now - eldestNavigation->second.timestamp() < max_duration_)
233 break;
234
235 UMA_HISTOGRAM_BOOLEAN("Net.PreconnectedNavigation",
236 eldestNavigation->second.did_use_preconnect());
237 eldestNavigation = mru_navigations_.Erase(eldestNavigation);
238 }
239
240 // Record the preconnect trigger for the url as used if exist
241 MRUNavigations::iterator itNavigation = mru_navigations_.Peek(original_url);
242 if (itNavigation == mru_navigations_.end())
243 itNavigation = mru_navigations_.Put(original_url, PreconnectRecallStat());
244
245 MRUPreconnects::iterator itPreconnect = mru_preconnects_.Peek(canonical_url);
246 bool wasPreconnected = (itPreconnect != mru_preconnects_.end());
247 if (wasPreconnected) {
248 itPreconnect->second.set_was_used();
249 itNavigation->second.set_did_use_preconnect();
250 }
251 }
252
128 Predictor::Predictor(bool preconnect_enabled) 253 Predictor::Predictor(bool preconnect_enabled)
129 : url_request_context_getter_(NULL), 254 : url_request_context_getter_(NULL),
130 predictor_enabled_(true), 255 predictor_enabled_(true),
131 peak_pending_lookups_(0), 256 peak_pending_lookups_(0),
132 shutdown_(false), 257 shutdown_(false),
133 max_concurrent_dns_lookups_(g_max_parallel_resolves), 258 max_concurrent_dns_lookups_(g_max_parallel_resolves),
134 max_dns_queue_delay_( 259 max_dns_queue_delay_(
135 TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)), 260 TimeDelta::FromMilliseconds(g_max_queueing_delay_ms)),
136 host_resolver_(NULL), 261 host_resolver_(NULL),
137 preconnect_enabled_(preconnect_enabled), 262 preconnect_enabled_(preconnect_enabled),
138 consecutive_omnibox_preconnect_count_(0), 263 consecutive_omnibox_preconnect_count_(0),
139 recent_preconnects_(
140 TimeDelta::FromSeconds(kMaxUnusedSocketLifetimeSecondsWithoutAGet)),
141 next_trim_time_(base::TimeTicks::Now() + 264 next_trim_time_(base::TimeTicks::Now() +
142 TimeDelta::FromHours(kDurationBetweenTrimmingsHours)) { 265 TimeDelta::FromHours(kDurationBetweenTrimmingsHours)) {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 266 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144 } 267 }
145 268
146 Predictor::~Predictor() { 269 Predictor::~Predictor() {
147 // TODO(rlp): Add DCHECK for CurrentlyOn(BrowserThread::IO) when the 270 // TODO(rlp): Add DCHECK for CurrentlyOn(BrowserThread::IO) when the
148 // ProfileManagerTest has been updated with a mock profile. 271 // ProfileManagerTest has been updated with a mock profile.
149 DCHECK(shutdown_); 272 DCHECK(shutdown_);
150 } 273 }
(...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 void Predictor::FinalizeInitializationOnIOThread( 783 void Predictor::FinalizeInitializationOnIOThread(
661 const UrlList& startup_urls, 784 const UrlList& startup_urls,
662 base::ListValue* referral_list, 785 base::ListValue* referral_list,
663 IOThread* io_thread, 786 IOThread* io_thread,
664 bool predictor_enabled) { 787 bool predictor_enabled) {
665 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 788 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
666 789
667 predictor_enabled_ = predictor_enabled; 790 predictor_enabled_ = predictor_enabled;
668 initial_observer_.reset(new InitialObserver()); 791 initial_observer_.reset(new InitialObserver());
669 host_resolver_ = io_thread->globals()->host_resolver.get(); 792 host_resolver_ = io_thread->globals()->host_resolver.get();
793 preconnect_usage_.reset(new PreconnectUsage());
670 794
671 // base::WeakPtrFactory instances need to be created and destroyed 795 // base::WeakPtrFactory instances need to be created and destroyed
672 // on the same thread. The predictor lives on the IO thread and will die 796 // on the same thread. The predictor lives on the IO thread and will die
673 // from there so now that we're on the IO thread we need to properly 797 // from there so now that we're on the IO thread we need to properly
674 // initialize the base::WeakPtrFactory. 798 // initialize the base::WeakPtrFactory.
675 // TODO(groby): Check if WeakPtrFactory has the same constraint. 799 // TODO(groby): Check if WeakPtrFactory has the same constraint.
676 weak_factory_.reset(new base::WeakPtrFactory<Predictor>(this)); 800 weak_factory_.reset(new base::WeakPtrFactory<Predictor>(this));
677 801
678 // Prefetch these hostnames on startup. 802 // Prefetch these hostnames on startup.
679 DnsPrefetchMotivatedList(startup_urls, UrlInfo::STARTUP_LIST_MOTIVATED); 803 DnsPrefetchMotivatedList(startup_urls, UrlInfo::STARTUP_LIST_MOTIVATED);
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
838 FROM_HERE, 962 FROM_HERE,
839 base::Bind(&Predictor::PreconnectUrlOnIOThread, 963 base::Bind(&Predictor::PreconnectUrlOnIOThread,
840 base::Unretained(this), url, first_party_for_cookies, 964 base::Unretained(this), url, first_party_for_cookies,
841 motivation, count)); 965 motivation, count));
842 } 966 }
843 } 967 }
844 968
845 void Predictor::PreconnectUrlOnIOThread( 969 void Predictor::PreconnectUrlOnIOThread(
846 const GURL& url, const GURL& first_party_for_cookies, 970 const GURL& url, const GURL& first_party_for_cookies,
847 UrlInfo::ResolutionMotivation motivation, int count) { 971 UrlInfo::ResolutionMotivation motivation, int count) {
848 GURL canonical_url(CanonicalizeUrl(url));
849 recent_preconnects_.SetRecentlySeen(canonical_url);
850
851 PreconnectOnIOThread(url, 972 PreconnectOnIOThread(url,
852 first_party_for_cookies, 973 first_party_for_cookies,
853 motivation, 974 motivation,
854 count, 975 count,
855 url_request_context_getter_.get()); 976 url_request_context_getter_.get());
856 } 977 }
857 978
858 void Predictor::RecordPreconnectNavigationStats(const GURL& url) { 979 void Predictor::RecordPreconnectTrigger(const GURL& url) {
859 UMA_HISTOGRAM_BOOLEAN( 980 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
860 "Net.PreconnectedNavigation", 981 BrowserThread::CurrentlyOn(BrowserThread::IO));
861 recent_preconnects_.WasRecentlySeen(url)); 982
983 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
984 RecordPreconnectTriggerOnIOThread(url);
985 } else {
986 BrowserThread::PostTask(
987 BrowserThread::IO,
988 FROM_HERE,
989 base::Bind(&Predictor::RecordPreconnectTriggerOnIOThread,
990 base::Unretained(this), url));
991 }
992 }
993
994 void Predictor::RecordPreconnectTriggerOnIOThread(const GURL& url) {
995 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
996 preconnect_usage_->ObservePreconnect(url);
997 }
998
999 void Predictor::RecordPreconnectNavigationStat(const GURL& url,
1000 const GURL& original_url) {
1001 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1002 preconnect_usage_->ObserveNavigation(url, original_url);
862 } 1003 }
863 1004
864 void Predictor::PredictFrameSubresources(const GURL& url, 1005 void Predictor::PredictFrameSubresources(const GURL& url,
865 const GURL& first_party_for_cookies) { 1006 const GURL& first_party_for_cookies) {
866 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || 1007 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
867 BrowserThread::CurrentlyOn(BrowserThread::IO)); 1008 BrowserThread::CurrentlyOn(BrowserThread::IO));
868 if (!predictor_enabled_) 1009 if (!predictor_enabled_)
869 return; 1010 return;
870 DCHECK_EQ(url.GetWithEmptyPath(), url); 1011 DCHECK_EQ(url.GetWithEmptyPath(), url);
871 // Add one pass through the message loop to allow current navigation to 1012 // Add one pass through the message loop to allow current navigation to
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
1226 IOThread* io_thread, 1367 IOThread* io_thread,
1227 net::URLRequestContextGetter* getter) { 1368 net::URLRequestContextGetter* getter) {
1228 // Empty function for unittests. 1369 // Empty function for unittests.
1229 } 1370 }
1230 1371
1231 void SimplePredictor::ShutdownOnUIThread(PrefService* user_prefs) { 1372 void SimplePredictor::ShutdownOnUIThread(PrefService* user_prefs) {
1232 SetShutdown(true); 1373 SetShutdown(true);
1233 } 1374 }
1234 1375
1235 } // namespace chrome_browser_net 1376 } // namespace chrome_browser_net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698