OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "components/page_load_metrics/browser/metrics_web_contents_observer.h" | 5 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "components/page_load_metrics/common/page_load_metrics_messages.h" | 9 #include "components/page_load_metrics/common/page_load_metrics_messages.h" |
10 #include "components/page_load_metrics/common/page_load_timing.h" | 10 #include "components/page_load_metrics/common/page_load_timing.h" |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 } | 57 } |
58 | 58 |
59 } // namespace | 59 } // namespace |
60 | 60 |
61 #define PAGE_LOAD_HISTOGRAM(name, sample) \ | 61 #define PAGE_LOAD_HISTOGRAM(name, sample) \ |
62 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \ | 62 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \ |
63 base::TimeDelta::FromMilliseconds(10), \ | 63 base::TimeDelta::FromMilliseconds(10), \ |
64 base::TimeDelta::FromMinutes(10), 100) | 64 base::TimeDelta::FromMinutes(10), 100) |
65 | 65 |
66 PageLoadTracker::PageLoadTracker(bool in_foreground) | 66 PageLoadTracker::PageLoadTracker(bool in_foreground) |
67 : has_commit_(false), started_in_foreground_(in_foreground) { | 67 : has_commit_(false), started_in_foreground_(in_foreground) {} |
68 RecordEvent(PAGE_LOAD_STARTED); | |
69 } | |
70 | 68 |
71 PageLoadTracker::~PageLoadTracker() { | 69 PageLoadTracker::~PageLoadTracker() { |
72 // Even a load that failed a provisional load should log | |
73 // that it aborted before first layout. | |
74 if (timing_.first_layout.is_zero()) | |
75 RecordEvent(PAGE_LOAD_ABORTED_BEFORE_FIRST_LAYOUT); | |
76 | |
77 if (has_commit_) | 70 if (has_commit_) |
78 RecordTimingHistograms(); | 71 RecordTimingHistograms(); |
79 } | 72 } |
80 | 73 |
81 void PageLoadTracker::WebContentsHidden() { | 74 void PageLoadTracker::WebContentsHidden() { |
82 // Only log the first time we background in a given page load. | 75 // Only log the first time we background in a given page load. |
83 if (background_time_.is_null()) { | 76 if (started_in_foreground_ && background_time_.is_null()) |
84 background_time_ = base::TimeTicks::Now(); | 77 background_time_ = base::TimeTicks::Now(); |
85 } | 78 } |
| 79 |
| 80 void PageLoadTracker::WebContentsShown() { |
| 81 // Only log the first time we foreground in a given page load. |
| 82 // Don't log foreground time if we started foregrounded. |
| 83 if (!started_in_foreground_ && foreground_time_.is_null()) |
| 84 foreground_time_ = base::TimeTicks::Now(); |
86 } | 85 } |
87 | 86 |
88 void PageLoadTracker::Commit() { | 87 void PageLoadTracker::Commit() { |
89 has_commit_ = true; | 88 has_commit_ = true; |
| 89 if (started_in_foreground_) |
| 90 RecordCommittedEvent(COMMITTED_LOAD_STARTED_IN_FOREGROUND); |
| 91 else |
| 92 RecordCommittedEvent(COMMITTED_LOAD_STARTED_IN_BACKGROUND); |
90 } | 93 } |
91 | 94 |
92 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& timing) { | 95 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing) { |
93 // Throw away IPCs that are not relevant to the current navigation. | 96 // Throw away IPCs that are not relevant to the current navigation. |
94 if (!timing_.navigation_start.is_null() && | 97 // A valid timing struct is one that has the same navigation start as the |
95 timing_.navigation_start != timing.navigation_start) { | 98 // previous one (if the previous one had a navigation start at all). |
96 // TODO(csharrison) uma log a counter here | 99 bool valid_timing_descendent = |
97 return false; | 100 timing_.navigation_start.is_null() || |
98 } | 101 timing_.navigation_start == new_timing.navigation_start; |
99 if (IsValidPageLoadTiming(timing)) { | 102 if (IsValidPageLoadTiming(new_timing) && valid_timing_descendent) { |
100 timing_ = timing; | 103 timing_ = new_timing; |
101 return true; | 104 return true; |
102 } | 105 } |
| 106 RecordCommittedEvent(COMMITTED_LOAD_BAD_IPC); |
103 return false; | 107 return false; |
104 } | 108 } |
105 | 109 |
106 void PageLoadTracker::RecordTimingHistograms() { | 110 void PageLoadTracker::RecordTimingHistograms() { |
107 DCHECK(has_commit_); | 111 DCHECK(has_commit_); |
108 // This method is similar to how blink converts TimeTicks to epoch time. | 112 // This method is similar to how blink converts TimeTicks to epoch time. |
109 // There may be slight inaccuracies due to inter-process timestamps, but | 113 // There may be slight inaccuracies due to inter-process timestamps, but |
110 // this solution is the best we have right now. | 114 // this solution is the best we have right now. |
111 base::TimeDelta background_delta; | 115 base::TimeDelta background_delta; |
112 if (started_in_foreground_) { | 116 if (started_in_foreground_) { |
(...skipping 15 matching lines...) Expand all Loading... |
128 } | 132 } |
129 if (!timing_.load_event_start.is_zero()) { | 133 if (!timing_.load_event_start.is_zero()) { |
130 if (timing_.load_event_start < background_delta) { | 134 if (timing_.load_event_start < background_delta) { |
131 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired", | 135 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired", |
132 timing_.load_event_start); | 136 timing_.load_event_start); |
133 } else { | 137 } else { |
134 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired.BG", | 138 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired.BG", |
135 timing_.load_event_start); | 139 timing_.load_event_start); |
136 } | 140 } |
137 } | 141 } |
138 if (!timing_.first_layout.is_zero()) { | 142 if (timing_.first_layout.is_zero()) { |
| 143 RecordCommittedEvent(COMMITTED_LOAD_ABORTED_BEFORE_FIRST_LAYOUT); |
| 144 } else { |
139 if (timing_.first_layout < background_delta) { | 145 if (timing_.first_layout < background_delta) { |
140 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout", | 146 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout", |
141 timing_.first_layout); | 147 timing_.first_layout); |
142 RecordEvent(PAGE_LOAD_SUCCESSFUL_FIRST_LAYOUT_FOREGROUND); | 148 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT_FOREGROUND); |
143 } else { | 149 } else { |
144 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout.BG", | 150 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout.BG", |
145 timing_.first_layout); | 151 timing_.first_layout); |
146 RecordEvent(PAGE_LOAD_SUCCESSFUL_FIRST_LAYOUT_BACKGROUND); | 152 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT_BACKGROUND); |
147 } | 153 } |
148 } | 154 } |
149 | 155 // Log time to first foreground / time to first background. Log counts that we |
| 156 // started a relevant page load in the foreground / background. |
| 157 if (!background_time_.is_null()) { |
| 158 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstBackground", |
| 159 background_delta); |
| 160 } else if (!foreground_time_.is_null()) { |
| 161 PAGE_LOAD_HISTOGRAM( |
| 162 "PageLoad.Timing2.NavigationToFirstForeground", |
| 163 WallTimeFromTimeTicks(foreground_time_) - timing_.navigation_start); |
| 164 } |
150 } | 165 } |
151 | 166 |
152 void PageLoadTracker::RecordEvent(PageLoadEvent event) { | 167 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { |
153 UMA_HISTOGRAM_ENUMERATION( | 168 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Provisional", event, |
154 "PageLoad.EventCounts", event, PAGE_LOAD_LAST_ENTRY); | 169 PROVISIONAL_LOAD_LAST_ENTRY); |
| 170 } |
| 171 |
| 172 void PageLoadTracker::RecordCommittedEvent(CommittedLoadEvent event) { |
| 173 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Committed", event, |
| 174 COMMITTED_LOAD_LAST_ENTRY); |
155 } | 175 } |
156 | 176 |
157 MetricsWebContentsObserver::MetricsWebContentsObserver( | 177 MetricsWebContentsObserver::MetricsWebContentsObserver( |
158 content::WebContents* web_contents) | 178 content::WebContents* web_contents) |
159 : content::WebContentsObserver(web_contents), in_foreground_(false) {} | 179 : content::WebContentsObserver(web_contents), in_foreground_(false) {} |
160 | 180 |
161 MetricsWebContentsObserver::~MetricsWebContentsObserver() {} | 181 MetricsWebContentsObserver::~MetricsWebContentsObserver() {} |
162 | 182 |
163 bool MetricsWebContentsObserver::OnMessageReceived( | 183 bool MetricsWebContentsObserver::OnMessageReceived( |
164 const IPC::Message& message, | 184 const IPC::Message& message, |
(...skipping 25 matching lines...) Expand all Loading... |
190 if (!navigation_handle->IsInMainFrame()) | 210 if (!navigation_handle->IsInMainFrame()) |
191 return; | 211 return; |
192 | 212 |
193 scoped_ptr<PageLoadTracker> finished_nav( | 213 scoped_ptr<PageLoadTracker> finished_nav( |
194 provisional_loads_.take_and_erase(navigation_handle)); | 214 provisional_loads_.take_and_erase(navigation_handle)); |
195 DCHECK(finished_nav); | 215 DCHECK(finished_nav); |
196 | 216 |
197 // Handle a pre-commit error here. Navigations that result in an error page | 217 // Handle a pre-commit error here. Navigations that result in an error page |
198 // will be ignored. | 218 // will be ignored. |
199 if (!navigation_handle->HasCommitted()) { | 219 if (!navigation_handle->HasCommitted()) { |
200 finished_nav->RecordEvent(PAGE_LOAD_FAILED_BEFORE_COMMIT); | |
201 if (navigation_handle->GetNetErrorCode() == net::ERR_ABORTED) | 220 if (navigation_handle->GetNetErrorCode() == net::ERR_ABORTED) |
202 finished_nav->RecordEvent(PAGE_LOAD_ABORTED_BEFORE_COMMIT); | 221 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_ABORTED); |
| 222 else |
| 223 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_FAILED_NON_ABORT); |
203 return; | 224 return; |
204 } | 225 } |
| 226 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED); |
205 | 227 |
206 // Don't treat a same-page nav as a new page load. | 228 // Don't treat a same-page nav as a new page load. |
207 if (navigation_handle->IsSamePage()) | 229 if (navigation_handle->IsSamePage()) |
208 return; | 230 return; |
209 | 231 |
210 // Eagerly log the previous UMA even if we don't care about the current | 232 // Eagerly log the previous UMA even if we don't care about the current |
211 // navigation. | 233 // navigation. |
212 committed_load_.reset(); | 234 committed_load_.reset(); |
213 | 235 |
214 if (!IsRelevantNavigation(navigation_handle)) | 236 if (!IsRelevantNavigation(navigation_handle)) |
215 return; | 237 return; |
216 | 238 |
217 committed_load_ = finished_nav.Pass(); | 239 committed_load_ = finished_nav.Pass(); |
218 committed_load_->Commit(); | 240 committed_load_->Commit(); |
219 } | 241 } |
220 | 242 |
221 void MetricsWebContentsObserver::WasShown() { | 243 void MetricsWebContentsObserver::WasShown() { |
222 in_foreground_ = true; | 244 in_foreground_ = true; |
| 245 if (committed_load_) |
| 246 committed_load_->WebContentsShown(); |
| 247 for (const auto& kv : provisional_loads_) { |
| 248 kv.second->WebContentsShown(); |
| 249 } |
223 } | 250 } |
224 | 251 |
225 void MetricsWebContentsObserver::WasHidden() { | 252 void MetricsWebContentsObserver::WasHidden() { |
226 in_foreground_ = false; | 253 in_foreground_ = false; |
227 if (committed_load_) | 254 if (committed_load_) |
228 committed_load_->WebContentsHidden(); | 255 committed_load_->WebContentsHidden(); |
229 for (const auto& kv : provisional_loads_) { | 256 for (const auto& kv : provisional_loads_) { |
230 kv.second->WebContentsHidden(); | 257 kv.second->WebContentsHidden(); |
231 } | 258 } |
232 } | 259 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 // sure here that we aren't logging UMA for internal pages. | 293 // sure here that we aren't logging UMA for internal pages. |
267 const GURL& browser_url = web_contents()->GetLastCommittedURL(); | 294 const GURL& browser_url = web_contents()->GetLastCommittedURL(); |
268 return navigation_handle->IsInMainFrame() && | 295 return navigation_handle->IsInMainFrame() && |
269 !navigation_handle->IsSamePage() && | 296 !navigation_handle->IsSamePage() && |
270 !navigation_handle->IsErrorPage() && | 297 !navigation_handle->IsErrorPage() && |
271 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() && | 298 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() && |
272 browser_url.SchemeIsHTTPOrHTTPS(); | 299 browser_url.SchemeIsHTTPOrHTTPS(); |
273 } | 300 } |
274 | 301 |
275 } // namespace page_load_metrics | 302 } // namespace page_load_metrics |
OLD | NEW |