diff options
author | tburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-27 17:32:48 +0000 |
---|---|---|
committer | tburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-07-27 17:32:48 +0000 |
commit | 8f201ee54cd4f0a87e7bc23e5dfd45d1536c61bf (patch) | |
tree | ef386a18d482c08811bbe230c60af9cfe7baf692 | |
parent | 10cf90db54510761424e16498da14889fdc7805e (diff) | |
download | chromium_src-8f201ee54cd4f0a87e7bc23e5dfd45d1536c61bf.zip chromium_src-8f201ee54cd4f0a87e7bc23e5dfd45d1536c61bf.tar.gz chromium_src-8f201ee54cd4f0a87e7bc23e5dfd45d1536c61bf.tar.bz2 |
Add histograms to record how effective prerendering would be based on
the user hovering over links.
R=dominich@chromium.org, cbentzel@chromium.org
Review URL: http://codereview.chromium.org/7472018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@94314 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/prerender/prerender_observer.cc | 196 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_observer.h | 23 |
2 files changed, 215 insertions, 4 deletions
diff --git a/chrome/browser/prerender/prerender_observer.cc b/chrome/browser/prerender/prerender_observer.cc index 5bcd38b..af6ce6b 100644 --- a/chrome/browser/prerender/prerender_observer.cc +++ b/chrome/browser/prerender/prerender_observer.cc @@ -4,6 +4,8 @@ #include "chrome/browser/prerender/prerender_observer.h" +#include "base/metrics/histogram.h" +#include "base/string_number_conversions.h" #include "base/time.h" #include "chrome/browser/prerender/prerender_manager.h" #include "chrome/browser/profiles/profile.h" @@ -13,10 +15,159 @@ namespace prerender { +namespace { + +const int kMinHoverThresholdsMs[] = { + 50, + 75, + 100, + 150, + 200, + 250, + 300, + 400, + 500, + 750, + 1000 +}; + +// Overview of hover-related histograms: +// -- count of hover start +// -- count of hover too short. +// difference between these is pages prerendered +// -- count of prerender used +// -- time from hover commence until click (subtract hover threshold +// from that value to figure out average savings). + +enum HoverEvents { + HOVER_EVENT_START = 0, + HOVER_EVENT_TOO_SHORT = 1, + HOVER_EVENT_REPLACED = 2, + HOVER_EVENT_CLICK = 3, + HOVER_EVENT_MAX +}; + +const int kNumHoverThresholds = arraysize(kMinHoverThresholdsMs); + +class PerHoverThresholdHistograms { + public: + explicit PerHoverThresholdHistograms(int hover_threshold_ms) { + std::string prefix = std::string("Prerender.HoverStats_") + + base::IntToString(hover_threshold_ms) + std::string("_"); + count_hover_events_ = base::LinearHistogram::FactoryGet( + prefix + std::string("Events"), + 1, + HOVER_EVENT_MAX, + HOVER_EVENT_MAX + 1, + base::Histogram::kUmaTargetedHistogramFlag); + time_hover_until_click_ = base::Histogram::FactoryTimeGet( + prefix + std::string("TimeToClick"), + base::TimeDelta::FromMilliseconds(1), + base::TimeDelta::FromSeconds(60), + 100, + base::Histogram::kUmaTargetedHistogramFlag); + } + base::Histogram* count_hover_events() { return count_hover_events_; } + base::Histogram* time_hover_until_click() { return time_hover_until_click_; } + + private: + base::Histogram* count_hover_events_; + base::Histogram* time_hover_until_click_; +}; + +} // namespace + +class PrerenderObserver::HoverData { + public: + void SetHoverThreshold(int threshold_ms) { + hover_threshold_ = base::TimeDelta::FromMilliseconds(threshold_ms); + histograms_.reset(new PerHoverThresholdHistograms(threshold_ms)); + } + + void RecordHover(const GURL& url) { + VerifyInitialized(); + + MaybeStartedPrerendering(); + + // Ignore duplicate hover messages. + if (new_url_ == url) + return; + + if (!new_url_.is_empty()) + histograms_->count_hover_events()->Add(HOVER_EVENT_TOO_SHORT); + + if (current_url_ == url) { + // If we came back to URL currently being prerendered, we don't need + // to "remember" to start prerendering, because we already have that + // URL prerendered. + new_url_ = GURL(); + } else { + // Otherwise, we remember this new URL as something we might soon + // start prerendering. + new_url_ = url; + new_time_ = base::TimeTicks::Now(); + } + + if (!new_url_.is_empty()) + histograms_->count_hover_events()->Add(HOVER_EVENT_START); + } + + void RecordNavigation(const GURL& url) { + VerifyInitialized(); + + // Artifically call RecordHover with an empty URL to accomplish two things: + // -- ensure we update what we are currently prerendering + // -- record if there is a pending new hover, that we "exited" it, + // thereby recording an EVENT_TOO_SHORT for it. + RecordHover(GURL()); + + if (current_url_ == url) { + // Match. We would have started prerendering the new URL. + histograms_->count_hover_events()->Add(HOVER_EVENT_CLICK); + histograms_->time_hover_until_click()->AddTime( + base::TimeTicks::Now() - current_time_); + current_url_ = GURL(); + } + } + + private: + void VerifyInitialized() { + DCHECK(histograms_.get() != NULL); + } + + void MaybeStartedPrerendering() { + if (!new_url_.is_empty() && + base::TimeTicks::Now() - new_time_ > hover_threshold_) { + if (!current_url_.is_empty()) + histograms_->count_hover_events()->Add(HOVER_EVENT_REPLACED); + current_url_ = new_url_; + current_time_ = new_time_; + new_url_ = GURL(); + } + } + + scoped_ptr<PerHoverThresholdHistograms> histograms_; + + // The time & url of the hover that is currently being prerendered. + base::TimeTicks current_time_; + GURL current_url_; + + // The time & url of a new hover that does not meet the threshold for + // prerendering and may replace the prerender currently being prerendered. + base::TimeTicks new_time_; + GURL new_url_; + + // The threshold for hovering. + base::TimeDelta hover_threshold_; +}; + PrerenderObserver::PrerenderObserver(TabContentsWrapper* tab) : TabContentsObserver(tab->tab_contents()), tab_(tab), - pplt_load_start_() { + pplt_load_start_(), + last_hovers_(new HoverData[kNumHoverThresholds]) { + for (int i = 0; i < kNumHoverThresholds; i++) + last_hovers_[i].SetHoverThreshold(kMinHoverThresholdsMs[i]); } PrerenderObserver::~PrerenderObserver() { @@ -39,6 +190,7 @@ bool PrerenderObserver::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(PrerenderObserver, message) IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartProvisionalLoadForFrame, OnDidStartProvisionalLoadForFrame) + IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateTargetURL, OnMsgUpdateTargetURL) IPC_END_MESSAGE_MAP() return false; } @@ -50,6 +202,23 @@ void PrerenderObserver::OnDidStartProvisionalLoadForFrame(int64 frame_id, if (is_main_frame) { // Record the beginning of a new PPLT navigation. pplt_load_start_ = base::TimeTicks::Now(); + + // Update hover stats. + for (int i = 0; i < kNumHoverThresholds; i++) + last_hovers_[i].RecordNavigation(url); + + MaybeLogCurrentHover(current_hover_url_ == url); + } +} + +void PrerenderObserver::OnMsgUpdateTargetURL(int32 page_id, const GURL& url) { + for (int i = 0; i < kNumHoverThresholds; i++) + last_hovers_[i].RecordHover(url); + + if (url != current_hover_url_) { + MaybeLogCurrentHover(false); + current_hover_url_ = url; + current_hover_time_ = base::TimeTicks::Now(); } } @@ -102,4 +271,29 @@ void PrerenderObserver::PrerenderSwappedIn() { } } +void PrerenderObserver::MaybeLogCurrentHover(bool was_used) { + if (current_hover_url_.is_empty()) + return; + + static const int64 min_ms = 0; + static const int64 max_ms = 2000; + static const int num_buckets = 100; + + int64 elapsed_ms = + (base::TimeTicks::Now() - current_hover_time_).InMilliseconds(); + + elapsed_ms = std::min(std::max(elapsed_ms, min_ms), max_ms); + elapsed_ms /= max_ms / num_buckets; + + if (was_used) { + UMA_HISTOGRAM_ENUMERATION("Prerender.HoverStats_TimeUntilClicked", + elapsed_ms, num_buckets); + } else { + UMA_HISTOGRAM_ENUMERATION("Prerender.HoverStats_TimeUntilDiscarded", + elapsed_ms, num_buckets); + } + + current_hover_url_ = GURL(); +} + } // namespace prerender diff --git a/chrome/browser/prerender/prerender_observer.h b/chrome/browser/prerender/prerender_observer.h index d851191..d4174cb 100644 --- a/chrome/browser/prerender/prerender_observer.h +++ b/chrome/browser/prerender/prerender_observer.h @@ -30,16 +30,21 @@ class PrerenderObserver : public TabContentsObserver { virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; virtual void DidStopLoading() OVERRIDE; + // Called when this prerendered TabContents has just been swapped in. + void PrerenderSwappedIn(); + + private: + // The data we store for a hover (time the hover occurred & URL). + class HoverData; + // Message handler. void OnDidStartProvisionalLoadForFrame(int64 frame_id, bool main_frame, bool has_opener_set, const GURL& url); - // Called when this prerendered TabContents has just been swapped in. - void PrerenderSwappedIn(); + void OnMsgUpdateTargetURL(int32 page_id, const GURL& url); - private: // Retrieves the PrerenderManager, or NULL, if none was found. PrerenderManager* MaybeGetPrerenderManager(); @@ -51,6 +56,11 @@ class PrerenderObserver : public TabContentsObserver { // Returns whether the TabContents being observed is currently prerendering. bool IsPrerendering(); + // Records histogram information for the current hover, based on whether + // it was used or not. Will not do anything if there is no current hover. + // Also resets the hover to no hover. + void MaybeLogCurrentHover(bool was_used); + // TabContentsWrapper we're created for. TabContentsWrapper* tab_; @@ -58,6 +68,13 @@ class PrerenderObserver : public TabContentsObserver { // the perceived page load time (PPLT). base::TimeTicks pplt_load_start_; + // Information about the last hover for each hover threshold. + scoped_array<HoverData> last_hovers_; + + // Information about the current hover independent of thresholds. + GURL current_hover_url_; + base::TimeTicks current_hover_time_; + DISALLOW_COPY_AND_ASSIGN(PrerenderObserver); }; |