blob: fabba4f5826023d91f540cf478726c0f1cee0798 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/prerender/prerender_histograms.h"
#include <string>
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "components/google/core/browser/google_util.h"
#include "net/http/http_cache.h"
namespace prerender {
namespace {
// This enum is used to define the buckets for the
// "Prerender.NoStatePrefetchResourceCount" histogram family.
// Hence, existing enumerated constants should never be deleted or reordered,
// and new constants should only be appended at the end of the enumeration.
enum NoStatePrefetchResponseType {
NO_STORE = 1 << 0,
REDIRECT = 1 << 1,
MAIN_RESOURCE = 1 << 2,
NO_STATE_PREFETCH_RESPONSE_TYPE_COUNT = 1 << 3
};
int GetResourceType(bool is_main_resource, bool is_redirect, bool is_no_store) {
return (is_no_store * NO_STORE) + (is_redirect * REDIRECT) +
(is_main_resource * MAIN_RESOURCE);
}
std::string ComposeHistogramName(const std::string& prefix_type,
const std::string& name) {
if (prefix_type.empty())
return std::string("Prerender.") + name;
return std::string("Prerender.") + prefix_type + std::string("_") + name;
}
std::string GetHistogramName(Origin origin, const std::string& name) {
switch (origin) {
case ORIGIN_OMNIBOX:
return ComposeHistogramName("omnibox", name);
case ORIGIN_NONE:
return ComposeHistogramName("none", name);
case ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN:
return ComposeHistogramName("websame", name);
case ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN:
return ComposeHistogramName("webcross", name);
case ORIGIN_EXTERNAL_REQUEST:
return ComposeHistogramName("externalrequest", name);
case ORIGIN_INSTANT:
return ComposeHistogramName("Instant", name);
case ORIGIN_LINK_REL_NEXT:
return ComposeHistogramName("webnext", name);
case ORIGIN_GWS_PRERENDER:
return ComposeHistogramName("gws", name);
case ORIGIN_EXTERNAL_REQUEST_FORCED_PRERENDER:
return ComposeHistogramName("externalrequestforced", name);
case ORIGIN_OFFLINE:
return ComposeHistogramName("offline", name);
default:
NOTREACHED();
break;
}
// Dummy return value to make the compiler happy.
NOTREACHED();
return ComposeHistogramName("none", name);
}
bool OriginIsOmnibox(Origin origin) {
return origin == ORIGIN_OMNIBOX;
}
const char* FirstContentfulPaintHiddenName(bool was_hidden) {
return was_hidden ? ".Hidden" : ".Visible";
}
} // namespace
// Helper macro for origin-based histogram reporting. All HISTOGRAM arguments
// must be UMA_HISTOGRAM... macros that contain an argument "name" which this
// macro will eventually substitute for the actual name used.
#define PREFIXED_HISTOGRAM(histogram_name, origin, HISTOGRAM) \
do { \
{ \
/* Do not rename. HISTOGRAM expects a local variable "name". */ \
std::string name = ComposeHistogramName(std::string(), histogram_name); \
HISTOGRAM; \
} \
/* Do not rename. HISTOGRAM expects a local variable "name". */ \
std::string name = GetHistogramName(origin, histogram_name); \
/* Branching because HISTOGRAM is caching the histogram into a static. */ \
if (origin == ORIGIN_OMNIBOX) { \
HISTOGRAM; \
} else if (origin == ORIGIN_NONE) { \
HISTOGRAM; \
} else if (origin == ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN) { \
HISTOGRAM; \
} else if (origin == ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN) { \
HISTOGRAM; \
} else if (origin == ORIGIN_EXTERNAL_REQUEST) { \
HISTOGRAM; \
} else if (origin == ORIGIN_INSTANT) { \
HISTOGRAM; \
} else if (origin == ORIGIN_LINK_REL_NEXT) { \
HISTOGRAM; \
} else if (origin == ORIGIN_EXTERNAL_REQUEST_FORCED_PRERENDER) { \
HISTOGRAM; \
} else if (origin == ORIGIN_OFFLINE) { \
HISTOGRAM; \
} else { \
HISTOGRAM; \
} \
} while (0)
PrerenderHistograms::PrerenderHistograms() {}
void PrerenderHistograms::RecordPrerenderStarted(Origin origin) const {
if (OriginIsOmnibox(origin)) {
UMA_HISTOGRAM_ENUMERATION(
"Prerender.OmniboxPrerenderCount", 1, 2);
}
}
void PrerenderHistograms::RecordUsedPrerender(Origin origin) const {
if (OriginIsOmnibox(origin)) {
UMA_HISTOGRAM_ENUMERATION(
"Prerender.OmniboxNavigationsUsedPrerenderCount", 1, 2);
}
}
void PrerenderHistograms::RecordTimeSinceLastRecentVisit(
Origin origin,
base::TimeDelta delta) const {
PREFIXED_HISTOGRAM(
"TimeSinceLastRecentVisit", origin,
UMA_HISTOGRAM_TIMES(name, delta));
}
void PrerenderHistograms::RecordPerceivedFirstContentfulPaintStatus(
Origin origin,
bool successful,
bool was_hidden) const {
base::UmaHistogramBoolean(GetHistogramName(origin, "PerceivedTTFCPRecorded") +
FirstContentfulPaintHiddenName(was_hidden),
successful);
}
void PrerenderHistograms::RecordPercentLoadDoneAtSwapin(Origin origin,
double fraction) const {
if (fraction < 0.0 || fraction > 1.0)
return;
int percentage = static_cast<int>(fraction * 100);
if (percentage < 0 || percentage > 100)
return;
PREFIXED_HISTOGRAM("PercentLoadDoneAtSwapin",
origin, UMA_HISTOGRAM_PERCENTAGE(name, percentage));
}
void PrerenderHistograms::RecordTimeUntilUsed(
Origin origin,
base::TimeDelta time_until_used) const {
PREFIXED_HISTOGRAM(
"TimeUntilUsed2", origin,
UMA_HISTOGRAM_CUSTOM_TIMES(
name,
time_until_used,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromMinutes(30),
50));
}
void PrerenderHistograms::RecordAbandonTimeUntilUsed(
Origin origin,
base::TimeDelta time_until_used) const {
PREFIXED_HISTOGRAM(
"AbandonTimeUntilUsed", origin,
UMA_HISTOGRAM_CUSTOM_TIMES(
name,
time_until_used,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromSeconds(30),
50));
}
void PrerenderHistograms::RecordPerSessionCount(Origin origin,
int count) const {
PREFIXED_HISTOGRAM(
"PrerendersPerSessionCount", origin,
UMA_HISTOGRAM_COUNTS(name, count));
}
void PrerenderHistograms::RecordTimeBetweenPrerenderRequests(
Origin origin, base::TimeDelta time) const {
PREFIXED_HISTOGRAM(
"TimeBetweenPrerenderRequests", origin,
UMA_HISTOGRAM_TIMES(name, time));
}
void PrerenderHistograms::RecordFinalStatus(
Origin origin,
FinalStatus final_status) const {
DCHECK(final_status != FINAL_STATUS_MAX);
PREFIXED_HISTOGRAM(
"FinalStatus", origin,
UMA_HISTOGRAM_ENUMERATION(name, final_status, FINAL_STATUS_MAX));
}
void PrerenderHistograms::RecordNetworkBytes(Origin origin,
bool used,
int64_t prerender_bytes,
int64_t profile_bytes) const {
const int kHistogramMin = 1;
const int kHistogramMax = 100000000; // 100M.
const int kBucketCount = 50;
UMA_HISTOGRAM_CUSTOM_COUNTS("Prerender.NetworkBytesTotalForProfile",
profile_bytes,
kHistogramMin,
1000000000, // 1G
kBucketCount);
if (prerender_bytes == 0)
return;
if (used) {
PREFIXED_HISTOGRAM(
"NetworkBytesUsed",
origin,
UMA_HISTOGRAM_CUSTOM_COUNTS(
name, prerender_bytes, kHistogramMin, kHistogramMax, kBucketCount));
} else {
PREFIXED_HISTOGRAM(
"NetworkBytesWasted",
origin,
UMA_HISTOGRAM_CUSTOM_COUNTS(
name, prerender_bytes, kHistogramMin, kHistogramMax, kBucketCount));
}
}
void PrerenderHistograms::RecordPrefetchResponseReceived(
Origin origin,
bool is_main_resource,
bool is_redirect,
bool is_no_store) const {
DCHECK(thread_checker_.CalledOnValidThread());
int sample = GetResourceType(is_main_resource, is_redirect, is_no_store);
std::string histogram_name =
GetHistogramName(origin, "NoStatePrefetchResponseTypes");
base::UmaHistogramExactLinear(histogram_name, sample,
NO_STATE_PREFETCH_RESPONSE_TYPE_COUNT);
}
void PrerenderHistograms::RecordPrefetchRedirectCount(
Origin origin,
bool is_main_resource,
int redirect_count) const {
DCHECK(thread_checker_.CalledOnValidThread());
const int kMaxRedirectCount = 10;
std::string histogram_base_name = base::StringPrintf(
"NoStatePrefetch%sResourceRedirects", is_main_resource ? "Main" : "Sub");
std::string histogram_name = GetHistogramName(origin, histogram_base_name);
base::UmaHistogramExactLinear(histogram_name, redirect_count,
kMaxRedirectCount);
}
void PrerenderHistograms::RecordPrefetchFirstContentfulPaintTime(
Origin origin,
bool is_no_store,
bool was_hidden,
base::TimeDelta time,
base::TimeDelta prefetch_age) const {
DCHECK(thread_checker_.CalledOnValidThread());
if (!prefetch_age.is_zero()) {
DCHECK_NE(origin, ORIGIN_NONE);
base::UmaHistogramCustomTimes(GetHistogramName(origin, "PrefetchAge"),
prefetch_age,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromMinutes(30), 50);
}
std::string histogram_base_name;
if (prefetch_age.is_zero()) {
histogram_base_name = "PrefetchTTFCP.Reference";
} else {
histogram_base_name = prefetch_age < base::TimeDelta::FromMinutes(
net::HttpCache::kPrefetchReuseMins)
? "PrefetchTTFCP.Warm"
: "PrefetchTTFCP.Cold";
}
histogram_base_name += is_no_store ? ".NoStore" : ".Cacheable";
histogram_base_name += FirstContentfulPaintHiddenName(was_hidden);
std::string histogram_name = GetHistogramName(origin, histogram_base_name);
base::UmaHistogramCustomTimes(histogram_name, time,
base::TimeDelta::FromMilliseconds(10),
base::TimeDelta::FromMinutes(2), 50);
}
} // namespace prerender