| Index: chrome/browser/net/predictor.cc
|
| diff --git a/chrome/browser/net/predictor.cc b/chrome/browser/net/predictor.cc
|
| index 6bedafb1b9b54ee2bb44123167c200e9b9591065..9d72d41fafde20b2654f21587fe57f0fb170581b 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,137 @@ class Predictor::LookupRequest {
|
| DISALLOW_COPY_AND_ASSIGN(LookupRequest);
|
| };
|
|
|
| +// This records UMAs for preconnect usage based on navigation URLs to
|
| +// gather precision/recall for user-event based preconnect triggers.
|
| +// Stats are gathered via a LRU cache that remembers all preconnect within the
|
| +// 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
|
| +// 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.
|
| + 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.
|
| + 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) {
|
| + 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 +269,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 +799,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,10 +976,12 @@ 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) {
|
| + if (motivation == UrlInfo::MOUSE_OVER_MOTIVATED)
|
| + RecordPreconnectTrigger(url);
|
|
|
| PreconnectOnIOThread(url,
|
| first_party_for_cookies,
|
| @@ -856,10 +990,25 @@ 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::IO));
|
| + if (preconnect_usage_)
|
| + preconnect_usage_->ObservePreconnect(url);
|
| +}
|
| +
|
| +void Predictor::RecordPreconnectNavigationStat(
|
| + const std::vector<GURL>& url_chain,
|
| + bool is_subresource) {
|
| + 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::IO));
|
| + if (preconnect_usage_)
|
| + preconnect_usage_->ObserveLinkNavigation(url);
|
| }
|
|
|
| void Predictor::PredictFrameSubresources(const GURL& url,
|
|
|