diff options
-rw-r--r-- | chrome/chrome_renderer.gypi | 2 | ||||
-rw-r--r-- | chrome/renderer/navigation_state.h | 16 | ||||
-rw-r--r-- | chrome/renderer/page_load_histograms.cc | 697 | ||||
-rw-r--r-- | chrome/renderer/page_load_histograms.h | 59 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 716 | ||||
-rw-r--r-- | chrome/renderer/render_view.h | 15 |
6 files changed, 769 insertions, 736 deletions
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index af9c6fd..de923833 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -130,6 +130,8 @@ 'renderer/page_click_listener.h', 'renderer/page_click_tracker.cc', 'renderer/page_click_tracker.h', + 'renderer/page_load_histograms.cc', + 'renderer/page_load_histograms.h', 'renderer/password_autocomplete_manager.cc', 'renderer/password_autocomplete_manager.h', 'renderer/pepper_devices.cc', diff --git a/chrome/renderer/navigation_state.h b/chrome/renderer/navigation_state.h index d9cee3e..6041389 100644 --- a/chrome/renderer/navigation_state.h +++ b/chrome/renderer/navigation_state.h @@ -152,18 +152,6 @@ class NavigationState : public WebKit::WebDataSource::ExtraData { first_paint_after_load_time_ = value; } - // Info about the URL used as the target of this navigation. - URLPattern::SchemeMasks scheme_type() const { return scheme_type_; } - void set_scheme_type(URLPattern::SchemeMasks scheme_type) { - scheme_type_ = scheme_type; - } - - // True iff the histograms for the associated frame have been dumped. - bool load_histograms_recorded() const { return load_histograms_recorded_; } - void set_load_histograms_recorded(bool value) { - load_histograms_recorded_ = value; - } - // True if we have already processed the "DidCommitLoad" event for this // request. Used by session history. bool request_committed() const { return request_committed_; } @@ -281,8 +269,6 @@ class NavigationState : public WebKit::WebDataSource::ExtraData { : transition_type_(transition_type), load_type_(UNDEFINED_LOAD), request_time_(request_time), - scheme_type_(static_cast<URLPattern::SchemeMasks>(0)), - load_histograms_recorded_(false), request_committed_(false), is_content_initiated_(is_content_initiated), pending_page_id_(pending_page_id), @@ -311,8 +297,6 @@ class NavigationState : public WebKit::WebDataSource::ExtraData { base::Time finish_load_time_; base::Time first_paint_time_; base::Time first_paint_after_load_time_; - URLPattern::SchemeMasks scheme_type_; - bool load_histograms_recorded_; bool request_committed_; bool is_content_initiated_; int32 pending_page_id_; diff --git a/chrome/renderer/page_load_histograms.cc b/chrome/renderer/page_load_histograms.cc new file mode 100644 index 0000000..30e8a4d --- /dev/null +++ b/chrome/renderer/page_load_histograms.cc @@ -0,0 +1,697 @@ +// Copyright (c) 2010 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/renderer/page_load_histograms.h" + +#include "base/logging.h" +#include "base/metrics/field_trial.h" +#include "base/metrics/histogram.h" +#include "base/time.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/renderer/navigation_state.h" +#include "chrome/renderer/render_thread.h" +#include "googleurl/src/gurl.h" +#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h" + +using base::Time; +using base::TimeDelta; +using WebKit::WebDataSource; +using WebKit::WebFrame; + +static const TimeDelta kPLTMin(TimeDelta::FromMilliseconds(10)); +static const TimeDelta kPLTMax(TimeDelta::FromMinutes(10)); +static const size_t kPLTCount(100); + +#define PLT_HISTOGRAM(name, sample) \ + UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, kPLTMin, kPLTMax, kPLTCount); + +// Returns the scheme type of the given URL if its type is one for which we +// dump page load histograms. Otherwise returns NULL. +static URLPattern::SchemeMasks GetSupportedSchemeType(const GURL& url) { + if (url.SchemeIs("http")) + return URLPattern::SCHEME_HTTP; + else if (url.SchemeIs("https")) + return URLPattern::SCHEME_HTTPS; + return static_cast<URLPattern::SchemeMasks>(0); +} + +PageLoadHistograms::PageLoadHistograms() + : has_dumped_(false), + cross_origin_access_count_(0), + same_origin_access_count_(0) { +} + +void PageLoadHistograms::Dump(WebFrame* frame) { + // We only dump histograms for main frames. + // In the future, it may be interesting to tag subframes and dump them too. + if (!frame || frame->parent()) + return; + + // If we've already dumped, do nothing. + // This simple bool works because we only dump for the main frame. + if (has_dumped_) + return; + + // Only dump for supported schemes. + URLPattern::SchemeMasks scheme_type = GetSupportedSchemeType(frame->url()); + if (scheme_type == 0) + return; + + // Configuration for PLT related histograms. + NavigationState* navigation_state = + NavigationState::FromDataSource(frame->dataSource()); + + // Collect measurement times. + Time start = navigation_state->start_load_time(); + if (start.is_null()) + return; // Probably very premature abandonment of page. + Time commit = navigation_state->commit_load_time(); + if (commit.is_null()) + return; // Probably very premature abandonment of page. + + // We properly handle null values for the next 3 variables. + Time request = navigation_state->request_time(); + Time first_paint = navigation_state->first_paint_time(); + Time first_paint_after_load = navigation_state->first_paint_after_load_time(); + Time finish_doc = navigation_state->finish_document_load_time(); + Time finish_all_loads = navigation_state->finish_load_time(); + + // Handle case where user hits "stop" or "back" before loading completely. + bool abandoned_page = finish_doc.is_null(); + if (abandoned_page) { + finish_doc = Time::Now(); + navigation_state->set_finish_document_load_time(finish_doc); + } + + // TODO(jar): We should really discriminate the definition of "abandon" more + // finely. We should have: + // abandon_before_document_loaded + // abandon_before_onload_fired + + if (finish_all_loads.is_null()) { + finish_all_loads = Time::Now(); + navigation_state->set_finish_load_time(finish_all_loads); + } else { + DCHECK(!abandoned_page); // How can the doc have finished but not the page? + if (!abandoned_page) + return; // Don't try to record a stat which is broken. + } + + has_dumped_ = true; + + // Note: Client side redirects will have no request time. + Time begin = request.is_null() ? start : request; + TimeDelta begin_to_finish_doc = finish_doc - begin; + TimeDelta begin_to_finish_all_loads = finish_all_loads - begin; + TimeDelta start_to_finish_all_loads = finish_all_loads - start; + TimeDelta start_to_commit = commit - start; + + NavigationState::LoadType load_type = navigation_state->load_type(); + + // The above code sanitized all values of times, in preparation for creating + // actual histograms. The remainder of this code could be run at destructor + // time for the navigation_state, since all data is intact. + + // Aggregate PLT data across all link types. + UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned", abandoned_page ? 1 : 0, 2); + UMA_HISTOGRAM_ENUMERATION("PLT.LoadType", load_type, + NavigationState::kLoadTypeMax); + PLT_HISTOGRAM("PLT.StartToCommit", start_to_commit); + PLT_HISTOGRAM("PLT.CommitToFinishDoc", finish_doc - commit); + PLT_HISTOGRAM("PLT.FinishDocToFinish", finish_all_loads - finish_doc); + PLT_HISTOGRAM("PLT.BeginToCommit", commit - begin); + PLT_HISTOGRAM("PLT.StartToFinish", start_to_finish_all_loads); + if (!request.is_null()) { + PLT_HISTOGRAM("PLT.RequestToStart", start - request); + PLT_HISTOGRAM("PLT.RequestToFinish", finish_all_loads - request); + } + PLT_HISTOGRAM("PLT.CommitToFinish", finish_all_loads - commit); + if (!first_paint.is_null()) { + DCHECK(begin <= first_paint); + PLT_HISTOGRAM("PLT.BeginToFirstPaint", first_paint - begin); + DCHECK(commit <= first_paint); + PLT_HISTOGRAM("PLT.CommitToFirstPaint", first_paint - commit); + } + if (!first_paint_after_load.is_null()) { + DCHECK(begin <= first_paint_after_load); + PLT_HISTOGRAM("PLT.BeginToFirstPaintAfterLoad", + first_paint_after_load - begin); + DCHECK(commit <= first_paint_after_load); + PLT_HISTOGRAM("PLT.CommitToFirstPaintAfterLoad", + first_paint_after_load - commit); + DCHECK(finish_all_loads <= first_paint_after_load); + PLT_HISTOGRAM("PLT.FinishToFirstPaintAfterLoad", + first_paint_after_load - finish_all_loads); + } + PLT_HISTOGRAM("PLT.BeginToFinishDoc", begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish", begin_to_finish_all_loads); + + // Load type related histograms. + switch (load_type) { + case NavigationState::UNDEFINED_LOAD: + PLT_HISTOGRAM("PLT.BeginToFinishDoc_UndefLoad", begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish_UndefLoad", begin_to_finish_all_loads); + break; + case NavigationState::RELOAD: + PLT_HISTOGRAM("PLT.BeginToFinishDoc_Reload", begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish_Reload", begin_to_finish_all_loads); + break; + case NavigationState::HISTORY_LOAD: + PLT_HISTOGRAM("PLT.BeginToFinishDoc_HistoryLoad", begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish_HistoryLoad", begin_to_finish_all_loads); + break; + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM("PLT.BeginToFinishDoc_NormalLoad", begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish_NormalLoad", begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM("PLT.BeginToFinishDoc_LinkLoadNormal", + begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish_LinkLoadNormal", + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_RELOAD: + PLT_HISTOGRAM("PLT.BeginToFinishDoc_LinkLoadReload", + begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish_LinkLoadReload", + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_STALE_OK: + PLT_HISTOGRAM("PLT.BeginToFinishDoc_LinkLoadStaleOk", + begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish_LinkLoadStaleOk", + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_ONLY: + PLT_HISTOGRAM("PLT.BeginToFinishDoc_LinkLoadCacheOnly", + begin_to_finish_doc); + PLT_HISTOGRAM("PLT.BeginToFinish_LinkLoadCacheOnly", + begin_to_finish_all_loads); + break; + default: + break; + } + + // Histograms to determine if DNS prefetching has an impact on PLT. + static bool use_dns_histogram(base::FieldTrialList::Find("DnsImpact") && + !base::FieldTrialList::Find("DnsImpact")->group_name().empty()); + if (use_dns_histogram) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.Abandoned", "DnsImpact"), + abandoned_page ? 1 : 0, 2); + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.LoadType", "DnsImpact"), + load_type, NavigationState::kLoadTypeMax); + switch (load_type) { + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_NormalLoad", "DnsImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadNormal", "DnsImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_RELOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadReload", "DnsImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_STALE_OK: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadStaleOk", "DnsImpact"), + begin_to_finish_all_loads); + break; + default: + break; + } + } + + // Histograms to determine if content prefetching has an impact on PLT. + static const bool prefetching_fieldtrial = + base::FieldTrialList::Find("Prefetch") && + !base::FieldTrialList::Find("Prefetch")->group_name().empty(); + if (prefetching_fieldtrial) { + if (navigation_state->was_prefetcher()) { + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinishDoc_ContentPrefetcher", "Prefetch"), + begin_to_finish_doc); + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_ContentPrefetcher", "Prefetch"), + begin_to_finish_all_loads); + } + if (navigation_state->was_referred_by_prefetcher()) { + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinishDoc_ContentPrefetcherReferrer", "Prefetch"), + begin_to_finish_doc); + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_ContentPrefetcherReferrer", "Prefetch"), + begin_to_finish_all_loads); + } + UMA_HISTOGRAM_ENUMERATION(base::FieldTrial::MakeName( + "PLT.Abandoned", "Prefetch"), + abandoned_page ? 1 : 0, 2); + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinishDoc", "Prefetch"), + begin_to_finish_doc); + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish", "Prefetch"), + begin_to_finish_all_loads); + } + + // Histograms to determine if backup connection jobs have an impact on PLT. + static const bool connect_backup_jobs_fieldtrial( + base::FieldTrialList::Find("ConnnectBackupJobs") && + !base::FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty()); + if (connect_backup_jobs_fieldtrial) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.Abandoned", "ConnnectBackupJobs"), + abandoned_page ? 1 : 0, 2); + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.LoadType", "ConnnectBackupJobs"), + load_type, NavigationState::kLoadTypeMax); + switch (load_type) { + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_NormalLoad", "ConnnectBackupJobs"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadNormal", "ConnnectBackupJobs"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_RELOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadReload", "ConnnectBackupJobs"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_STALE_OK: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadStaleOk", "ConnnectBackupJobs"), + begin_to_finish_all_loads); + break; + default: + break; + } + } + + // Histograms to determine if the number of connections has an + // impact on PLT. + // TODO(jar): Consider removing the per-link-type versions. We + // really only need LINK_LOAD_NORMAL and NORMAL_LOAD. + static bool use_connection_impact_histogram( + base::FieldTrialList::Find("ConnCountImpact") && + !base::FieldTrialList::Find("ConnCountImpact")->group_name().empty()); + if (use_connection_impact_histogram) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.Abandoned", "ConnCountImpact"), + abandoned_page ? 1 : 0, 2); + switch (load_type) { + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_NormalLoad", "ConnCountImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadNormal", "ConnCountImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_RELOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadReload", "ConnCountImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_STALE_OK: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadStaleOk", "ConnCountImpact"), + begin_to_finish_all_loads); + break; + default: + break; + } + } + + // Histograms to determine effect of idle socket timeout. + static bool use_idle_socket_timeout_histogram( + base::FieldTrialList::Find("IdleSktToImpact") && + !base::FieldTrialList::Find("IdleSktToImpact")->group_name().empty()); + if (use_idle_socket_timeout_histogram) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.Abandoned", "IdleSktToImpact"), + abandoned_page ? 1 : 0, 2); + switch (load_type) { + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_NormalLoad", "IdleSktToImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadNormal", "IdleSktToImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_RELOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadReload", "IdleSktToImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_STALE_OK: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadStaleOk", "IdleSktToImpact"), + begin_to_finish_all_loads); + break; + default: + break; + } + } + + // Histograms to determine effect of number of connections per proxy. + static bool use_proxy_connection_impact_histogram( + base::FieldTrialList::Find("ProxyConnectionImpact") && + !base::FieldTrialList::Find( + "ProxyConnectionImpact")->group_name().empty()); + if (use_proxy_connection_impact_histogram) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.Abandoned", "ProxyConnectionImpact"), + abandoned_page ? 1 : 0, 2); + switch (load_type) { + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_NormalLoad", "ProxyConnectionImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadNormal", "ProxyConnectionImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_RELOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadReload", "ProxyConnectionImpact"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_STALE_OK: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadStaleOk", "ProxyConnectionImpact"), + begin_to_finish_all_loads); + break; + default: + break; + } + } + + // Histograms to determine if SDCH has an impact. + // TODO(jar): Consider removing per-link load types and the enumeration. + static bool use_sdch_histogram(base::FieldTrialList::Find("GlobalSdch") && + !base::FieldTrialList::Find("GlobalSdch")->group_name().empty()); + if (use_sdch_histogram) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.LoadType", "GlobalSdch"), + load_type, NavigationState::kLoadTypeMax); + switch (load_type) { + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_NormalLoad", "GlobalSdch"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadNormal", "GlobalSdch"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_RELOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadReload", "GlobalSdch"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_STALE_OK: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadStaleOk", "GlobalSdch"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_ONLY: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadCacheOnly", "GlobalSdch"), + begin_to_finish_all_loads); + break; + default: + break; + } + } + + // Histograms to determine if cache size has an impact on PLT. + static bool use_cache_histogram1(base::FieldTrialList::Find("CacheSize") && + !base::FieldTrialList::Find("CacheSize")->group_name().empty()); + if (use_cache_histogram1 && NavigationState::LINK_LOAD_NORMAL <= load_type && + NavigationState::LINK_LOAD_CACHE_ONLY >= load_type) { + // TODO(mbelshe): Do we really want BeginToFinishDoc here? It seems like + // StartToFinish or BeginToFinish would be better. + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinishDoc_LinkLoad", "CacheSize"), begin_to_finish_doc); + } + + // Histograms to determine if cache throttling has an impact on PLT. + static bool use_cache_histogram2( + base::FieldTrialList::Find("CacheThrottle") && + !base::FieldTrialList::Find("CacheThrottle")->group_name().empty()); + if (use_cache_histogram2) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.Abandoned", "CacheThrottle"), + abandoned_page ? 1 : 0, 2); + switch (load_type) { + case NavigationState::RELOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_Reload", "CacheThrottle"), + begin_to_finish_all_loads); + break; + case NavigationState::HISTORY_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_HistoryLoad", "CacheThrottle"), + begin_to_finish_all_loads); + break; + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_NormalLoad", "CacheThrottle"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadNormal", "CacheThrottle"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_RELOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadReload", "CacheThrottle"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_STALE_OK: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadStaleOk", "CacheThrottle"), + begin_to_finish_all_loads); + break; + case NavigationState::LINK_LOAD_CACHE_ONLY: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadCacheOnly", "CacheThrottle"), + begin_to_finish_all_loads); + break; + default: + break; + } + if (NavigationState::RELOAD <= load_type && + NavigationState::LINK_LOAD_CACHE_ONLY >= load_type) { + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish", "CacheThrottle"), + begin_to_finish_all_loads); + } + } + + // For the SPDY field trials, we need to verify that the page loaded was + // the type we requested: + // if we asked for a SPDY request, we got a SPDY request + // if we asked for a HTTP request, we got a HTTP request + // Due to spdy version mismatches, it is possible that we ask for SPDY + // but didn't get SPDY. + static bool use_spdy_histogram(base::FieldTrialList::Find("SpdyImpact") && + !base::FieldTrialList::Find("SpdyImpact")->group_name().empty()); + if (use_spdy_histogram) { + // We take extra effort to only compute these once. + static bool in_spdy_trial = base::FieldTrialList::Find( + "SpdyImpact")->group_name() == "npn_with_spdy"; + static bool in_http_trial = base::FieldTrialList::Find( + "SpdyImpact")->group_name() == "npn_with_http"; + + bool spdy_trial_success = navigation_state->was_fetched_via_spdy() ? + in_spdy_trial : in_http_trial; + if (spdy_trial_success) { + // Histograms to determine if SPDY has an impact for https traffic. + // TODO(mbelshe): After we've seen the difference between BeginToFinish + // and StartToFinish, consider removing one or the other. + if (scheme_type == URLPattern::SCHEME_HTTPS && + navigation_state->was_npn_negotiated()) { + UMA_HISTOGRAM_ENUMERATION( + base::FieldTrial::MakeName("PLT.Abandoned", "SpdyImpact"), + abandoned_page ? 1 : 0, 2); + switch (load_type) { + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_LinkLoadNormal_SpdyTrial", "SpdyImpact"), + begin_to_finish_all_loads); + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.StartToFinish_LinkLoadNormal_SpdyTrial", "SpdyImpact"), + start_to_finish_all_loads); + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.StartToCommit_LinkLoadNormal_SpdyTrial", "SpdyImpact"), + start_to_commit); + break; + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.BeginToFinish_NormalLoad_SpdyTrial", "SpdyImpact"), + begin_to_finish_all_loads); + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.StartToFinish_NormalLoad_SpdyTrial", "SpdyImpact"), + start_to_finish_all_loads); + PLT_HISTOGRAM(base::FieldTrial::MakeName( + "PLT.StartToCommit_NormalLoad_SpdyTrial", "SpdyImpact"), + start_to_commit); + break; + default: + break; + } + } + + // Histograms to compare the impact of alternate protocol over http + // traffic: when spdy is used vs. when http is used. + if (scheme_type == URLPattern::SCHEME_HTTP && + navigation_state->was_alternate_protocol_available()) { + if (!navigation_state->was_npn_negotiated()) { + // This means that even there is alternate protocols for npn_http or + // npn_spdy, they are not taken (due to the base::FieldTrial). + switch (load_type) { + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM( + "PLT.StartToFinish_LinkLoadNormal_AlternateProtocol_http", + start_to_finish_all_loads); + PLT_HISTOGRAM( + "PLT.StartToCommit_LinkLoadNormal_AlternateProtocol_http", + start_to_commit); + break; + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM( + "PLT.StartToFinish_NormalLoad_AlternateProtocol_http", + start_to_finish_all_loads); + PLT_HISTOGRAM( + "PLT.StartToCommit_NormalLoad_AlternateProtocol_http", + start_to_commit); + break; + default: + break; + } + } else if (navigation_state->was_fetched_via_spdy()) { + switch (load_type) { + case NavigationState::LINK_LOAD_NORMAL: + PLT_HISTOGRAM( + "PLT.StartToFinish_LinkLoadNormal_AlternateProtocol_spdy", + start_to_finish_all_loads); + PLT_HISTOGRAM( + "PLT.StartToCommit_LinkLoadNormal_AlternateProtocol_spdy", + start_to_commit); + break; + case NavigationState::NORMAL_LOAD: + PLT_HISTOGRAM( + "PLT.StartToFinish_NormalLoad_AlternateProtocol_spdy", + start_to_finish_all_loads); + PLT_HISTOGRAM( + "PLT.StartToCommit_NormalLoad_AlternateProtocol_spdy", + start_to_commit); + break; + default: + break; + } + } + } + } + } + + // Record page load time and abandonment rates for proxy cases. + if (navigation_state->was_fetched_via_proxy()) { + if (scheme_type == URLPattern::SCHEME_HTTPS) { + PLT_HISTOGRAM("PLT.StartToFinish.Proxy.https", start_to_finish_all_loads); + UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned.Proxy.https", + abandoned_page ? 1 : 0, 2); + } else { + DCHECK(scheme_type == URLPattern::SCHEME_HTTP); + PLT_HISTOGRAM("PLT.StartToFinish.Proxy.http", start_to_finish_all_loads); + UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned.Proxy.http", + abandoned_page ? 1 : 0, 2); + } + } else { + if (scheme_type == URLPattern::SCHEME_HTTPS) { + PLT_HISTOGRAM("PLT.StartToFinish.NoProxy.https", + start_to_finish_all_loads); + UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned.NoProxy.https", + abandoned_page ? 1 : 0, 2); + } else { + DCHECK(scheme_type == URLPattern::SCHEME_HTTP); + PLT_HISTOGRAM("PLT.StartToFinish.NoProxy.http", + start_to_finish_all_loads); + UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned.NoProxy.http", + abandoned_page ? 1 : 0, 2); + } + } + + // Site isolation metrics. + UMA_HISTOGRAM_COUNTS("SiteIsolation.PageLoadsWithCrossSiteFrameAccess", + cross_origin_access_count_); + UMA_HISTOGRAM_COUNTS("SiteIsolation.PageLoadsWithSameSiteFrameAccess", + same_origin_access_count_); + ResetCrossFramePropertyAccess(); + + // Log the PLT to the info log. + LogPageLoadTime(navigation_state, frame->dataSource()); + + // Since there are currently no guarantees that renderer histograms will be + // sent to the browser, we initiate a PostTask here to be sure that we send + // the histograms we generated. Without this call, pages that don't have an + // on-close-handler might generate data that is lost when the renderer is + // shutdown abruptly (perchance because the user closed the tab). + // TODO(jar) BUG=33233: This needs to be moved to a PostDelayedTask, and it + // should post when the onload is complete, so that it doesn't interfere with + // the next load. + if (RenderThread::current()) { + RenderThread::current()->SendHistograms( + chrome::kHistogramSynchronizerReservedSequenceNumber); + } +} + +void PageLoadHistograms::IncrementCrossFramePropertyAccess(bool cross_origin) { + if (cross_origin) + cross_origin_access_count_++; + else + same_origin_access_count_++; +} + +void PageLoadHistograms::ResetCrossFramePropertyAccess() { + cross_origin_access_count_ = 0; + same_origin_access_count_ = 0; +} + +void PageLoadHistograms::LogPageLoadTime(const NavigationState* state, + const WebDataSource* ds) const { + // Because this function gets called on every page load, + // take extra care to optimize it away if logging is turned off. + if (logging::LOG_INFO < logging::GetMinLogLevel()) + return; + + DCHECK(state); + DCHECK(ds); + GURL url(ds->request().url()); + Time start = state->start_load_time(); + Time finish = state->finish_load_time(); + // TODO(mbelshe): should we log more stats? + VLOG(1) << "PLT: " << (finish - start).InMilliseconds() << "ms " + << url.spec(); +} diff --git a/chrome/renderer/page_load_histograms.h b/chrome/renderer/page_load_histograms.h new file mode 100644 index 0000000..7045089 --- /dev/null +++ b/chrome/renderer/page_load_histograms.h @@ -0,0 +1,59 @@ +// Copyright (c) 2010 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. + +#ifndef CHROME_RENDERER_PAGE_LOAD_HISTOGRAMS_H_ +#define CHROME_RENDERER_PAGE_LOAD_HISTOGRAMS_H_ + +#include "base/basictypes.h" + +class NavigationState; + +namespace WebKit { +class WebDataSource; +class WebFrame; +} + +class PageLoadHistograms { + public: + PageLoadHistograms(); + + // Dump all page load histograms appropriate for the given frame. + // + // This method will only dump once-per-instance, so it is safe to call + // multiple times. + // + // The time points we keep are + // request: time document was requested by user + // start: time load of document started + // commit: time load of document started + // finish_document: main document loaded, before onload() + // finish_all_loads: after onload() and all resources are loaded + // first_paint: first paint performed + // first_paint_after_load: first paint performed after load is finished + // begin: request if it was user requested, start otherwise + // + // It's possible for the request time not to be set, if a client + // redirect had been done (the user never requested the page) + // Also, it's possible to load a page without ever laying it out + // so first_paint and first_paint_after_load can be 0. + void Dump(WebKit::WebFrame* frame); + + void IncrementCrossFramePropertyAccess(bool cross_origin); + + private: + void ResetCrossFramePropertyAccess(); + void LogPageLoadTime(const NavigationState* state, + const WebKit::WebDataSource* ds) const; + + bool has_dumped_; + + // Site isolation metric counts. + // These are per-page-load counts, reset to 0 after they are dumped. + int cross_origin_access_count_; + int same_origin_access_count_; + + DISALLOW_COPY_AND_ASSIGN(PageLoadHistograms); +}; + +#endif // CHROME_RENDERER_PAGE_LOAD_HISTOGRAMS_H_ diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 09caae4..8c09d90 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -15,7 +15,6 @@ #include "base/callback.h" #include "base/command_line.h" #include "base/compiler_specific.h" -#include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/path_service.h" #include "base/process_util.h" @@ -69,6 +68,7 @@ #include "chrome/renderer/navigation_state.h" #include "chrome/renderer/notification_provider.h" #include "chrome/renderer/page_click_tracker.h" +#include "chrome/renderer/page_load_histograms.h" #include "chrome/renderer/password_autocomplete_manager.h" #include "chrome/renderer/plugin_channel_host.h" #include "chrome/renderer/print_web_view_helper.h" @@ -474,8 +474,6 @@ RenderView::RenderView(RenderThreadBase* render_thread, has_document_tag_(false), #endif document_tag_(0), - cross_origin_access_count_(0), - same_origin_access_count_(0), target_url_status_(TARGET_NONE), spelling_panel_visible_(false), view_type_(ViewType::INVALID), @@ -2622,18 +2620,7 @@ void RenderView::willClose(WebFrame* frame) { WebDataSource* ds = frame->dataSource(); NavigationState* navigation_state = NavigationState::FromDataSource(ds); - if (!frame->parent()) { - const GURL& url = frame->url(); - // Ensure state contains scheme. - if (url.SchemeIs("http")) - navigation_state->set_scheme_type(URLPattern::SCHEME_HTTP); - else if (url.SchemeIs("https")) - navigation_state->set_scheme_type(URLPattern::SCHEME_HTTPS); - - // Dump will only be provided when scheme is http or https. - DumpLoadHistograms(); - } - + page_load_histograms_.Dump(frame); navigation_state->user_script_idle_scheduler()->Cancel(); // TODO(jhawkins): Remove once frameDetached is called by WebKit. @@ -3539,10 +3526,7 @@ void RenderView::logCrossFramePropertyAccess(WebFrame* frame, const WebString& property_name, unsigned long long event_id) { // TODO(johnnyg): track the individual properties and repeat event_ids. - if (cross_origin) - cross_origin_access_count_++; - else - same_origin_access_count_++; + page_load_histograms_.IncrementCrossFramePropertyAccess(cross_origin); } void RenderView::didChangeContentsSize(WebFrame* frame, const WebSize& size) { @@ -4652,30 +4636,12 @@ void RenderView::OnClosePage(const ViewMsg_ClosePage_Params& params) { // revisited to avoid having two ways to close a page. Having a single way // to close that can run onunload is also useful for fixing // http://b/issue?id=753080. - WebFrame* main_frame = webview()->mainFrame(); - if (main_frame) { - const GURL& url = main_frame->url(); - // TODO(davemoore) this code should be removed once willClose() gets - // called when a page is destroyed. DumpLoadHistograms() is safe to call - // multiple times for the same frame, but it will simplify things. - - // Ensure state contains scheme. - NavigationState* navigation_state = - NavigationState::FromDataSource(main_frame->dataSource()); - if (url.SchemeIs("http")) - navigation_state->set_scheme_type(URLPattern::SCHEME_HTTP); - else if (url.SchemeIs("https")) - navigation_state->set_scheme_type(URLPattern::SCHEME_HTTPS); - - // Dump will only be provided when scheme is http or https. - DumpLoadHistograms(); - } + // TODO(davemoore) This code should be removed once willClose() gets + // called when a page is destroyed. page_load_histograms_.Dump() is safe + // to call multiple times for the same frame, but it will simplify things. + page_load_histograms_.Dump(webview()->mainFrame()); webview()->dispatchUnloadEvent(); - // Reset stats - cross_origin_access_count_ = 0; - same_origin_access_count_ = 0; - // Just echo back the params in the ACK. Send(new ViewHostMsg_ClosePage_ACK(routing_id_, params)); } @@ -4955,674 +4921,6 @@ void RenderView::OnExtensionMessageInvoke(const std::string& extension_id, extension_id, function_name, args, this, event_url); } -// Dump all load time histograms. -// -// The time points we keep are -// request: time document was requested by user -// start: time load of document started -// commit: time load of document started -// finish_document: main document loaded, before onload() -// finish_all_loads: after onload() and all resources are loaded -// first_paint: first paint performed -// first_paint_after_load: first paint performed after load is finished -// begin: request if it was user requested, start otherwise -// -// It's possible for the request time not to be set, if a client -// redirect had been done (the user never requested the page) -// Also, it's possible to load a page without ever laying it out -// so first_paint and first_paint_after_load can be 0. -void RenderView::DumpLoadHistograms() const { - // Configuration for PLT related histograms. - static const TimeDelta kPLTMin(TimeDelta::FromMilliseconds(10)); - static const TimeDelta kPLTMax(TimeDelta::FromMinutes(10)); - static const size_t kPLTCount(100); - #define PLT_HISTOGRAM(name, sample) \ - UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, kPLTMin, kPLTMax, kPLTCount); - - WebFrame* main_frame = webview()->mainFrame(); - NavigationState* navigation_state = - NavigationState::FromDataSource(main_frame->dataSource()); - - URLPattern::SchemeMasks scheme_type = navigation_state->scheme_type(); - if (scheme_type == 0) - return; - DCHECK(scheme_type == URLPattern::SCHEME_HTTP || - scheme_type == URLPattern::SCHEME_HTTPS); - - // If we've already dumped, do nothing. - if (navigation_state->load_histograms_recorded()) - return; - - // Collect measurement times. - Time start = navigation_state->start_load_time(); - if (start.is_null()) - return; // Probably very premature abandonment of page. - Time commit = navigation_state->commit_load_time(); - if (commit.is_null()) - return; // Probably very premature abandonment of page. - - // We properly handle null values for the next 3 variables. - Time request = navigation_state->request_time(); - Time first_paint = navigation_state->first_paint_time(); - Time first_paint_after_load = navigation_state->first_paint_after_load_time(); - Time finish_doc = navigation_state->finish_document_load_time(); - Time finish_all_loads = navigation_state->finish_load_time(); - - // Handle case where user hits "stop" or "back" before loading completely. - bool abandoned_page = finish_doc.is_null(); - if (abandoned_page) { - finish_doc = Time::Now(); - navigation_state->set_finish_document_load_time(finish_doc); - } - - // TODO(jar): We should really discriminate the definition of "abandon" more - // finely. We should have: - // abandon_before_document_loaded - // abandon_before_onload_fired - - if (finish_all_loads.is_null()) { - finish_all_loads = Time::Now(); - navigation_state->set_finish_load_time(finish_all_loads); - } else { - DCHECK(!abandoned_page); // How can the doc have finished but not the page? - if (!abandoned_page) - return; // Don't try to record a stat which is broken. - } - - // Note: Client side redirects will have no request time. - Time begin = request.is_null() ? start : request; - TimeDelta begin_to_finish_doc = finish_doc - begin; - TimeDelta begin_to_finish_all_loads = finish_all_loads - begin; - TimeDelta start_to_finish_all_loads = finish_all_loads - start; - TimeDelta start_to_commit = commit - start; - - NavigationState::LoadType load_type = navigation_state->load_type(); - - // The above code sanitized all values of times, in preparation for creating - // actual histograms. The remainder of this code could be run at destructor - // time for the navigation_state, since all data is intact. - - // Aggregate PLT data across all link types. - UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned", abandoned_page ? 1 : 0, 2); - UMA_HISTOGRAM_ENUMERATION("PLT.LoadType", load_type, - NavigationState::kLoadTypeMax); - PLT_HISTOGRAM("PLT.StartToCommit", start_to_commit); - PLT_HISTOGRAM("PLT.CommitToFinishDoc", finish_doc - commit); - PLT_HISTOGRAM("PLT.FinishDocToFinish", finish_all_loads - finish_doc); - PLT_HISTOGRAM("PLT.BeginToCommit", commit - begin); - PLT_HISTOGRAM("PLT.StartToFinish", start_to_finish_all_loads); - if (!request.is_null()) { - PLT_HISTOGRAM("PLT.RequestToStart", start - request); - PLT_HISTOGRAM("PLT.RequestToFinish", finish_all_loads - request); - } - PLT_HISTOGRAM("PLT.CommitToFinish", finish_all_loads - commit); - if (!first_paint.is_null()) { - DCHECK(begin <= first_paint); - PLT_HISTOGRAM("PLT.BeginToFirstPaint", first_paint - begin); - DCHECK(commit <= first_paint); - PLT_HISTOGRAM("PLT.CommitToFirstPaint", first_paint - commit); - } - if (!first_paint_after_load.is_null()) { - DCHECK(begin <= first_paint_after_load); - PLT_HISTOGRAM("PLT.BeginToFirstPaintAfterLoad", - first_paint_after_load - begin); - DCHECK(commit <= first_paint_after_load); - PLT_HISTOGRAM("PLT.CommitToFirstPaintAfterLoad", - first_paint_after_load - commit); - DCHECK(finish_all_loads <= first_paint_after_load); - PLT_HISTOGRAM("PLT.FinishToFirstPaintAfterLoad", - first_paint_after_load - finish_all_loads); - } - PLT_HISTOGRAM("PLT.BeginToFinishDoc", begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish", begin_to_finish_all_loads); - - // Load type related histograms. - switch (load_type) { - case NavigationState::UNDEFINED_LOAD: - PLT_HISTOGRAM("PLT.BeginToFinishDoc_UndefLoad", begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish_UndefLoad", begin_to_finish_all_loads); - break; - case NavigationState::RELOAD: - PLT_HISTOGRAM("PLT.BeginToFinishDoc_Reload", begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish_Reload", begin_to_finish_all_loads); - break; - case NavigationState::HISTORY_LOAD: - PLT_HISTOGRAM("PLT.BeginToFinishDoc_HistoryLoad", begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish_HistoryLoad", begin_to_finish_all_loads); - break; - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM("PLT.BeginToFinishDoc_NormalLoad", begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish_NormalLoad", begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM("PLT.BeginToFinishDoc_LinkLoadNormal", - begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish_LinkLoadNormal", - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_RELOAD: - PLT_HISTOGRAM("PLT.BeginToFinishDoc_LinkLoadReload", - begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish_LinkLoadReload", - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_STALE_OK: - PLT_HISTOGRAM("PLT.BeginToFinishDoc_LinkLoadStaleOk", - begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish_LinkLoadStaleOk", - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_ONLY: - PLT_HISTOGRAM("PLT.BeginToFinishDoc_LinkLoadCacheOnly", - begin_to_finish_doc); - PLT_HISTOGRAM("PLT.BeginToFinish_LinkLoadCacheOnly", - begin_to_finish_all_loads); - break; - default: - break; - } - - // Histograms to determine if DNS prefetching has an impact on PLT. - static bool use_dns_histogram(base::FieldTrialList::Find("DnsImpact") && - !base::FieldTrialList::Find("DnsImpact")->group_name().empty()); - if (use_dns_histogram) { - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.Abandoned", "DnsImpact"), - abandoned_page ? 1 : 0, 2); - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.LoadType", "DnsImpact"), - load_type, NavigationState::kLoadTypeMax); - switch (load_type) { - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_NormalLoad", "DnsImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadNormal", "DnsImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_RELOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadReload", "DnsImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_STALE_OK: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadStaleOk", "DnsImpact"), - begin_to_finish_all_loads); - break; - default: - break; - } - } - - // Histograms to determine if content prefetching has an impact on PLT. - static const bool prefetching_fieldtrial = - base::FieldTrialList::Find("Prefetch") && - !base::FieldTrialList::Find("Prefetch")->group_name().empty(); - if (prefetching_fieldtrial) { - if (navigation_state->was_prefetcher()) { - PLT_HISTOGRAM( - base::FieldTrial::MakeName("PLT.BeginToFinishDoc_ContentPrefetcher", - "Prefetch"), - begin_to_finish_doc); - PLT_HISTOGRAM( - base::FieldTrial::MakeName("PLT.BeginToFinish_ContentPrefetcher", - "Prefetch"), - begin_to_finish_all_loads); - } - if (navigation_state->was_referred_by_prefetcher()) { - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinishDoc_ContentPrefetcherReferrer", - "Prefetch"), - begin_to_finish_doc); - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_ContentPrefetcherReferrer", - "Prefetch"), - begin_to_finish_all_loads); - } - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.Abandoned", "Prefetch"), - abandoned_page ? 1 : 0, 2); - PLT_HISTOGRAM(base::FieldTrial::MakeName("PLT.BeginToFinishDoc", - "Prefetch"), - begin_to_finish_doc); - PLT_HISTOGRAM(base::FieldTrial::MakeName("PLT.BeginToFinish", "Prefetch"), - begin_to_finish_all_loads); - } - - // Histograms to determine if backup connection jobs have an impact on PLT. - static const bool connect_backup_jobs_fieldtrial( - base::FieldTrialList::Find("ConnnectBackupJobs") && - !base::FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty()); - if (connect_backup_jobs_fieldtrial) { - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.Abandoned", "ConnnectBackupJobs"), - abandoned_page ? 1 : 0, 2); - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.LoadType", "ConnnectBackupJobs"), - load_type, NavigationState::kLoadTypeMax); - switch (load_type) { - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_NormalLoad", "ConnnectBackupJobs"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadNormal", "ConnnectBackupJobs"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_RELOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadReload", "ConnnectBackupJobs"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_STALE_OK: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadStaleOk", "ConnnectBackupJobs"), - begin_to_finish_all_loads); - break; - default: - break; - } - } - - // Histograms to determine if the number of connections has an - // impact on PLT. - // TODO(jar): Consider removing the per-link-type versions. We - // really only need LINK_LOAD_NORMAL and NORMAL_LOAD. - static bool use_connection_impact_histogram( - base::FieldTrialList::Find("ConnCountImpact") && - !base::FieldTrialList::Find("ConnCountImpact")->group_name().empty()); - if (use_connection_impact_histogram) { - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.Abandoned", "ConnCountImpact"), - abandoned_page ? 1 : 0, 2); - switch (load_type) { - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_NormalLoad", "ConnCountImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadNormal", "ConnCountImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_RELOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadReload", "ConnCountImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_STALE_OK: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadStaleOk", "ConnCountImpact"), - begin_to_finish_all_loads); - break; - default: - break; - } - } - - // Histograms to determine effect of idle socket timeout. - static bool use_idle_socket_timeout_histogram( - base::FieldTrialList::Find("IdleSktToImpact") && - !base::FieldTrialList::Find("IdleSktToImpact")->group_name().empty()); - if (use_idle_socket_timeout_histogram) { - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.Abandoned", "IdleSktToImpact"), - abandoned_page ? 1 : 0, 2); - switch (load_type) { - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_NormalLoad", "IdleSktToImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadNormal", "IdleSktToImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_RELOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadReload", "IdleSktToImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_STALE_OK: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadStaleOk", "IdleSktToImpact"), - begin_to_finish_all_loads); - break; - default: - break; - } - } - - // Histograms to determine effect of number of connections per proxy. - static bool use_proxy_connection_impact_histogram( - base::FieldTrialList::Find("ProxyConnectionImpact") && - !base::FieldTrialList::Find("ProxyConnectionImpact")-> - group_name().empty()); - if (use_proxy_connection_impact_histogram) { - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.Abandoned", "ProxyConnectionImpact"), - abandoned_page ? 1 : 0, 2); - switch (load_type) { - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_NormalLoad", "ProxyConnectionImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadNormal", "ProxyConnectionImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_RELOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadReload", "ProxyConnectionImpact"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_STALE_OK: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadStaleOk", "ProxyConnectionImpact"), - begin_to_finish_all_loads); - break; - default: - break; - } - } - - // Histograms to determine if SDCH has an impact. - // TODO(jar): Consider removing per-link load types and the enumeration. - static bool use_sdch_histogram(base::FieldTrialList::Find("GlobalSdch") && - !base::FieldTrialList::Find("GlobalSdch")->group_name().empty()); - if (use_sdch_histogram) { - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.LoadType", "GlobalSdch"), - load_type, NavigationState::kLoadTypeMax); - switch (load_type) { - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_NormalLoad", "GlobalSdch"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadNormal", "GlobalSdch"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_RELOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadReload", "GlobalSdch"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_STALE_OK: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadStaleOk", "GlobalSdch"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_ONLY: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadCacheOnly", "GlobalSdch"), - begin_to_finish_all_loads); - break; - default: - break; - } - } - - // Histograms to determine if cache size has an impact on PLT. - static bool use_cache_histogram1(base::FieldTrialList::Find("CacheSize") && - !base::FieldTrialList::Find("CacheSize")->group_name().empty()); - if (use_cache_histogram1 && - NavigationState::LINK_LOAD_NORMAL <= load_type && - NavigationState::LINK_LOAD_CACHE_ONLY >= load_type) { - // TODO(mbelshe): Do we really want BeginToFinishDoc here? It seems like - // StartToFinish or BeginToFinish would be better. - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinishDoc_LinkLoad", "CacheSize"), begin_to_finish_doc); - } - - // Histograms to determine if cache throttling has an impact on PLT. - static bool use_cache_histogram2( - base::FieldTrialList::Find("CacheThrottle") && - !base::FieldTrialList::Find("CacheThrottle")->group_name().empty()); - if (use_cache_histogram2) { - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.Abandoned", "CacheThrottle"), - abandoned_page ? 1 : 0, 2); - switch (load_type) { - case NavigationState::RELOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_Reload", "CacheThrottle"), - begin_to_finish_all_loads); - break; - case NavigationState::HISTORY_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_HistoryLoad", "CacheThrottle"), - begin_to_finish_all_loads); - break; - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_NormalLoad", "CacheThrottle"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadNormal", "CacheThrottle"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_RELOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadReload", "CacheThrottle"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_STALE_OK: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadStaleOk", "CacheThrottle"), - begin_to_finish_all_loads); - break; - case NavigationState::LINK_LOAD_CACHE_ONLY: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadCacheOnly", "CacheThrottle"), - begin_to_finish_all_loads); - break; - default: - break; - } - if (NavigationState::RELOAD <= load_type && - NavigationState::LINK_LOAD_CACHE_ONLY >= load_type) { - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish", "CacheThrottle"), - begin_to_finish_all_loads); - } - } - - // For the SPDY field trials, we need to verify that the page loaded was - // the type we requested: - // if we asked for a SPDY request, we got a SPDY request - // if we asked for a HTTP request, we got a HTTP request - // Due to spdy version mismatches, it is possible that we ask for SPDY - // but didn't get SPDY. - static bool use_spdy_histogram(base::FieldTrialList::Find("SpdyImpact") && - !base::FieldTrialList::Find("SpdyImpact")->group_name().empty()); - if (use_spdy_histogram) { - // We take extra effort to only compute these once. - static bool in_spdy_trial = - base::FieldTrialList::Find("SpdyImpact")->group_name() == - "npn_with_spdy"; - static bool in_http_trial = - base::FieldTrialList::Find("SpdyImpact")->group_name() == - "npn_with_http"; - - bool spdy_trial_success = navigation_state->was_fetched_via_spdy() ? - in_spdy_trial : in_http_trial; - if (spdy_trial_success) { - // Histograms to determine if SPDY has an impact for https traffic. - // TODO(mbelshe): After we've seen the difference between BeginToFinish - // and StartToFinish, consider removing one or the other. - if (scheme_type == URLPattern::SCHEME_HTTPS && - navigation_state->was_npn_negotiated()) { - UMA_HISTOGRAM_ENUMERATION( - base::FieldTrial::MakeName("PLT.Abandoned", "SpdyImpact"), - abandoned_page ? 1 : 0, 2); - switch (load_type) { - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_LinkLoadNormal_SpdyTrial", "SpdyImpact"), - begin_to_finish_all_loads); - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.StartToFinish_LinkLoadNormal_SpdyTrial", "SpdyImpact"), - start_to_finish_all_loads); - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.StartToCommit_LinkLoadNormal_SpdyTrial", "SpdyImpact"), - start_to_commit); - break; - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.BeginToFinish_NormalLoad_SpdyTrial", "SpdyImpact"), - begin_to_finish_all_loads); - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.StartToFinish_NormalLoad_SpdyTrial", "SpdyImpact"), - start_to_finish_all_loads); - PLT_HISTOGRAM(base::FieldTrial::MakeName( - "PLT.StartToCommit_NormalLoad_SpdyTrial", "SpdyImpact"), - start_to_commit); - break; - default: - break; - } - } - - // Histograms to compare the impact of alternate protocol over http - // traffic: when spdy is used vs. when http is used. - if (scheme_type == URLPattern::SCHEME_HTTP && - navigation_state->was_alternate_protocol_available()) { - if (!navigation_state->was_npn_negotiated()) { - // This means that even there is alternate protocols for npn_http or - // npn_spdy, they are not taken (due to the base::FieldTrial). - switch (load_type) { - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM( - "PLT.StartToFinish_LinkLoadNormal_AlternateProtocol_http", - start_to_finish_all_loads); - PLT_HISTOGRAM( - "PLT.StartToCommit_LinkLoadNormal_AlternateProtocol_http", - start_to_commit); - break; - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM( - "PLT.StartToFinish_NormalLoad_AlternateProtocol_http", - start_to_finish_all_loads); - PLT_HISTOGRAM( - "PLT.StartToCommit_NormalLoad_AlternateProtocol_http", - start_to_commit); - break; - default: - break; - } - } else if (navigation_state->was_fetched_via_spdy()) { - switch (load_type) { - case NavigationState::LINK_LOAD_NORMAL: - PLT_HISTOGRAM( - "PLT.StartToFinish_LinkLoadNormal_AlternateProtocol_spdy", - start_to_finish_all_loads); - PLT_HISTOGRAM( - "PLT.StartToCommit_LinkLoadNormal_AlternateProtocol_spdy", - start_to_commit); - break; - case NavigationState::NORMAL_LOAD: - PLT_HISTOGRAM( - "PLT.StartToFinish_NormalLoad_AlternateProtocol_spdy", - start_to_finish_all_loads); - PLT_HISTOGRAM( - "PLT.StartToCommit_NormalLoad_AlternateProtocol_spdy", - start_to_commit); - break; - default: - break; - } - } - } - } - } - - // Record page load time and abandonment rates for proxy cases. - if (navigation_state->was_fetched_via_proxy()) { - if (scheme_type == URLPattern::SCHEME_HTTPS) { - PLT_HISTOGRAM("PLT.StartToFinish.Proxy.https", start_to_finish_all_loads); - UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned.Proxy.https", - abandoned_page ? 1 : 0, 2); - } else { - DCHECK(scheme_type == URLPattern::SCHEME_HTTP); - PLT_HISTOGRAM("PLT.StartToFinish.Proxy.http", start_to_finish_all_loads); - UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned.Proxy.http", - abandoned_page ? 1 : 0, 2); - } - } else { - if (scheme_type == URLPattern::SCHEME_HTTPS) { - PLT_HISTOGRAM("PLT.StartToFinish.NoProxy.https", - start_to_finish_all_loads); - UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned.NoProxy.https", - abandoned_page ? 1 : 0, 2); - } else { - DCHECK(scheme_type == URLPattern::SCHEME_HTTP); - PLT_HISTOGRAM("PLT.StartToFinish.NoProxy.http", - start_to_finish_all_loads); - UMA_HISTOGRAM_ENUMERATION("PLT.Abandoned.NoProxy.http", - abandoned_page ? 1 : 0, 2); - } - } - - // Site isolation metrics. - UMA_HISTOGRAM_COUNTS("SiteIsolation.PageLoadsWithCrossSiteFrameAccess", - cross_origin_access_count_); - UMA_HISTOGRAM_COUNTS("SiteIsolation.PageLoadsWithSameSiteFrameAccess", - same_origin_access_count_); - - // TODO(jar): This is the ONLY call in this method that needed more than - // navigation_state. This should be relocated, or changed, so that this - // body can be made a method on NavigationStates, and run via its destructor. - // Log some PLT data to the error log. - LogNavigationState(navigation_state, main_frame->dataSource()); - - navigation_state->set_load_histograms_recorded(true); - - // Since there are currently no guarantees that renderer histograms will be - // sent to the browser, we initiate a PostTask here to be sure that we send - // the histograms we generated. Without this call, pages that don't have an - // on-close-handler might generate data that is lost when the renderer is - // shutdown abruptly (perchance because the user closed the tab). - // TODO(jar) BUG=33233: This needs to be moved to a PostDelayedTask, and it - // should post when the onload is complete, so that it doesn't interfere with - // the next load. - if (RenderThread::current()) { - RenderThread::current()->SendHistograms( - chrome::kHistogramSynchronizerReservedSequenceNumber); - } -} - -void RenderView::LogNavigationState(const NavigationState* state, - const WebDataSource* ds) const { - // Because this function gets called on every page load, - // take extra care to optimize it away if logging is turned off. - if (logging::LOG_INFO < logging::GetMinLogLevel()) - return; - - DCHECK(state); - DCHECK(ds); - GURL url(ds->request().url()); - Time start = state->start_load_time(); - Time finish = state->finish_load_time(); - // TODO(mbelshe): should we log more stats? - VLOG(1) << "PLT: " << (finish - start).InMilliseconds() << "ms " - << url.spec(); -} - void RenderView::postAccessibilityNotification( const WebAccessibilityObject& obj, WebAccessibilityNotification notification) { diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index cd28c02..321faf0 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -28,6 +28,7 @@ #include "chrome/common/render_messages_params.h" #include "chrome/common/renderer_preferences.h" #include "chrome/common/view_types.h" +#include "chrome/renderer/page_load_histograms.h" #include "chrome/renderer/pepper_plugin_delegate_impl.h" #include "chrome/renderer/render_widget.h" #include "chrome/renderer/renderer_webcookiejar_impl.h" @@ -960,8 +961,6 @@ class RenderView : public RenderWidget, // image doesn't have a frame at the specified size, the first is returned. bool DownloadImage(int id, const GURL& image_url, int image_size); - void DumpLoadHistograms() const; - // Initializes the document_tag_ member if necessary. void EnsureDocumentTag(); @@ -1011,10 +1010,6 @@ class RenderView : public RenderWidget, const std::string& html, bool replace); - // Logs the navigation state to the console. - void LogNavigationState(const NavigationState* state, - const WebKit::WebDataSource* ds) const; - bool MaybeLoadAlternateErrorPage(WebKit::WebFrame* frame, const WebKit::WebURLError& error, bool replace); @@ -1174,11 +1169,6 @@ class RenderView : public RenderWidget, int document_tag_; - // Site isolation metrics flags. These are per-page-load counts, reset to 0 - // in OnClosePage. - int cross_origin_access_count_; - int same_origin_access_count_; - // UI state ------------------------------------------------------------------ // The state of our target_url transmissions. When we receive a request to @@ -1319,6 +1309,9 @@ class RenderView : public RenderWidget, // Device orientation dispatcher attached to this view; lazily initialized. scoped_ptr<DeviceOrientationDispatcher> device_orientation_dispatcher_; + // Responsible for sending page load related histograms. + PageLoadHistograms page_load_histograms_; + // Misc ---------------------------------------------------------------------- // The current and pending file chooser completion objects. If the queue is |