Chromium Code Reviews| Index: chrome/browser/net/predictor.cc |
| diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc |
| index 6bedafb1b9b54ee2bb44123167c200e9b9591065..7ab6d1f8448cae20324c7b9457a7d9b35146b029 100644 |
| --- a/chrome/browser/net/predictor.cc |
| +++ b/chrome/browser/net/predictor.cc |
| @@ -9,9 +9,11 @@ |
| #include <set> |
| #include <sstream> |
| +#include "base/basictypes.h" |
| #include "base/bind.h" |
| #include "base/command_line.h" |
| #include "base/compiler_specific.h" |
| +#include "base/containers/mru_cache.h" |
| #include "base/metrics/histogram.h" |
| #include "base/prefs/pref_service.h" |
| #include "base/stl_util.h" |
| @@ -125,6 +127,136 @@ class Predictor::LookupRequest { |
| DISALLOW_COPY_AND_ASSIGN(LookupRequest); |
| }; |
| +// 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
|
| +// gather precision/recall for user-event based preconnect triggers. |
| +// 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.
|
| +// last N seconds. |
| +// A preconnect trigger is considered as used iff a navigation including |
| +// 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
|
| +// kMaxUnusedSocketLifetimeSecondsWithoutAGet. |
| +class Predictor::PreconnectUsage { |
| + public: |
| + PreconnectUsage(); |
| + ~PreconnectUsage(); |
| + |
| + // Record a preconnect trigger to |url|. |
| + void ObservePreconnect(const GURL& url); |
| + |
| + // Record a user navigation with its redirect history, |url_chain|. |
| + // We are uncertain if this is actually a link navigation. |
| + void ObserveNavigationChain(const std::vector<GURL>& url_chain, |
| + bool is_subresource); |
| + |
| + // Record a user link navigation to |final_url|. |
| + // We are certain that this is a user-triggered link navigation. |
| + void ObserveLinkNavigation(const GURL& final_url); |
| + |
| + private: |
| + // This tracks whether a preconnect was used in some navigation or not |
| + class PreconnectPrecisionStat { |
| + public: |
| + PreconnectPrecisionStat() |
| + : timestamp_(base::TimeTicks::Now()), |
| + was_used_(false) { |
| + } |
| + |
| + const base::TimeTicks& timestamp() { return timestamp_; } |
| + |
| + void set_was_used() { was_used_ = true; } |
| + bool was_used() const { return was_used_; } |
| + |
| + private: |
| + base::TimeTicks timestamp_; |
| + bool was_used_; |
| + }; |
| + |
| + typedef base::MRUCache<GURL, PreconnectPrecisionStat> MRUPreconnects; |
| + MRUPreconnects mru_preconnects_; |
| + |
| + // The longest time an entry can persist in mru_preconnect_ |
| + const base::TimeDelta max_duration_; |
| + |
| + std::vector<GURL> recent_navigation_chain_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(PreconnectUsage); |
| +}; |
| + |
| +Predictor::PreconnectUsage::PreconnectUsage() |
| + : mru_preconnects_(MRUPreconnects::NO_AUTO_EVICT), |
| + max_duration_(base::TimeDelta::FromSeconds( |
| + Predictor::kMaxUnusedSocketLifetimeSecondsWithoutAGet)) { |
| +} |
| + |
| +Predictor::PreconnectUsage::~PreconnectUsage() {} |
| + |
| +void Predictor::PreconnectUsage::ObservePreconnect(const GURL& url) { |
| + // 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.
|
| + base::TimeTicks now = base::TimeTicks::Now(); |
| + |
| + MRUPreconnects::reverse_iterator eldest_preconnect = |
| + mru_preconnects_.rbegin(); |
| + while (!mru_preconnects_.empty()) { |
| + DCHECK(eldest_preconnect == mru_preconnects_.rbegin()); |
| + if (now - eldest_preconnect->second.timestamp() < max_duration_) |
| + break; |
| + |
| + UMA_HISTOGRAM_BOOLEAN("Net.PreconnectTriggerUsed", |
| + eldest_preconnect->second.was_used()); |
| + eldest_preconnect = mru_preconnects_.Erase(eldest_preconnect); |
| + } |
| + |
| + // 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.
|
| + GURL canonical_url(Predictor::CanonicalizeUrl(url)); |
| + mru_preconnects_.Put(canonical_url, PreconnectPrecisionStat()); |
| +} |
| + |
| +void Predictor::PreconnectUsage::ObserveNavigationChain( |
| + 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.
|
| + if (url_chain.empty()) |
| + return; |
| + |
| + if (!is_subresource) |
| + recent_navigation_chain_ = url_chain; |
| + |
| + GURL canonical_url(Predictor::CanonicalizeUrl(url_chain.back())); |
| + |
| + // Record the preconnect trigger for the url as used if exist |
| + MRUPreconnects::iterator itPreconnect = mru_preconnects_.Peek(canonical_url); |
| + bool was_preconnected = (itPreconnect != mru_preconnects_.end()); |
| + if (was_preconnected) |
| + itPreconnect->second.set_was_used(); |
| + |
| + // This is an UMA which was named incorrectly. This actually measures the |
| + // ratio of URLRequests which have used a preconnected session. |
| + UMA_HISTOGRAM_BOOLEAN("Net.PreconnectedNavigation", was_preconnected); |
| +} |
| + |
| +void Predictor::PreconnectUsage::ObserveLinkNavigation(const GURL& url) { |
| + if (recent_navigation_chain_.empty() || |
| + url != recent_navigation_chain_.back()) { |
| + // The navigation chain is not available for this navigation. |
| + recent_navigation_chain_.clear(); |
| + recent_navigation_chain_.push_back(url); |
| + } |
| + |
| + // See if the link navigation involved preconnected session. |
| + bool did_use_preconnect = false; |
| + for (std::vector<GURL>::const_iterator it = recent_navigation_chain_.begin(); |
| + it != recent_navigation_chain_.end(); |
| + ++it) { |
| + GURL canonical_url(Predictor::CanonicalizeUrl(*it)); |
| + |
| + // Record the preconnect trigger for the url as used if exist |
| + MRUPreconnects::iterator itPreconnect = |
| + mru_preconnects_.Peek(canonical_url); |
| + bool was_preconnected = (itPreconnect != mru_preconnects_.end()); |
| + if (was_preconnected) |
| + did_use_preconnect = true; |
| + } |
| + |
| + UMA_HISTOGRAM_BOOLEAN("Net.PreconnectedLinkNavigations", did_use_preconnect); |
| +} |
| + |
| Predictor::Predictor(bool preconnect_enabled) |
| : url_request_context_getter_(NULL), |
| predictor_enabled_(true), |
| @@ -136,8 +268,6 @@ Predictor::Predictor(bool preconnect_enabled) |
| host_resolver_(NULL), |
| preconnect_enabled_(preconnect_enabled), |
| consecutive_omnibox_preconnect_count_(0), |
| - recent_preconnects_( |
| - TimeDelta::FromSeconds(kMaxUnusedSocketLifetimeSecondsWithoutAGet)), |
| next_trim_time_(base::TimeTicks::Now() + |
| TimeDelta::FromHours(kDurationBetweenTrimmingsHours)) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| @@ -668,6 +798,7 @@ void Predictor::FinalizeInitializationOnIOThread( |
| predictor_enabled_ = predictor_enabled; |
| initial_observer_.reset(new InitialObserver()); |
| host_resolver_ = io_thread->globals()->host_resolver.get(); |
| + preconnect_usage_.reset(new PreconnectUsage()); |
| // base::WeakPtrFactory instances need to be created and destroyed |
| // on the same thread. The predictor lives on the IO thread and will die |
| @@ -844,11 +975,10 @@ void Predictor::PreconnectUrl(const GURL& url, |
| } |
| void Predictor::PreconnectUrlOnIOThread( |
| - const GURL& url, const GURL& first_party_for_cookies, |
| - UrlInfo::ResolutionMotivation motivation, int count) { |
| - GURL canonical_url(CanonicalizeUrl(url)); |
| - recent_preconnects_.SetRecentlySeen(canonical_url); |
| - |
| + const GURL& url, |
| + const GURL& first_party_for_cookies, |
| + UrlInfo::ResolutionMotivation motivation, |
| + int count) { |
| PreconnectOnIOThread(url, |
| first_party_for_cookies, |
| motivation, |
| @@ -856,10 +986,54 @@ void Predictor::PreconnectUrlOnIOThread( |
| url_request_context_getter_.get()); |
| } |
| -void Predictor::RecordPreconnectNavigationStats(const GURL& url) { |
| - UMA_HISTOGRAM_BOOLEAN( |
| - "Net.PreconnectedNavigation", |
| - recent_preconnects_.WasRecentlySeen(url)); |
| +void Predictor::RecordPreconnectTrigger(const GURL& url) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || |
| + BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| + RecordPreconnectTriggerOnIOThread(url); |
| + } else { |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&Predictor::RecordPreconnectTriggerOnIOThread, |
| + base::Unretained(this), url)); |
| + } |
| +} |
| + |
| +void Predictor::RecordPreconnectTriggerOnIOThread(const GURL& url) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (preconnect_usage_) |
| + preconnect_usage_->ObservePreconnect(url); |
| +} |
| + |
| +void Predictor::RecordPreconnectNavigationStat( |
| + 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.
|
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + if (preconnect_usage_) |
| + preconnect_usage_->ObserveNavigationChain(url_chain, is_subresource); |
| +} |
| + |
| +void Predictor::RecordLinkNavigation(const GURL& url) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || |
| + BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| + RecordLinkNavigationOnIOThread(url); |
| + } else { |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&Predictor::RecordLinkNavigationOnIOThread, |
| + base::Unretained(this), url)); |
| + } |
| +} |
| + |
| +void Predictor::RecordLinkNavigationOnIOThread(const GURL& url) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (preconnect_usage_) |
| + preconnect_usage_->ObserveLinkNavigation(url); |
| } |
| void Predictor::PredictFrameSubresources(const GURL& url, |