summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-27 17:32:48 +0000
committertburkard@chromium.org <tburkard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-27 17:32:48 +0000
commit8f201ee54cd4f0a87e7bc23e5dfd45d1536c61bf (patch)
treeef386a18d482c08811bbe230c60af9cfe7baf692
parent10cf90db54510761424e16498da14889fdc7805e (diff)
downloadchromium_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.cc196
-rw-r--r--chrome/browser/prerender/prerender_observer.h23
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);
};