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

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: 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 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 b7061c748b6479e801c1d9eacb63744ae752df38..d217650a34138f9531286dcae4bc5bd5222ad7b7 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,129 @@ 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 two LRU caches that remembers all preconnect and
+// user link navigations 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 the url.
+ void ObservePreconnect(const GURL& url);
+
+ // Record a user link navigation to the url.
+ void ObserveNavigation(const GURL& url, const GURL& original_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_;
+
+ // This tracks whether a navigation used a preconnected session or not
+ class PreconnectRecallStat {
+ public:
+ PreconnectRecallStat()
+ : timestamp_(base::TimeTicks::Now()),
+ did_use_preconnect_(false) {
+ }
+
+ const base::TimeTicks& timestamp() { return timestamp_; }
+
+ void set_did_use_preconnect() { did_use_preconnect_ = true; }
+ bool did_use_preconnect() const { return did_use_preconnect_; }
+
+ private:
+ base::TimeTicks timestamp_;
+ bool did_use_preconnect_;
+ };
+
+ typedef base::MRUCache<GURL, PreconnectRecallStat> MRUNavigations;
+ MRUNavigations mru_navigations_;
+
+ // The longest time an entry can persist in mru_preconnect_/mru_navigations_
+ const base::TimeDelta max_duration_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreconnectUsage);
+};
+
+Predictor::PreconnectUsage::PreconnectUsage()
+ : mru_preconnects_(MRUPreconnects::NO_AUTO_EVICT),
+ mru_navigations_(MRUNavigations::NO_AUTO_EVICT),
+ max_duration_(base::TimeDelta::FromSeconds(
+ Predictor::kMaxUnusedSocketLifetimeSecondsWithoutAGet)) {
+}
+
+Predictor::PreconnectUsage::~PreconnectUsage() {}
+
+void Predictor::PreconnectUsage::ObservePreconnect(const GURL& url) {
+ GURL canonical_url(Predictor::CanonicalizeUrl(url));
+ mru_preconnects_.Put(canonical_url, PreconnectPrecisionStat());
+}
+
+void Predictor::PreconnectUsage::ObserveNavigation(const GURL& url,
+ const GURL& original_url) {
+ GURL canonical_url(Predictor::CanonicalizeUrl(url));
+
+ // Evict any overly old entries and record stats
+ base::TimeTicks now = base::TimeTicks::Now();
+
+ MRUPreconnects::reverse_iterator eldestPreconnect = mru_preconnects_.rbegin();
+ while (!mru_preconnects_.empty()) {
+ DCHECK(eldestPreconnect == mru_preconnects_.rbegin());
+ if (now - eldestPreconnect->second.timestamp() < max_duration_)
+ break;
+
+ UMA_HISTOGRAM_BOOLEAN("Net.PreconnectTriggerUsed",
+ eldestPreconnect->second.was_used());
+ eldestPreconnect = mru_preconnects_.Erase(eldestPreconnect);
+ }
+
+ MRUNavigations::reverse_iterator eldestNavigation = mru_navigations_.rbegin();
+ while (!mru_navigations_.empty()) {
+ DCHECK(eldestNavigation == mru_navigations_.rbegin());
+ if (now - eldestNavigation->second.timestamp() < max_duration_)
+ break;
+
+ UMA_HISTOGRAM_BOOLEAN("Net.PreconnectedNavigation",
+ eldestNavigation->second.did_use_preconnect());
+ eldestNavigation = mru_navigations_.Erase(eldestNavigation);
+ }
+
+ // Record the preconnect trigger for the url as used if exist
+ MRUNavigations::iterator itNavigation = mru_navigations_.Peek(original_url);
+ if (itNavigation == mru_navigations_.end())
+ itNavigation = mru_navigations_.Put(original_url, PreconnectRecallStat());
+
+ MRUPreconnects::iterator itPreconnect = mru_preconnects_.Peek(canonical_url);
+ bool wasPreconnected = (itPreconnect != mru_preconnects_.end());
+ if (wasPreconnected) {
+ itPreconnect->second.set_was_used();
+ itNavigation->second.set_did_use_preconnect();
+ }
+}
+
Predictor::Predictor(bool preconnect_enabled)
: url_request_context_getter_(NULL),
predictor_enabled_(true),
@@ -136,8 +261,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));
@@ -667,6 +790,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
@@ -845,9 +969,6 @@ 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);
-
PreconnectOnIOThread(url,
first_party_for_cookies,
motivation,
@@ -855,10 +976,30 @@ 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));
+ preconnect_usage_->ObservePreconnect(url);
+}
+
+void Predictor::RecordPreconnectNavigationStat(const GURL& url,
+ const GURL& original_url) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ preconnect_usage_->ObserveNavigation(url, original_url);
}
void Predictor::PredictFrameSubresources(const GURL& url,

Powered by Google App Engine
This is Rietveld 408576698