Give names to all utility processes.
[chromium-blink-merge.git] / chrome / browser / prerender / prerender_histograms.cc
blob69e4ca7ed57b12bde1fdca5c081a92731ded7830
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/prerender/prerender_histograms.h"
7 #include <string>
9 #include "base/format_macros.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/stringprintf.h"
12 #include "chrome/browser/predictors/autocomplete_action_predictor.h"
13 #include "chrome/browser/prerender/prerender_manager.h"
14 #include "chrome/browser/prerender/prerender_util.h"
16 using predictors::AutocompleteActionPredictor;
18 namespace prerender {
20 namespace {
22 // Time window for which we will record windowed PLTs from the last observed
23 // link rel=prefetch tag. This is not intended to be the same as the prerender
24 // ttl, it's just intended to be a window during which a prerender has likely
25 // affected performance.
26 const int kWindowDurationSeconds = 30;
28 std::string ComposeHistogramName(const std::string& prefix_type,
29 const std::string& name) {
30 if (prefix_type.empty())
31 return std::string("Prerender.") + name;
32 return std::string("Prerender.") + prefix_type + std::string("_") + name;
35 std::string GetHistogramName(Origin origin, uint8 experiment_id,
36 bool is_wash, const std::string& name) {
37 if (is_wash)
38 return ComposeHistogramName("wash", name);
40 if (origin == ORIGIN_GWS_PRERENDER) {
41 if (experiment_id == kNoExperiment)
42 return ComposeHistogramName("gws", name);
43 return ComposeHistogramName("exp" + std::string(1, experiment_id + '0'),
44 name);
47 if (experiment_id != kNoExperiment)
48 return ComposeHistogramName("wash", name);
50 switch (origin) {
51 case ORIGIN_OMNIBOX:
52 return ComposeHistogramName("omnibox", name);
53 case ORIGIN_NONE:
54 return ComposeHistogramName("none", name);
55 case ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN:
56 return ComposeHistogramName("websame", name);
57 case ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN:
58 return ComposeHistogramName("webcross", name);
59 case ORIGIN_LOCAL_PREDICTOR:
60 return ComposeHistogramName("localpredictor", name);
61 case ORIGIN_EXTERNAL_REQUEST:
62 return ComposeHistogramName("externalrequest", name);
63 case ORIGIN_INSTANT:
64 return ComposeHistogramName("Instant", name);
65 case ORIGIN_LINK_REL_NEXT:
66 return ComposeHistogramName("webnext", name);
67 case ORIGIN_GWS_PRERENDER: // Handled above.
68 default:
69 NOTREACHED();
70 break;
73 // Dummy return value to make the compiler happy.
74 NOTREACHED();
75 return ComposeHistogramName("wash", name);
78 bool OriginIsOmnibox(Origin origin) {
79 return origin == ORIGIN_OMNIBOX;
82 } // namespace
84 // Helper macros for experiment-based and origin-based histogram reporting.
85 // All HISTOGRAM arguments must be UMA_HISTOGRAM... macros that contain an
86 // argument "name" which these macros will eventually substitute for the
87 // actual name used.
88 #define PREFIXED_HISTOGRAM(histogram_name, origin, HISTOGRAM) \
89 PREFIXED_HISTOGRAM_INTERNAL(origin, GetCurrentExperimentId(), \
90 IsOriginExperimentWash(), HISTOGRAM, \
91 histogram_name)
93 #define PREFIXED_HISTOGRAM_ORIGIN_EXPERIMENT(histogram_name, origin, \
94 experiment, HISTOGRAM) \
95 PREFIXED_HISTOGRAM_INTERNAL(origin, experiment, false, HISTOGRAM, \
96 histogram_name)
98 #define PREFIXED_HISTOGRAM_INTERNAL(origin, experiment, wash, HISTOGRAM, \
99 histogram_name) do { \
101 /* Do not rename. HISTOGRAM expects a local variable "name". */ \
102 std::string name = ComposeHistogramName(std::string(), histogram_name); \
103 HISTOGRAM; \
105 /* Do not rename. HISTOGRAM expects a local variable "name". */ \
106 std::string name = GetHistogramName(origin, experiment, wash, \
107 histogram_name); \
108 /* Usually, a browsing session should only have a single experiment. */ \
109 /* Therefore, when there is a second experiment ID other than the one */ \
110 /* being recorded, don't record anything. */ \
111 /* Furthermore, experiments only apply if the origin is GWS. Should there */ \
112 /* somehow be an experiment ID if the origin is not GWS, ignore the */ \
113 /* experiment ID. */ \
114 static uint8 recording_experiment = kNoExperiment; \
115 if (recording_experiment == kNoExperiment && experiment != kNoExperiment) \
116 recording_experiment = experiment; \
117 if (wash) { \
118 HISTOGRAM; \
119 } else if (experiment != kNoExperiment && \
120 (origin != ORIGIN_GWS_PRERENDER || \
121 experiment != recording_experiment)) { \
122 } else if (origin == ORIGIN_OMNIBOX) { \
123 HISTOGRAM; \
124 } else if (origin == ORIGIN_NONE) { \
125 HISTOGRAM; \
126 } else if (origin == ORIGIN_LINK_REL_PRERENDER_SAMEDOMAIN) { \
127 HISTOGRAM; \
128 } else if (origin == ORIGIN_LINK_REL_PRERENDER_CROSSDOMAIN) { \
129 HISTOGRAM; \
130 } else if (origin == ORIGIN_LOCAL_PREDICTOR) { \
131 HISTOGRAM; \
132 } else if (origin == ORIGIN_EXTERNAL_REQUEST) { \
133 HISTOGRAM; \
134 } else if (origin == ORIGIN_INSTANT) { \
135 HISTOGRAM; \
136 } else if (origin == ORIGIN_LINK_REL_NEXT) { \
137 HISTOGRAM; \
138 } else if (experiment != kNoExperiment) { \
139 HISTOGRAM; \
140 } else { \
141 HISTOGRAM; \
143 } while (0)
145 PrerenderHistograms::PrerenderHistograms()
146 : last_experiment_id_(kNoExperiment),
147 last_origin_(ORIGIN_MAX),
148 origin_experiment_wash_(false),
149 seen_any_pageload_(true),
150 seen_pageload_started_after_prerender_(true) {
153 void PrerenderHistograms::RecordPrerender(Origin origin, const GURL& url) {
154 // Check if we are doing an experiment.
155 uint8 experiment = GetQueryStringBasedExperiment(url);
157 // We need to update last_experiment_id_, last_origin_, and
158 // origin_experiment_wash_.
159 if (!WithinWindow()) {
160 // If we are outside a window, this is a fresh start and we are fine,
161 // and there is no mix.
162 origin_experiment_wash_ = false;
163 } else {
164 // If we are inside the last window, there is a mish mash of origins
165 // and experiments if either there was a mish mash before, or the current
166 // experiment/origin does not match the previous one.
167 if (experiment != last_experiment_id_ || origin != last_origin_)
168 origin_experiment_wash_ = true;
171 last_origin_ = origin;
172 last_experiment_id_ = experiment;
174 // If we observe multiple tags within the 30 second window, we will still
175 // reset the window to begin at the most recent occurrence, so that we will
176 // always be in a window in the 30 seconds from each occurrence.
177 last_prerender_seen_time_ = GetCurrentTimeTicks();
178 seen_any_pageload_ = false;
179 seen_pageload_started_after_prerender_ = false;
182 void PrerenderHistograms::RecordPrerenderStarted(Origin origin) const {
183 if (OriginIsOmnibox(origin)) {
184 UMA_HISTOGRAM_ENUMERATION(
185 base::StringPrintf("Prerender.OmniboxPrerenderCount%s",
186 PrerenderManager::GetModeString()), 1, 2);
190 void PrerenderHistograms::RecordConcurrency(size_t prerender_count) const {
191 static const size_t kMaxRecordableConcurrency = 20;
192 DCHECK_GE(kMaxRecordableConcurrency, Config().max_link_concurrency);
193 UMA_HISTOGRAM_ENUMERATION(
194 base::StringPrintf("Prerender.PrerenderCountOf%" PRIuS "Max",
195 kMaxRecordableConcurrency),
196 prerender_count, kMaxRecordableConcurrency + 1);
199 void PrerenderHistograms::RecordUsedPrerender(Origin origin) const {
200 if (OriginIsOmnibox(origin)) {
201 UMA_HISTOGRAM_ENUMERATION(
202 base::StringPrintf("Prerender.OmniboxNavigationsUsedPrerenderCount%s",
203 PrerenderManager::GetModeString()), 1, 2);
207 void PrerenderHistograms::RecordTimeSinceLastRecentVisit(
208 Origin origin,
209 base::TimeDelta delta) const {
210 PREFIXED_HISTOGRAM(
211 "TimeSinceLastRecentVisit", origin,
212 UMA_HISTOGRAM_TIMES(name, delta));
215 base::TimeTicks PrerenderHistograms::GetCurrentTimeTicks() const {
216 return base::TimeTicks::Now();
219 // Helper macro for histograms.
220 #define RECORD_PLT(tag, perceived_page_load_time) \
221 PREFIXED_HISTOGRAM( \
222 tag, origin, \
223 UMA_HISTOGRAM_CUSTOM_TIMES( \
224 name, \
225 perceived_page_load_time, \
226 base::TimeDelta::FromMilliseconds(10), \
227 base::TimeDelta::FromSeconds(60), \
228 100))
230 // Summary of all histograms Perceived PLT histograms:
231 // (all prefixed PerceivedPLT)
232 // PerceivedPLT -- Perceived Pageloadtimes (PPLT) for all pages in the group.
233 // ...Windowed -- PPLT for pages in the 30s after a prerender is created.
234 // ...Matched -- A prerendered page that was swapped in. In the NoUse
235 // and Control group cases, while nothing ever gets swapped in, we do keep
236 // track of what would be prerendered and would be swapped in -- and those
237 // cases are what is classified as Match for these groups.
238 // ...MatchedComplete -- A prerendered page that was swapped in + a few
239 // that were not swapped in so that the set of pages lines up more closely with
240 // the control group.
241 // ...FirstAfterMiss -- First page to finish loading after a prerender, which
242 // is different from the page that was prerendered.
243 // ...FirstAfterMissNonOverlapping -- Same as FirstAfterMiss, but only
244 // triggering for the first page to finish after the prerender that also started
245 // after the prerender started.
246 // ...FirstAfterMissBoth -- pages meeting
247 // FirstAfterMiss AND FirstAfterMissNonOverlapping
248 // ...FirstAfterMissAnyOnly -- pages meeting
249 // FirstAfterMiss but NOT FirstAfterMissNonOverlapping
250 // ..FirstAfterMissNonOverlappingOnly -- pages meeting
251 // FirstAfterMissNonOverlapping but NOT FirstAfterMiss
253 void PrerenderHistograms::RecordPerceivedPageLoadTime(
254 Origin origin,
255 base::TimeDelta perceived_page_load_time,
256 NavigationType navigation_type,
257 const GURL& url) {
258 if (!url.SchemeIsHTTPOrHTTPS())
259 return;
260 bool within_window = WithinWindow();
261 bool is_google_url = IsGoogleDomain(url);
262 RECORD_PLT("PerceivedPLT", perceived_page_load_time);
263 if (within_window)
264 RECORD_PLT("PerceivedPLTWindowed", perceived_page_load_time);
265 if (navigation_type != NAVIGATION_TYPE_NORMAL) {
266 DCHECK(navigation_type == NAVIGATION_TYPE_WOULD_HAVE_BEEN_PRERENDERED ||
267 navigation_type == NAVIGATION_TYPE_PRERENDERED);
268 RECORD_PLT("PerceivedPLTMatchedComplete", perceived_page_load_time);
269 if (navigation_type == NAVIGATION_TYPE_PRERENDERED)
270 RECORD_PLT("PerceivedPLTMatched", perceived_page_load_time);
271 seen_any_pageload_ = true;
272 seen_pageload_started_after_prerender_ = true;
273 } else if (within_window) {
274 RECORD_PLT("PerceivedPLTWindowNotMatched", perceived_page_load_time);
275 if (!is_google_url) {
276 bool recorded_any = false;
277 bool recorded_non_overlapping = false;
278 if (!seen_any_pageload_) {
279 seen_any_pageload_ = true;
280 RECORD_PLT("PerceivedPLTFirstAfterMiss", perceived_page_load_time);
281 recorded_any = true;
283 if (!seen_pageload_started_after_prerender_ &&
284 perceived_page_load_time <= GetTimeSinceLastPrerender()) {
285 seen_pageload_started_after_prerender_ = true;
286 RECORD_PLT("PerceivedPLTFirstAfterMissNonOverlapping",
287 perceived_page_load_time);
288 recorded_non_overlapping = true;
290 if (recorded_any || recorded_non_overlapping) {
291 if (recorded_any && recorded_non_overlapping) {
292 RECORD_PLT("PerceivedPLTFirstAfterMissBoth",
293 perceived_page_load_time);
294 } else if (recorded_any) {
295 RECORD_PLT("PerceivedPLTFirstAfterMissAnyOnly",
296 perceived_page_load_time);
297 } else if (recorded_non_overlapping) {
298 RECORD_PLT("PerceivedPLTFirstAfterMissNonOverlappingOnly",
299 perceived_page_load_time);
306 void PrerenderHistograms::RecordPageLoadTimeNotSwappedIn(
307 Origin origin,
308 base::TimeDelta page_load_time,
309 const GURL& url) const {
310 // If the URL to be prerendered is not a http[s] URL, or is a Google URL,
311 // do not record.
312 if (!url.SchemeIsHTTPOrHTTPS() || IsGoogleDomain(url))
313 return;
314 RECORD_PLT("PrerenderNotSwappedInPLT", page_load_time);
317 void PrerenderHistograms::RecordPercentLoadDoneAtSwapin(Origin origin,
318 double fraction) const {
319 if (fraction < 0.0 || fraction > 1.0)
320 return;
321 int percentage = static_cast<int>(fraction * 100);
322 if (percentage < 0 || percentage > 100)
323 return;
324 PREFIXED_HISTOGRAM("PercentLoadDoneAtSwapin",
325 origin, UMA_HISTOGRAM_PERCENTAGE(name, percentage));
328 base::TimeDelta PrerenderHistograms::GetTimeSinceLastPrerender() const {
329 return base::TimeTicks::Now() - last_prerender_seen_time_;
332 bool PrerenderHistograms::WithinWindow() const {
333 if (last_prerender_seen_time_.is_null())
334 return false;
335 return GetTimeSinceLastPrerender() <=
336 base::TimeDelta::FromSeconds(kWindowDurationSeconds);
339 void PrerenderHistograms::RecordTimeUntilUsed(
340 Origin origin,
341 base::TimeDelta time_until_used) const {
342 PREFIXED_HISTOGRAM(
343 "TimeUntilUsed2", origin,
344 UMA_HISTOGRAM_CUSTOM_TIMES(
345 name,
346 time_until_used,
347 base::TimeDelta::FromMilliseconds(10),
348 base::TimeDelta::FromMinutes(30),
349 50));
352 void PrerenderHistograms::RecordAbandonTimeUntilUsed(
353 Origin origin,
354 base::TimeDelta time_until_used) const {
355 PREFIXED_HISTOGRAM(
356 "AbandonTimeUntilUsed", origin,
357 UMA_HISTOGRAM_CUSTOM_TIMES(
358 name,
359 time_until_used,
360 base::TimeDelta::FromMilliseconds(10),
361 base::TimeDelta::FromSeconds(30),
362 50));
365 void PrerenderHistograms::RecordPerSessionCount(Origin origin,
366 int count) const {
367 PREFIXED_HISTOGRAM(
368 "PrerendersPerSessionCount", origin,
369 UMA_HISTOGRAM_COUNTS(name, count));
372 void PrerenderHistograms::RecordTimeBetweenPrerenderRequests(
373 Origin origin, base::TimeDelta time) const {
374 PREFIXED_HISTOGRAM(
375 "TimeBetweenPrerenderRequests", origin,
376 UMA_HISTOGRAM_TIMES(name, time));
379 void PrerenderHistograms::RecordFinalStatus(
380 Origin origin,
381 uint8 experiment_id,
382 PrerenderContents::MatchCompleteStatus mc_status,
383 FinalStatus final_status) const {
384 DCHECK(final_status != FINAL_STATUS_MAX);
386 if (mc_status == PrerenderContents::MATCH_COMPLETE_DEFAULT ||
387 mc_status == PrerenderContents::MATCH_COMPLETE_REPLACED) {
388 PREFIXED_HISTOGRAM_ORIGIN_EXPERIMENT(
389 "FinalStatus", origin, experiment_id,
390 UMA_HISTOGRAM_ENUMERATION(name, final_status, FINAL_STATUS_MAX));
392 if (mc_status == PrerenderContents::MATCH_COMPLETE_DEFAULT ||
393 mc_status == PrerenderContents::MATCH_COMPLETE_REPLACEMENT ||
394 mc_status == PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING) {
395 PREFIXED_HISTOGRAM_ORIGIN_EXPERIMENT(
396 "FinalStatusMatchComplete", origin, experiment_id,
397 UMA_HISTOGRAM_ENUMERATION(name, final_status, FINAL_STATUS_MAX));
401 void PrerenderHistograms::RecordNetworkBytes(Origin origin,
402 bool used,
403 int64 prerender_bytes,
404 int64 profile_bytes) {
405 const int kHistogramMin = 1;
406 const int kHistogramMax = 100000000; // 100M.
407 const int kBucketCount = 50;
409 UMA_HISTOGRAM_CUSTOM_COUNTS("Prerender.NetworkBytesTotalForProfile",
410 profile_bytes,
411 kHistogramMin,
412 1000000000, // 1G
413 kBucketCount);
415 if (prerender_bytes == 0)
416 return;
418 if (used) {
419 PREFIXED_HISTOGRAM(
420 "NetworkBytesUsed",
421 origin,
422 UMA_HISTOGRAM_CUSTOM_COUNTS(
423 name, prerender_bytes, kHistogramMin, kHistogramMax, kBucketCount));
424 } else {
425 PREFIXED_HISTOGRAM(
426 "NetworkBytesWasted",
427 origin,
428 UMA_HISTOGRAM_CUSTOM_COUNTS(
429 name, prerender_bytes, kHistogramMin, kHistogramMax, kBucketCount));
433 uint8 PrerenderHistograms::GetCurrentExperimentId() const {
434 if (!WithinWindow())
435 return kNoExperiment;
436 return last_experiment_id_;
439 bool PrerenderHistograms::IsOriginExperimentWash() const {
440 if (!WithinWindow())
441 return false;
442 return origin_experiment_wash_;
445 } // namespace prerender