Chromium Code Reviews| Index: chrome/browser/prerender/prerender_manager.cc |
| =================================================================== |
| --- chrome/browser/prerender/prerender_manager.cc (revision 91002) |
| +++ chrome/browser/prerender/prerender_manager.cc (working copy) |
| @@ -78,6 +78,36 @@ |
| } // namespace |
| +// Helper macros for experiment-based and origin-based histogram reporting. |
| +#define PREFIXED_HISTOGRAM(histogram) \ |
| + PREFIXED_HISTOGRAM_INTERNAL(GetCurrentOrigin(), GetCurrentExperimentId(), \ |
| + IsOriginExperimentWash(), histogram) |
| + |
| +#define PREFIXED_HISTOGRAM_PRERENDER_MANAGER(pm, histogram) \ |
| + PREFIXED_HISTOGRAM_INTERNAL(pm->GetCurrentOrigin(), \ |
| + pm->GetCurrentExperimentId(), \ |
| + pm->IsOriginExperimentWash(), histogram) |
| + |
| +#define PREFIXED_HISTOGRAM_ORIGIN_EXPERIMENT(origin, experiment, histogram) \ |
| + PREFIXED_HISTOGRAM_INTERNAL(origin, experiment, false, histogram) |
| + |
| +#define PREFIXED_HISTOGRAM_INTERNAL(origin, experiment, wash, histogram) { \ |
| + static char experiment_id = kNoExperiment; \ |
|
dominich.google
2011/06/30 19:55:15
This should be a uint8 now.
If you have two histo
tburkard
2011/06/30 21:40:20
Done.
|
| + if (experiment_id == kNoExperiment && experiment != kNoExperiment) \ |
| + experiment_id = experiment; \ |
| + if (wash || \ |
| + (experiment != kNoExperiment && (origin != ORIGIN_LINK_REL_PRERENDER || \ |
| + experiment != experiment_id))) { \ |
| + histogram; \ |
| + } else if (experiment != kNoExperiment) { \ |
| + histogram; \ |
| + } else if (origin == ORIGIN_OMNIBOX) { \ |
| + histogram; \ |
| + } else { \ |
| + histogram; \ |
| + } \ |
| +} |
| + |
| class PrerenderManager::OnCloseTabContentsDeleter : public TabContentsDelegate { |
| public: |
| OnCloseTabContentsDeleter(PrerenderManager* manager, |
| @@ -176,6 +206,29 @@ |
| } |
| // static |
| +uint8 PrerenderManager::GetQueryStringBasedExperiment(const GURL& url) { |
| + url_parse::Parsed parsed; |
| + url_parse::ParseStandardURL(url.spec().c_str(), url.spec().length(), |
| + &parsed); |
| + url_parse::Component query = parsed.query; |
| + url_parse::Component key, value; |
| + while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key, |
| + &value)) { |
| + if (key.len != 3 || strncmp(url.spec().c_str() + key.begin, "lpe", key.len)) |
| + continue; |
| + |
| + // We found a lpe= query string component. |
| + if (value.len != 1) |
| + continue; |
| + uint8 exp = *(url.spec().c_str() + value.begin) - '0'; |
| + if (exp < 1 || exp > 9) |
| + continue; |
| + return exp; |
| + } |
| + return kNoExperiment; |
| +} |
| + |
| +// static |
| bool PrerenderManager::IsValidHttpMethod(const std::string& method) { |
| // method has been canonicalized to upper case at this point so we can just |
| // compare them. |
| @@ -229,6 +282,9 @@ |
| max_prerender_memory_mb_(kDefaultMaxPrerenderMemoryMB), |
| max_elements_(kDefaultMaxPrerenderElements), |
| prerender_contents_factory_(PrerenderContents::CreateFactory()), |
| + last_experiment_id_(kNoExperiment), |
| + last_origin_(ORIGIN_LINK_REL_PRERENDER), |
| + origin_experiment_wash_(false), |
| last_prerender_start_time_(GetCurrentTimeTicks() - |
| base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)), |
| runnable_method_factory_(this), |
| @@ -275,6 +331,26 @@ |
| const GURL& referrer) { |
| DCHECK(CalledOnValidThread()); |
| + // Check if we are doing an experiment. |
| + uint8 experiment = PrerenderManager::GetQueryStringBasedExperiment(url_arg); |
| + |
| + // We need to update last_experiment_id_, last_origin_, and |
| + // origin_experiment_wash_. |
| + if (!WithinWindow()) { |
| + // If we are outside a window, this is a fresh start and we are fine, |
| + // and there is no mix. |
| + origin_experiment_wash_ = false; |
| + } else { |
| + // If we are inside the last window, there is a mish mash of origins |
| + // and experiments if either there was a mish mash before, or the current |
| + // experiment/origin does not match the previous one. |
| + if (experiment != last_experiment_id_ || origin != last_origin_) |
| + origin_experiment_wash_ = true; |
| + } |
| + |
| + last_origin_ = origin; |
| + last_experiment_id_ = experiment; |
| + |
| // If we observe multiple tags within the 30 second window, we will still |
| // reset the window to begin at the most recent occurrence, so that we will |
| // always be in a window in the 30 seconds from each occurrence. |
| @@ -311,7 +387,7 @@ |
| // case, when a new tab is added to a process used for prerendering. |
| if (RenderProcessHost::ShouldTryToUseExistingProcessHost() && |
| !RenderProcessHost::run_renderer_in_process()) { |
| - RecordFinalStatus(origin, FINAL_STATUS_TOO_MANY_PROCESSES); |
| + RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); |
| return false; |
| } |
| @@ -320,7 +396,7 @@ |
| // Cancel the prerender. We could add it to the pending prerender list but |
| // this doesn't make sense as the next prerender request will be triggered |
| // by a navigation and is unlikely to be the same site. |
| - RecordFinalStatus(origin, FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
| + RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
| return false; |
| } |
| @@ -333,13 +409,14 @@ |
| // Don't prerender page if parent RenderViewHost no longer exists, or it has |
| // no view. The latter should only happen when the RenderView has closed. |
| if (!source_render_view_host || !source_render_view_host->view()) { |
| - RecordFinalStatus(origin, FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED); |
| + RecordFinalStatus(origin, experiment, |
| + FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED); |
| return false; |
| } |
| } |
| PrerenderContents* prerender_contents = |
| - CreatePrerenderContents(url, referrer, origin); |
| + CreatePrerenderContents(url, referrer, origin, experiment); |
| if (!prerender_contents || !prerender_contents->Init()) |
| return false; |
| @@ -509,8 +586,9 @@ |
| RecordTimeUntilUsed(GetCurrentTimeTicks() - |
| prerender_contents->load_start_time()); |
| - UMA_HISTOGRAM_COUNTS("Prerender.PrerendersPerSessionCount", |
| - ++prerenders_per_session_count_); |
| + PREFIXED_HISTOGRAM(UMA_HISTOGRAM_COUNTS( |
| + GetDefaultHistogramName("Prerender.PrerendersPerSessionCount"), |
| + ++prerenders_per_session_count_)); |
| prerender_contents->set_final_status(FINAL_STATUS_USED); |
| RenderViewHost* render_view_host = |
| @@ -620,10 +698,11 @@ |
| PrerenderContents* PrerenderManager::CreatePrerenderContents( |
| const GURL& url, |
| const GURL& referrer, |
| - Origin origin) { |
| + Origin origin, |
| + uint8 experiment_id) { |
| DCHECK(CalledOnValidThread()); |
| return prerender_contents_factory_->CreatePrerenderContents( |
| - this, prerender_tracker_, profile_, url, referrer, origin); |
| + this, prerender_tracker_, profile_, url, referrer, origin, experiment_id); |
| } |
| bool PrerenderManager::IsPendingDelete(PrerenderContents* entry) const { |
| @@ -650,14 +729,15 @@ |
| // Helper macro for histograms. |
| #define RECORD_PLT(tag, perceived_page_load_time) { \ |
| + PREFIXED_HISTOGRAM_PRERENDER_MANAGER(prerender_manager, \ |
| UMA_HISTOGRAM_CUSTOM_TIMES( \ |
| - base::FieldTrial::MakeName(std::string("Prerender.") + tag, \ |
| - "Prefetch"), \ |
| + base::FieldTrial::MakeName( \ |
| + prerender_manager->GetDefaultHistogramName(tag), "Prefetch"), \ |
| perceived_page_load_time, \ |
| base::TimeDelta::FromMilliseconds(10), \ |
| base::TimeDelta::FromSeconds(60), \ |
| - 100); \ |
| - } |
| + 100)); \ |
| +} |
| // static |
| void PrerenderManager::RecordPerceivedPageLoadTime( |
| @@ -785,8 +865,10 @@ |
| DCHECK(CalledOnValidThread()); |
| base::TimeDelta elapsed_time = |
| GetCurrentTimeTicks() - last_prerender_start_time_; |
| - UMA_HISTOGRAM_TIMES("Prerender.TimeBetweenPrerenderRequests", |
| - elapsed_time); |
| + PREFIXED_HISTOGRAM( |
| + UMA_HISTOGRAM_TIMES( |
| + GetDefaultHistogramName("Prerender.TimeBetweenPrerenderRequests"), |
| + elapsed_time)); |
| if (!rate_limit_enabled_) |
| return true; |
| return elapsed_time > |
| @@ -1026,12 +1108,85 @@ |
| void PrerenderManager::RecordTimeUntilUsed(base::TimeDelta time_until_used) { |
| DCHECK(CalledOnValidThread()); |
| - UMA_HISTOGRAM_CUSTOM_TIMES( |
| - "Prerender.TimeUntilUsed", |
| + PREFIXED_HISTOGRAM(UMA_HISTOGRAM_CUSTOM_TIMES( |
| + GetDefaultHistogramName("Prerender.TimeUntilUsed"), |
| time_until_used, |
| base::TimeDelta::FromMilliseconds(10), |
| base::TimeDelta::FromSeconds(kDefaultMaxPrerenderAgeSeconds), |
| - 50); |
| + 50)); |
| } |
| +void PrerenderManager::RecordFinalStatus(Origin origin, |
| + uint8 experiment_id, |
| + FinalStatus final_status) const { |
| + DCHECK(final_status != FINAL_STATUS_MAX); |
| + // FINAL_STATUS_CONTROL_GROUP indicates that the PrerenderContents |
| + // was created only to measure "would-have-been-prerendered" for |
| + // control group measurements. Don't pollute data with it. |
| + if (PrerenderManager::IsControlGroup() || |
| + final_status == FINAL_STATUS_CONTROL_GROUP) |
| + return; |
| + PREFIXED_HISTOGRAM_ORIGIN_EXPERIMENT(origin, experiment_id, |
| + UMA_HISTOGRAM_ENUMERATION( |
| + GetHistogramName(origin, experiment_id, "FinalStatus"), |
| + final_status, |
| + FINAL_STATUS_MAX)); |
| +} |
| + |
| +std::string PrerenderManager::ComposeHistogramName(std::string prefix_type, |
|
dominich.google
2011/06/30 19:55:15
const references here
tburkard
2011/06/30 21:40:20
Done.
|
| + std::string name) const { |
| + if (prefix_type.empty()) |
| + return std::string("Prerender.") + name; |
| + return std::string("Prerender.") + prefix_type + std::string("_") + name; |
| +} |
| + |
| +std::string PrerenderManager::GetHistogramName(Origin origin, |
| + uint8 experiment_id, |
| + std::string name) const{ |
|
dominich.google
2011/06/30 19:55:15
const reference.
tburkard
2011/06/30 21:40:20
Done.
|
| + switch (origin) { |
| + case ORIGIN_OMNIBOX: |
| + if (experiment_id != kNoExperiment) |
| + return ComposeHistogramName("wash", name); |
| + return ComposeHistogramName("omnibox", name); |
| + case ORIGIN_LINK_REL_PRERENDER: |
| + if (experiment_id == kNoExperiment) |
| + return ComposeHistogramName("", name); |
| + return ComposeHistogramName("exp" + std::string(1, experiment_id + '0'), |
| + name); |
| + default: |
| + NOTREACHED(); |
| + break; |
| + }; |
| + |
| + // Dummy return value to make the compiler happy. |
| + NOTREACHED(); |
| + return ComposeHistogramName("wash", name); |
| +} |
| + |
| +std::string PrerenderManager::GetDefaultHistogramName(std::string name) const { |
|
dominich.google
2011/06/30 19:55:15
const reference.
tburkard
2011/06/30 21:40:20
Done.
|
| + if (!WithinWindow()) |
| + return ComposeHistogramName("", name); |
| + if (origin_experiment_wash_) |
| + return ComposeHistogramName("wash", name); |
| + return GetHistogramName(last_origin_, last_experiment_id_, name); |
| +} |
| + |
| +uint8 PrerenderManager::GetCurrentExperimentId() const { |
| + if (!WithinWindow()) |
| + return kNoExperiment; |
| + return last_experiment_id_; |
| +} |
| + |
| +Origin PrerenderManager::GetCurrentOrigin() const { |
| + if (!WithinWindow()) |
| + return ORIGIN_LINK_REL_PRERENDER; |
| + return last_origin_; |
| +} |
| + |
| +bool PrerenderManager::IsOriginExperimentWash() const { |
| + if (!WithinWindow()) |
| + return false; |
| + return origin_experiment_wash_; |
| +} |
| + |
| } // namespace prerender |