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

Unified 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, 5 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 side-by-side diff with in-line comments
Download patch
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,

Powered by Google App Engine
This is Rietveld 408576698