OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/renderer/page_load_histograms.h" | 5 #include "chrome/renderer/page_load_histograms.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
(...skipping 20 matching lines...) Expand all Loading... |
31 // Returns the scheme type of the given URL if its type is one for which we | 31 // Returns the scheme type of the given URL if its type is one for which we |
32 // dump page load histograms. Otherwise returns NULL. | 32 // dump page load histograms. Otherwise returns NULL. |
33 static URLPattern::SchemeMasks GetSupportedSchemeType(const GURL& url) { | 33 static URLPattern::SchemeMasks GetSupportedSchemeType(const GURL& url) { |
34 if (url.SchemeIs("http")) | 34 if (url.SchemeIs("http")) |
35 return URLPattern::SCHEME_HTTP; | 35 return URLPattern::SCHEME_HTTP; |
36 else if (url.SchemeIs("https")) | 36 else if (url.SchemeIs("https")) |
37 return URLPattern::SCHEME_HTTPS; | 37 return URLPattern::SCHEME_HTTPS; |
38 return static_cast<URLPattern::SchemeMasks>(0); | 38 return static_cast<URLPattern::SchemeMasks>(0); |
39 } | 39 } |
40 | 40 |
| 41 static void DumpWebTiming(const Time& navigation_start, |
| 42 const Time& load_event_start, |
| 43 const Time& load_event_end, |
| 44 NavigationState* navigation_state) { |
| 45 if (navigation_start.is_null() || |
| 46 load_event_start.is_null() || |
| 47 load_event_end.is_null()) |
| 48 return; |
| 49 |
| 50 if (navigation_state->web_timing_histograms_recorded()) |
| 51 return; |
| 52 navigation_state->set_web_timing_histograms_recorded(true); |
| 53 |
| 54 // TODO(tonyg): There are many new details we can record, add them after the |
| 55 // basic metrics are evaluated. |
| 56 // TODO(simonjam): There is no way to distinguish between abandonment and |
| 57 // intentional Javascript navigation before the load event fires. |
| 58 PLT_HISTOGRAM("PLT.NavStartToLoadStart", load_event_start - navigation_start); |
| 59 PLT_HISTOGRAM("PLT.NavStartToLoadEnd", load_event_end - navigation_start); |
| 60 } |
| 61 |
41 enum MissingStartType { | 62 enum MissingStartType { |
42 START_MISSING = 0x1, | 63 START_MISSING = 0x1, |
43 COMMIT_MISSING = 0x2, | 64 COMMIT_MISSING = 0x2, |
44 NAV_START_MISSING = 0x4, | 65 NAV_START_MISSING = 0x4, |
45 MISSING_START_TYPE_MAX = 0x8 | 66 MISSING_START_TYPE_MAX = 0x8 |
46 }; | 67 }; |
47 | 68 |
48 enum AbandonType { | 69 enum AbandonType { |
49 FINISH_DOC_MISSING = 0x1, | 70 FINISH_DOC_MISSING = 0x1, |
50 FINISH_ALL_LOADS_MISSING = 0x2, | 71 FINISH_ALL_LOADS_MISSING = 0x2, |
(...skipping 11 matching lines...) Expand all Loading... |
62 // We only dump histograms for main frames. | 83 // We only dump histograms for main frames. |
63 // In the future, it may be interesting to tag subframes and dump them too. | 84 // In the future, it may be interesting to tag subframes and dump them too. |
64 if (!frame || frame->parent()) | 85 if (!frame || frame->parent()) |
65 return; | 86 return; |
66 | 87 |
67 // Only dump for supported schemes. | 88 // Only dump for supported schemes. |
68 URLPattern::SchemeMasks scheme_type = GetSupportedSchemeType(frame->url()); | 89 URLPattern::SchemeMasks scheme_type = GetSupportedSchemeType(frame->url()); |
69 if (scheme_type == 0) | 90 if (scheme_type == 0) |
70 return; | 91 return; |
71 | 92 |
72 // If we've already dumped, do nothing. | |
73 // This simple bool works because we only dump for the main frame. | |
74 NavigationState* navigation_state = | 93 NavigationState* navigation_state = |
75 NavigationState::FromDataSource(frame->dataSource()); | 94 NavigationState::FromDataSource(frame->dataSource()); |
76 if (navigation_state->load_histograms_recorded()) | |
77 return; | |
78 | 95 |
79 // Times based on the Web Timing metrics. | 96 // Times based on the Web Timing metrics. |
80 // https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview
.html | 97 // http://www.w3.org/TR/navigation-timing/ |
81 // TODO(tonyg, jar): We are in the process of vetting these metrics against | 98 // TODO(tonyg, jar): We are in the process of vetting these metrics against |
82 // the existing ones. Once we understand any differences, we will standardize | 99 // the existing ones. Once we understand any differences, we will standardize |
83 // on a single set of metrics. | 100 // on a single set of metrics. |
84 const WebPerformance& performance = frame->performance(); | 101 const WebPerformance& performance = frame->performance(); |
85 Time navigation_start = Time::FromDoubleT(performance.navigationStart()); | 102 Time navigation_start = Time::FromDoubleT(performance.navigationStart()); |
86 Time load_event_start = Time::FromDoubleT(performance.loadEventStart()); | 103 Time load_event_start = Time::FromDoubleT(performance.loadEventStart()); |
87 Time load_event_end = Time::FromDoubleT(performance.loadEventEnd()); | 104 Time load_event_end = Time::FromDoubleT(performance.loadEventEnd()); |
| 105 DumpWebTiming(navigation_start, load_event_start, load_event_end, |
| 106 navigation_state); |
| 107 |
| 108 // If we've already dumped, do nothing. |
| 109 // This simple bool works because we only dump for the main frame. |
| 110 if (navigation_state->load_histograms_recorded()) |
| 111 return; |
88 | 112 |
89 // Collect measurement times. | 113 // Collect measurement times. |
90 Time start = navigation_state->start_load_time(); | 114 Time start = navigation_state->start_load_time(); |
91 Time commit = navigation_state->commit_load_time(); | 115 Time commit = navigation_state->commit_load_time(); |
92 | 116 |
93 // TODO(tonyg, jar): We aren't certain why the start is missing sometimes, but | 117 // TODO(tonyg, jar): Start can be missing after an in-document navigation and |
94 // we presume it is a very premature abandonment of the page. | 118 // possibly other cases like a very premature abandonment of the page. |
95 // The PLT.MissingStart histogram should help us troubleshoot and then we can | 119 // The PLT.MissingStart histogram should help us troubleshoot and then we can |
96 // remove this. | 120 // remove this. |
97 int missing_start_type = 0; | 121 int missing_start_type = 0; |
98 missing_start_type |= start.is_null() ? START_MISSING : 0; | 122 missing_start_type |= start.is_null() ? START_MISSING : 0; |
99 missing_start_type |= commit.is_null() ? COMMIT_MISSING : 0; | 123 missing_start_type |= commit.is_null() ? COMMIT_MISSING : 0; |
100 missing_start_type |= navigation_start.is_null() ? NAV_START_MISSING : 0; | 124 missing_start_type |= navigation_start.is_null() ? NAV_START_MISSING : 0; |
101 UMA_HISTOGRAM_ENUMERATION("PLT.MissingStart", missing_start_type, | 125 UMA_HISTOGRAM_ENUMERATION("PLT.MissingStart", missing_start_type, |
102 MISSING_START_TYPE_MAX); | 126 MISSING_START_TYPE_MAX); |
103 if (missing_start_type) | 127 if (missing_start_type) |
104 return; | 128 return; |
105 | 129 |
106 // Record the new PLT times prior to the faulty abandon check below. | |
107 // TODO(tonyg): There are many new details we can record, add them after the | |
108 // basic metrics are evaluated. | |
109 // TODO(simonjam): There is no way to distinguish between abandonment and | |
110 // intentional Javascript navigation before the load event fires. | |
111 if (!load_event_start.is_null()) | |
112 PLT_HISTOGRAM("PLT.NavStartToLoadStart", | |
113 load_event_start - navigation_start); | |
114 if (!load_event_end.is_null()) | |
115 PLT_HISTOGRAM("PLT.NavStartToLoadEnd", load_event_end - navigation_start); | |
116 | |
117 // We properly handle null values for the next 3 variables. | 130 // We properly handle null values for the next 3 variables. |
118 Time request = navigation_state->request_time(); | 131 Time request = navigation_state->request_time(); |
119 Time first_paint = navigation_state->first_paint_time(); | 132 Time first_paint = navigation_state->first_paint_time(); |
120 Time first_paint_after_load = navigation_state->first_paint_after_load_time(); | 133 Time first_paint_after_load = navigation_state->first_paint_after_load_time(); |
121 Time finish_doc = navigation_state->finish_document_load_time(); | 134 Time finish_doc = navigation_state->finish_document_load_time(); |
122 Time finish_all_loads = navigation_state->finish_load_time(); | 135 Time finish_all_loads = navigation_state->finish_load_time(); |
123 | 136 |
124 // TODO(tonyg, jar): We suspect a bug in abandonment counting, this temporary | 137 // TODO(tonyg, jar): We suspect a bug in abandonment counting, this temporary |
125 // historgram should help us to troubleshoot. | 138 // histogram should help us to troubleshoot. |
126 int abandon_type = 0; | 139 int abandon_type = 0; |
127 abandon_type |= finish_doc.is_null() ? FINISH_DOC_MISSING : 0; | 140 abandon_type |= finish_doc.is_null() ? FINISH_DOC_MISSING : 0; |
128 abandon_type |= finish_all_loads.is_null() ? FINISH_ALL_LOADS_MISSING : 0; | 141 abandon_type |= finish_all_loads.is_null() ? FINISH_ALL_LOADS_MISSING : 0; |
129 abandon_type |= load_event_start.is_null() ? LOAD_EVENT_START_MISSING : 0; | 142 abandon_type |= load_event_start.is_null() ? LOAD_EVENT_START_MISSING : 0; |
130 abandon_type |= load_event_end.is_null() ? LOAD_EVENT_END_MISSING : 0; | 143 abandon_type |= load_event_end.is_null() ? LOAD_EVENT_END_MISSING : 0; |
131 UMA_HISTOGRAM_ENUMERATION("PLT.AbandonType", abandon_type, ABANDON_TYPE_MAX); | 144 UMA_HISTOGRAM_ENUMERATION("PLT.AbandonType", abandon_type, ABANDON_TYPE_MAX); |
132 | 145 |
133 // Handle case where user hits "stop" or "back" before loading completely. | 146 // Handle case where user hits "stop" or "back" before loading completely. |
134 bool abandoned_page = finish_doc.is_null(); | 147 bool abandoned_page = finish_doc.is_null(); |
135 if (abandoned_page) { | 148 if (abandoned_page) { |
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 | 783 |
771 DCHECK(state); | 784 DCHECK(state); |
772 DCHECK(ds); | 785 DCHECK(ds); |
773 GURL url(ds->request().url()); | 786 GURL url(ds->request().url()); |
774 Time start = state->start_load_time(); | 787 Time start = state->start_load_time(); |
775 Time finish = state->finish_load_time(); | 788 Time finish = state->finish_load_time(); |
776 // TODO(mbelshe): should we log more stats? | 789 // TODO(mbelshe): should we log more stats? |
777 VLOG(1) << "PLT: " << (finish - start).InMilliseconds() << "ms " | 790 VLOG(1) << "PLT: " << (finish - start).InMilliseconds() << "ms " |
778 << url.spec(); | 791 << url.spec(); |
779 } | 792 } |
OLD | NEW |