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 "chrome/browser/sessions/session_restore_stats_collector.h" | 5 #include "chrome/browser/sessions/session_restore_stats_collector.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
11 #include "content/public/browser/notification_service.h" | 11 #include "content/public/browser/notification_service.h" |
12 #include "content/public/browser/notification_types.h" | 12 #include "content/public/browser/notification_types.h" |
13 #include "content/public/browser/render_widget_host_view.h" | 13 #include "content/public/browser/render_widget_host_view.h" |
14 #include "content/public/browser/web_contents.h" | 14 #include "content/public/browser/web_contents.h" |
15 | 15 |
16 namespace { | |
17 | |
16 using content::NavigationController; | 18 using content::NavigationController; |
17 using content::RenderWidgetHost; | 19 using content::RenderWidgetHost; |
20 using content::Source; | |
18 using content::WebContents; | 21 using content::WebContents; |
19 | 22 |
20 // static | 23 const char kSessionRestoreActions[] = "SessionRestore.Actions"; |
21 void SessionRestoreStatsCollector::TrackTabs( | |
22 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, | |
23 const base::TimeTicks& restore_started) { | |
24 if (!shared_collector_) | |
25 shared_collector_ = new SessionRestoreStatsCollector(restore_started); | |
26 | 24 |
27 shared_collector_->AddTabs(tabs); | 25 // The enumeration values stored in the "SessionRestore.Actions" histogram. |
26 enum SessionRestoreActionsUma { | |
27 // Counts the total number of session restores that have occurred. | |
28 SESSION_RESTORE_ACTIONS_UMA_INITIATED = 0, | |
29 // Counts the number of session restores that have seen deferred tab loadings | |
30 // for whatever reason (almost certainly due to memory pressure). | |
31 SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS = 1, | |
32 // The size of this enum. Must be the last entry. | |
33 SESSION_RESTORE_ACTIONS_UMA_MAX, | |
34 }; | |
35 | |
36 // The enumeration of values stored in the "SessionRestore.TabActions" | |
37 // histogram. | |
38 enum SessionRestoreTabActionsUma { | |
39 // Incremented for each tab created in a session restore. | |
40 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED = 0, | |
41 // Incremented for each tab that session restore decides not to load. | |
42 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED = 1, | |
43 // Incremented for each tab that is successfully loaded. | |
44 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED = 2, | |
45 // Incremented for each session-restore-deferred tab that is subsequently | |
46 // loaded. | |
47 SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED = 3, | |
48 // The size of this enum. Must be the last entry. | |
49 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX, | |
50 }; | |
51 | |
52 } // namespace | |
53 | |
54 SessionRestoreStatsCollector::TabLoaderStats::TabLoaderStats() | |
55 : tab_count(0u), tabs_loaded(0u), parallel_tab_loads(0u) { | |
28 } | 56 } |
29 | 57 |
30 // static | 58 SessionRestoreStatsCollector::TabState::TabState( |
31 void SessionRestoreStatsCollector::TrackActiveTabs( | 59 NavigationController* controller) |
32 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, | 60 : controller(controller), |
33 const base::TimeTicks& restore_started) { | 61 render_widget_host(nullptr), |
34 if (!shared_collector_) | 62 is_deferred(false), |
35 shared_collector_ = new SessionRestoreStatsCollector(restore_started); | 63 loading_state(TAB_IS_NOT_LOADING) { |
36 | |
37 std::vector<SessionRestoreDelegate::RestoredTab> active_tabs; | |
38 for (auto tab : tabs) { | |
39 if (tab.is_active()) | |
40 active_tabs.push_back(tab); | |
41 } | |
42 shared_collector_->AddTabs(active_tabs); | |
43 } | 64 } |
44 | 65 |
45 SessionRestoreStatsCollector::SessionRestoreStatsCollector( | 66 SessionRestoreStatsCollector::SessionRestoreStatsCollector( |
46 const base::TimeTicks& restore_started) | 67 const base::TimeTicks& restore_started) |
47 : got_first_foreground_load_(false), | 68 : got_done_tracking_non_deferred_tabs_(false), |
69 got_first_foreground_load_(false), | |
48 got_first_paint_(false), | 70 got_first_paint_(false), |
71 got_report_tab_deferred_(false), | |
49 restore_started_(restore_started), | 72 restore_started_(restore_started), |
50 tab_count_(0), | 73 waiting_for_load_tab_count_(0u), |
51 max_parallel_tab_loads_(0) { | 74 loading_tab_count_(0u) { |
52 this_retainer_ = this; | 75 this_retainer_ = this; |
53 registrar_.Add( | |
54 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | |
55 content::NotificationService::AllSources()); | |
56 } | 76 } |
57 | 77 |
58 SessionRestoreStatsCollector::~SessionRestoreStatsCollector() { | 78 SessionRestoreStatsCollector::~SessionRestoreStatsCollector() { |
59 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && | 79 // The collector should only be destroyed when tracking is entirely |
sky
2015/05/27 15:18:39
Is this true if shutdown happens before everything
chrisha
2015/06/03 21:16:36
Very good point. Removed.
| |
60 tabs_tracked_.empty() && render_widget_hosts_loading_.empty()); | 80 // finished. |
61 DCHECK(shared_collector_ == this); | 81 DCHECK(DoneTracking()); |
62 shared_collector_ = nullptr; | 82 } |
83 | |
84 void SessionRestoreStatsCollector::TrackTabs( | |
85 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) { | |
86 DCHECK(!got_done_tracking_non_deferred_tabs_); | |
87 | |
88 // If this is the first call to TrackTabs then start observing events. | |
89 if (tab_loader_stats_.tab_count == 0) { | |
90 registrar_.Add( | |
91 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | |
92 content::NotificationService::AllSources()); | |
93 } | |
94 | |
95 tab_loader_stats_.tab_count += tabs.size(); | |
96 waiting_for_load_tab_count_ += tabs.size(); | |
97 for (auto& tab : tabs) { | |
98 TabState* tab_state = RegisterForNotifications( | |
99 &tab.contents()->GetController()); | |
100 // Active tabs have already started loading, kicked by the TabLoader. | |
sky
2015/05/27 15:18:39
Actually, don't they start loading because they ar
chrisha
2015/06/03 21:16:36
Acknowledged.
| |
101 if (tab.is_active()) | |
102 MarkTabAsLoading(tab_state); | |
103 } | |
104 } | |
105 | |
106 void SessionRestoreStatsCollector::DeferTab(NavigationController* tab) { | |
107 TabState* tab_state = GetTabState(tab); | |
108 | |
109 // If the tab is no longer being tracked it has already finished loading. | |
110 // This can occur if the user forces the tab to load before the entire session | |
111 // restore is over, and the TabLoader then decides it would defer loading of | |
112 // that tab. | |
113 if (!tab_state) | |
114 return; | |
115 | |
116 // Mark this tab as deferred, if its still being tracked. A tab should not be | |
117 // marked as deferred twice. | |
118 DCHECK(!tab_state->is_deferred); | |
119 tab_state->is_deferred = true; | |
120 | |
121 // A tab that didn't start loading before it was deferred is not to be | |
122 // actively monitored for loading. | |
123 if (tab_state->loading_state == TAB_IS_NOT_LOADING) | |
124 --waiting_for_load_tab_count_; | |
sky
2015/05/27 15:18:39
Might waiting_for_load_tab_count_ be 0 now?
chrisha
2015/06/03 21:16:36
Yeah, it might. I thought it simpler to keep all o
sky
2015/06/03 22:00:07
Helper function SGTM.
chrisha
2015/06/04 14:04:47
Done.
| |
125 | |
126 ReportTabDeferred(); | |
63 } | 127 } |
64 | 128 |
65 void SessionRestoreStatsCollector::Observe( | 129 void SessionRestoreStatsCollector::Observe( |
66 int type, | 130 int type, |
67 const content::NotificationSource& source, | 131 const content::NotificationSource& source, |
68 const content::NotificationDetails& details) { | 132 const content::NotificationDetails& details) { |
69 switch (type) { | 133 switch (type) { |
70 case content::NOTIFICATION_LOAD_START: { | 134 case content::NOTIFICATION_LOAD_START: { |
71 // Add this render_widget_host to the set of those we're waiting for | 135 // This occurs when a tab has started to load. This can be because of |
72 // paints on. We want to only record stats for paints that occur after | 136 // the tab loader (only for non-deferred tabs) or because the user clicked |
73 // a load has finished. | 137 // on the tab. |
74 NavigationController* tab = | 138 NavigationController* tab = Source<NavigationController>(source).ptr(); |
75 content::Source<NavigationController>(source).ptr(); | 139 TabState* tab_state = GetTabState(tab); |
76 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); | 140 MarkTabAsLoading(tab_state); |
77 DCHECK(render_widget_host); | |
78 render_widget_hosts_loading_.insert(render_widget_host); | |
79 break; | 141 break; |
80 } | 142 } |
81 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { | 143 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { |
82 WebContents* web_contents = content::Source<WebContents>(source).ptr(); | 144 // This happens when a tab has been closed. A tab can be in any state |
83 RemoveTab(&web_contents->GetController()); | 145 // when this occurs. Simply stop tracking the tab. |
146 WebContents* web_contents = Source<WebContents>(source).ptr(); | |
sky
2015/05/27 15:18:39
Code seems to assume we'll get a LOAD_STOP before
chrisha
2015/06/03 21:16:36
Another great catch.
I'm not sure if that's guara
| |
147 NavigationController* tab = &web_contents->GetController(); | |
148 RemoveTab(tab); | |
84 break; | 149 break; |
85 } | 150 } |
86 case content::NOTIFICATION_LOAD_STOP: { | 151 case content::NOTIFICATION_LOAD_STOP: { |
87 NavigationController* tab = | 152 // This occurs to loading tabs when they have finished loading. The tab |
88 content::Source<NavigationController>(source).ptr(); | 153 // may or may not already have painted at this point. |
89 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); | 154 |
90 render_widget_hosts_to_paint_.insert(render_widget_host); | 155 // Update the tab state and any global state as necessary. |
91 RemoveTab(tab); | 156 NavigationController* tab = Source<NavigationController>(source).ptr(); |
92 if (!got_first_foreground_load_ && render_widget_host && | 157 TabState* tab_state = GetTabState(tab); |
93 render_widget_host->GetView() && | 158 DCHECK(tab_state); |
94 render_widget_host->GetView()->IsShowing()) { | 159 tab_state->loading_state = TAB_IS_LOADED; |
160 --loading_tab_count_; | |
161 if (!tab_state->is_deferred) | |
162 --waiting_for_load_tab_count_; | |
163 | |
164 // Update statistics. | |
sky
2015/05/27 15:18:39
nit: this comment isn't really useful, I would nuk
chrisha
2015/06/03 21:16:36
Done.
| |
165 if (tab_state->is_deferred) { | |
166 ReportDeferredTabLoaded(); | |
167 } else { | |
168 DCHECK(!got_done_tracking_non_deferred_tabs_); | |
169 ++tab_loader_stats_.tabs_loaded; | |
170 } | |
171 | |
172 // Update UMA stats for foreground tabs. | |
173 if (!got_first_foreground_load_ && | |
174 tab_state->render_widget_host && | |
175 tab_state->render_widget_host->GetView() && | |
176 tab_state->render_widget_host->GetView()->IsShowing()) { | |
95 got_first_foreground_load_ = true; | 177 got_first_foreground_load_ = true; |
96 base::TimeDelta time_to_load = | 178 base::TimeDelta time_to_load = |
97 base::TimeTicks::Now() - restore_started_; | 179 base::TimeTicks::Now() - restore_started_; |
98 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded", | 180 DCHECK(!got_done_tracking_non_deferred_tabs_); |
99 time_to_load, | 181 tab_loader_stats_.foreground_tab_first_loaded = time_to_load; |
100 base::TimeDelta::FromMilliseconds(10), | |
101 base::TimeDelta::FromSeconds(100), 100); | |
102 // Record a time for the number of tabs, to help track down | |
103 // contention. | |
104 std::string time_for_count = base::StringPrintf( | |
105 "SessionRestore.ForegroundTabFirstLoaded_%d", tab_count_); | |
106 base::HistogramBase* counter_for_count = | |
107 base::Histogram::FactoryTimeGet( | |
108 time_for_count, base::TimeDelta::FromMilliseconds(10), | |
109 base::TimeDelta::FromSeconds(100), 100, | |
110 base::Histogram::kUmaTargetedHistogramFlag); | |
111 counter_for_count->AddTime(time_to_load); | |
112 } | 182 } |
183 | |
184 // If first paint has already been observed then there's no need to keep | |
sky
2015/05/27 15:18:39
This comment explains what the code does not why.
chrisha
2015/06/03 21:16:36
Done.
| |
185 // tracking this tab. | |
186 if (got_first_paint_) | |
187 RemoveTab(tab); | |
188 | |
113 break; | 189 break; |
114 } | 190 } |
115 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: { | 191 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: { |
192 // This notification is across all tabs in the browser so notifications | |
193 // will arrive for tabs that the collector is not explicitly tracking. | |
194 | |
195 // Only process this event if first paint hasn't been seen and this is a | |
196 // paint of a visible tab. | |
116 RenderWidgetHost* render_widget_host = | 197 RenderWidgetHost* render_widget_host = |
117 content::Source<RenderWidgetHost>(source).ptr(); | 198 Source<RenderWidgetHost>(source).ptr(); |
118 if (!got_first_paint_ && render_widget_host->GetView() && | 199 if (!got_first_paint_ && |
200 render_widget_host->GetView() && | |
119 render_widget_host->GetView()->IsShowing()) { | 201 render_widget_host->GetView()->IsShowing()) { |
120 if (render_widget_hosts_to_paint_.find(render_widget_host) != | 202 TabState* tab_state = GetTabState(render_widget_host); |
121 render_widget_hosts_to_paint_.end()) { | 203 if (tab_state) { |
122 // Got a paint for one of our renderers, so record time. | 204 // This is a paint for a tab that is explicitly being tracked so |
205 // update the statistics. | |
123 got_first_paint_ = true; | 206 got_first_paint_ = true; |
124 base::TimeDelta time_to_paint = | 207 base::TimeDelta time_to_paint = |
125 base::TimeTicks::Now() - restore_started_; | 208 base::TimeTicks::Now() - restore_started_; |
126 // TODO(danduong): to remove this with 467680, to make sure we | 209 DCHECK(!got_done_tracking_non_deferred_tabs_); |
127 // don't forget to clean this up. | 210 tab_loader_stats_.foreground_tab_first_paint = time_to_paint; |
128 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint", | 211 } else { |
129 time_to_paint, | 212 // If this is a host for a tab we're not tracking then some other tab |
130 base::TimeDelta::FromMilliseconds(10), | |
131 base::TimeDelta::FromSeconds(100), 100); | |
132 // Record a time for the number of tabs, to help track down | |
133 // contention. | |
134 std::string time_for_count = base::StringPrintf( | |
135 "SessionRestore.ForegroundTabFirstPaint_%d", tab_count_); | |
136 base::HistogramBase* counter_for_count = | |
137 base::Histogram::FactoryTimeGet( | |
138 time_for_count, base::TimeDelta::FromMilliseconds(10), | |
139 base::TimeDelta::FromSeconds(100), 100, | |
140 base::Histogram::kUmaTargetedHistogramFlag); | |
141 counter_for_count->AddTime(time_to_paint); | |
142 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint2", | |
143 time_to_paint, | |
144 base::TimeDelta::FromMilliseconds(100), | |
145 base::TimeDelta::FromMinutes(16), 50); | |
146 // Record a time for the number of tabs, to help track down | |
147 // contention. | |
148 std::string time_for_count2 = base::StringPrintf( | |
149 "SessionRestore.ForegroundTabFirstPaint2_%d", tab_count_); | |
150 base::HistogramBase* counter_for_count2 = | |
151 base::Histogram::FactoryTimeGet( | |
152 time_for_count2, base::TimeDelta::FromMilliseconds(100), | |
153 base::TimeDelta::FromMinutes(16), 50, | |
154 base::Histogram::kUmaTargetedHistogramFlag); | |
155 counter_for_count2->AddTime(time_to_paint); | |
156 } else if (render_widget_hosts_loading_.find(render_widget_host) == | |
157 render_widget_hosts_loading_.end()) { | |
158 // If this is a host for a tab we're not loading some other tab | |
159 // has rendered and there's no point tracking the time. This could | 213 // has rendered and there's no point tracking the time. This could |
160 // happen because the user opened a different tab or restored tabs | 214 // happen because the user opened a different tab or restored tabs |
161 // to an already existing browser and an existing tab painted. | 215 // to an already existing browser and an existing tab was in the |
216 // foreground. | |
162 got_first_paint_ = true; | 217 got_first_paint_ = true; |
sky
2015/05/27 15:18:39
AFAICT both paths set got_first_paint_ to true. Se
chrisha
2015/06/03 21:16:36
Indeed... remnant of the previous more tortured lo
| |
163 } | 218 } |
219 | |
220 if (got_first_paint_) { | |
221 // If the first paint has been observed the entire to-paint tracking | |
222 // mechanism is no longer needed. | |
223 registrar_.Remove( | |
224 this, | |
225 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | |
226 content::NotificationService::AllSources()); | |
227 | |
228 // Remove any tabs that have loaded. These were only being kept around | |
229 // while waiting for a paint event. | |
230 std::vector<NavigationController*> loaded_tabs; | |
231 for (auto& map_entry : tabs_tracked_) { | |
232 TabState& tab_state = map_entry.second; | |
233 if (tab_state.loading_state == TAB_IS_LOADED) | |
234 loaded_tabs.push_back(tab_state.controller); | |
235 } | |
236 for (auto& tab : loaded_tabs) | |
237 RemoveTab(tab); | |
238 } | |
164 } | 239 } |
165 break; | 240 break; |
166 } | 241 } |
167 default: | 242 default: |
168 NOTREACHED() << "Unknown notification received:" << type; | 243 NOTREACHED() << "Unknown notification received:" << type; |
169 break; | 244 break; |
170 } | 245 } |
171 | 246 |
172 // Check if we are done and if so, reset |this_retainer_| as the collector no | 247 // If non-deferred tabs are no longer being tracked then detach this collector |
173 // longer needs to stay alive. | 248 // from being the shared collector. |
174 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && | 249 if (!got_done_tracking_non_deferred_tabs_ && DoneTrackingNonDeferredTabs()) { |
175 tabs_tracked_.empty() && render_widget_hosts_loading_.empty()) | 250 got_done_tracking_non_deferred_tabs_ = true; |
251 | |
252 // Mark the point at which all tabs have loaded and log the UMA metrics. | |
sky
2015/05/27 15:18:39
Again, not a useful comment.
chrisha
2015/06/03 21:16:36
Acknowledged.
| |
253 tab_loader_stats_.all_tabs_loaded = | |
254 base::TimeTicks::Now() - restore_started_; | |
255 ReportTabLoaderStats(); | |
256 } | |
257 | |
258 // If tracking is completely finished then emit collected metrics and destroy | |
259 // this stats collector. | |
260 if (got_done_tracking_non_deferred_tabs_ && DoneTracking()) | |
176 this_retainer_ = nullptr; | 261 this_retainer_ = nullptr; |
177 } | 262 } |
178 | 263 |
179 void SessionRestoreStatsCollector::AddTabs( | 264 void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) { |
180 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) { | 265 // Stop observing this tab. |
181 tab_count_ += tabs.size(); | 266 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
182 for (auto& tab : tabs) { | 267 Source<WebContents>(tab->GetWebContents())); |
183 RegisterForNotifications(&tab.contents()->GetController()); | 268 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP, |
184 if (tab.is_active()) { | 269 Source<NavigationController>(tab)); |
185 RenderWidgetHost* render_widget_host = | 270 registrar_.Remove(this, content::NOTIFICATION_LOAD_START, |
186 GetRenderWidgetHost(&tab.contents()->GetController()); | 271 Source<NavigationController>(tab)); |
187 render_widget_hosts_loading_.insert(render_widget_host); | 272 |
188 } | 273 // Get the tab state. |
sky
2015/05/27 15:18:39
Again, this comment isn't useful. It just document
chrisha
2015/06/03 21:16:36
Acknowledged.
| |
189 } | 274 auto tab_it = tabs_tracked_.find(tab); |
275 DCHECK(tab_it != tabs_tracked_.end()); | |
276 TabState& tab_state = tab_it->second; | |
277 | |
278 // Remove the tab from the secondary index if it's there. | |
279 auto rwh_it = render_widget_map_.find(tab_state.render_widget_host); | |
280 if (rwh_it != render_widget_map_.end()) | |
281 render_widget_map_.erase(rwh_it); | |
282 | |
283 // Remove the tab from the |tracked_tabs_| map. | |
284 tabs_tracked_.erase(tab_it); | |
190 } | 285 } |
191 | 286 |
192 void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) { | 287 SessionRestoreStatsCollector::TabState* |
193 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 288 SessionRestoreStatsCollector::RegisterForNotifications( |
194 content::Source<WebContents>(tab->GetWebContents())); | |
195 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP, | |
196 content::Source<NavigationController>(tab)); | |
197 registrar_.Remove(this, content::NOTIFICATION_LOAD_START, | |
198 content::Source<NavigationController>(tab)); | |
199 if (render_widget_hosts_loading_.size() > max_parallel_tab_loads_) | |
200 max_parallel_tab_loads_ = render_widget_hosts_loading_.size(); | |
201 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); | |
202 render_widget_hosts_loading_.erase(render_widget_host); | |
203 tabs_tracked_.erase(tab); | |
204 | |
205 // If there are no more tabs loading or being tracked, restore is done and | |
206 // record the time. Note that we are not yet finished, as we might still be | |
207 // waiting for our first paint, which can happen after all tabs are done | |
208 // loading. | |
209 // TODO(georgesak): review behaviour of ForegroundTabFirstPaint. | |
210 if (tabs_tracked_.empty() && render_widget_hosts_loading_.empty()) { | |
211 base::TimeDelta time_to_load = base::TimeTicks::Now() - restore_started_; | |
212 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.AllTabsLoaded", time_to_load, | |
213 base::TimeDelta::FromMilliseconds(10), | |
214 base::TimeDelta::FromSeconds(100), 100); | |
215 // Record a time for the number of tabs, to help track down contention. | |
216 std::string time_for_count = | |
217 base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_); | |
218 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet( | |
219 time_for_count, base::TimeDelta::FromMilliseconds(10), | |
220 base::TimeDelta::FromSeconds(100), 100, | |
221 base::Histogram::kUmaTargetedHistogramFlag); | |
222 counter_for_count->AddTime(time_to_load); | |
223 | |
224 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads", | |
225 max_parallel_tab_loads_); | |
226 } | |
227 } | |
228 | |
229 void SessionRestoreStatsCollector::RegisterForNotifications( | |
230 NavigationController* tab) { | 289 NavigationController* tab) { |
231 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 290 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
232 content::Source<WebContents>(tab->GetWebContents())); | 291 Source<WebContents>(tab->GetWebContents())); |
233 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, | 292 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
234 content::Source<NavigationController>(tab)); | 293 Source<NavigationController>(tab)); |
235 registrar_.Add(this, content::NOTIFICATION_LOAD_START, | 294 registrar_.Add(this, content::NOTIFICATION_LOAD_START, |
236 content::Source<NavigationController>(tab)); | 295 Source<NavigationController>(tab)); |
237 tabs_tracked_.insert(tab); | 296 auto result = tabs_tracked_.insert(std::make_pair(tab, TabState(tab))); |
297 DCHECK(result.second); | |
298 TabState* tab_state = &result.first->second; | |
299 return tab_state; | |
238 } | 300 } |
239 | 301 |
240 RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost( | 302 RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost( |
241 NavigationController* tab) { | 303 NavigationController* tab) { |
242 WebContents* web_contents = tab->GetWebContents(); | 304 WebContents* web_contents = tab->GetWebContents(); |
243 if (web_contents) { | 305 if (web_contents) { |
244 content::RenderWidgetHostView* render_widget_host_view = | 306 content::RenderWidgetHostView* render_widget_host_view = |
245 web_contents->GetRenderWidgetHostView(); | 307 web_contents->GetRenderWidgetHostView(); |
246 if (render_widget_host_view) | 308 if (render_widget_host_view) |
247 return render_widget_host_view->GetRenderWidgetHost(); | 309 return render_widget_host_view->GetRenderWidgetHost(); |
248 } | 310 } |
249 return nullptr; | 311 return nullptr; |
250 } | 312 } |
251 | 313 |
252 // static | 314 SessionRestoreStatsCollector::TabState* |
253 SessionRestoreStatsCollector* SessionRestoreStatsCollector::shared_collector_ = | 315 SessionRestoreStatsCollector::GetTabState(NavigationController* tab) { |
254 nullptr; | 316 // This lookup can fail because DeferTab calls can arrive for tabs that have |
317 // already loaded (user forced) and are no longer tracked. | |
318 auto it = tabs_tracked_.find(tab); | |
319 if (it == tabs_tracked_.end()) | |
320 return nullptr; | |
321 return &it->second; | |
322 } | |
323 | |
324 SessionRestoreStatsCollector::TabState* | |
325 SessionRestoreStatsCollector::GetTabState(RenderWidgetHost* tab) { | |
326 // This lookup can fail as events are received for tabs that aren't | |
sky
2015/05/27 15:18:39
You can figure out the NavigationController the RW
chrisha
2015/06/03 21:16:36
Done.
| |
327 // explicitly being tracked. | |
328 auto it = render_widget_map_.find(tab); | |
329 if (it == render_widget_map_.end()) | |
330 return nullptr; | |
331 return it->second; | |
332 } | |
333 | |
334 void SessionRestoreStatsCollector::MarkTabAsLoading(TabState* tab_state) { | |
335 CHECK(tab_state->loading_state == TAB_IS_NOT_LOADING); | |
sky
2015/05/27 15:18:39
Why the CHECK?
chrisha
2015/06/03 21:16:36
Made a DCHECK. This really shouldn't be called twi
| |
336 if (tab_state->loading_state != TAB_IS_NOT_LOADING) | |
337 return; | |
338 tab_state->loading_state = TAB_IS_LOADING; | |
339 ++loading_tab_count_; | |
340 | |
341 DCHECK(!got_done_tracking_non_deferred_tabs_); | |
342 tab_loader_stats_.parallel_tab_loads = std::max( | |
343 tab_loader_stats_.parallel_tab_loads, | |
344 loading_tab_count_); | |
345 | |
346 // Get the RenderWidgetHost for the tab and add it to the secondary index. | |
347 RenderWidgetHost* render_widget_host = GetRenderWidgetHost( | |
348 tab_state->controller); | |
349 DCHECK(render_widget_host); | |
350 tab_state->render_widget_host = render_widget_host; | |
351 auto result = render_widget_map_.insert(std::make_pair( | |
352 render_widget_host, tab_state)); | |
353 DCHECK(result.second); | |
354 } | |
355 | |
356 bool SessionRestoreStatsCollector::DoneTrackingNonDeferredTabs() const { | |
357 // This should only be called when it hasn't yet returned true. | |
358 DCHECK(!got_done_tracking_non_deferred_tabs_); | |
359 return got_first_paint_ && waiting_for_load_tab_count_ == 0; | |
360 } | |
361 | |
362 bool SessionRestoreStatsCollector::DoneTracking() const { | |
363 // This should only be called once DoneTrackingNonDeferredTabs has returned | |
364 // true. | |
365 DCHECK(got_done_tracking_non_deferred_tabs_); | |
366 return tabs_tracked_.empty() && render_widget_map_.empty(); | |
367 } | |
368 | |
369 void SessionRestoreStatsCollector::ReportTabLoaderStats() { | |
370 UMA_HISTOGRAM_COUNTS_100("SessionRestore.TabCount", | |
371 tab_loader_stats_.tab_count); | |
372 | |
373 UMA_HISTOGRAM_ENUMERATION(kSessionRestoreActions, | |
374 SESSION_RESTORE_ACTIONS_UMA_INITIATED, | |
375 SESSION_RESTORE_ACTIONS_UMA_MAX); | |
376 | |
377 for (size_t i = 0; i < tab_loader_stats_.tab_count; ++i) { | |
378 UMA_HISTOGRAM_ENUMERATION("SessionRestore.TabActions", | |
379 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED, | |
380 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX); | |
381 } | |
382 | |
383 for (size_t i = 0; i < tab_loader_stats_.tabs_loaded; ++i) { | |
384 UMA_HISTOGRAM_ENUMERATION("SessionRestore.TabActions", | |
385 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED, | |
386 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX); | |
387 } | |
388 | |
389 if (!tab_loader_stats_.foreground_tab_first_loaded.is_zero()) { | |
390 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded", | |
391 tab_loader_stats_.foreground_tab_first_loaded, | |
392 base::TimeDelta::FromMilliseconds(10), | |
393 base::TimeDelta::FromSeconds(100), 100); | |
394 | |
395 // Record a time for the number of tabs, to help track down contention. | |
396 std::string time_for_count = base::StringPrintf( | |
397 "SessionRestore.ForegroundTabFirstLoaded_%d", | |
398 tab_loader_stats_.tab_count); | |
399 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet( | |
400 time_for_count, base::TimeDelta::FromMilliseconds(10), | |
401 base::TimeDelta::FromSeconds(100), 100, | |
402 base::Histogram::kUmaTargetedHistogramFlag); | |
403 counter_for_count->AddTime(tab_loader_stats_.foreground_tab_first_loaded); | |
404 } | |
405 | |
406 if (!tab_loader_stats_.foreground_tab_first_paint.is_zero()) { | |
407 UMA_HISTOGRAM_CUSTOM_TIMES( | |
408 "SessionRestore.ForegroundTabFirstPaint3", | |
409 tab_loader_stats_.foreground_tab_first_paint, | |
410 base::TimeDelta::FromMilliseconds(100), | |
411 base::TimeDelta::FromMinutes(16), 50); | |
412 | |
413 std::string time_for_count = base::StringPrintf( | |
414 "SessionRestore.ForegroundTabFirstPaint3_%d", | |
415 tab_loader_stats_.tab_count); | |
416 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet( | |
417 time_for_count, base::TimeDelta::FromMilliseconds(100), | |
418 base::TimeDelta::FromMinutes(16), 50, | |
419 base::Histogram::kUmaTargetedHistogramFlag); | |
420 counter_for_count->AddTime(tab_loader_stats_.foreground_tab_first_paint); | |
421 } | |
422 | |
423 if (!tab_loader_stats_.all_tabs_loaded.is_zero()) { | |
424 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.AllTabsLoaded", | |
425 tab_loader_stats_.all_tabs_loaded, | |
426 base::TimeDelta::FromMilliseconds(10), | |
427 base::TimeDelta::FromSeconds(100), 100); | |
428 | |
429 // Record a time for the number of tabs, to help track down contention. | |
430 std::string time_for_count = | |
431 base::StringPrintf("SessionRestore.AllTabsLoaded_%d", | |
432 tab_loader_stats_.tab_count); | |
433 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet( | |
434 time_for_count, base::TimeDelta::FromMilliseconds(10), | |
435 base::TimeDelta::FromSeconds(100), 100, | |
436 base::Histogram::kUmaTargetedHistogramFlag); | |
437 counter_for_count->AddTime(tab_loader_stats_.all_tabs_loaded); | |
438 } | |
439 | |
440 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads", | |
441 tab_loader_stats_.parallel_tab_loads); | |
442 } | |
443 | |
444 void SessionRestoreStatsCollector::ReportTabDeferred() { | |
445 if (!got_report_tab_deferred_) { | |
446 got_report_tab_deferred_ = true; | |
447 | |
448 UMA_HISTOGRAM_ENUMERATION(kSessionRestoreActions, | |
449 SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS, | |
450 SESSION_RESTORE_ACTIONS_UMA_MAX); | |
451 } | |
452 | |
453 UMA_HISTOGRAM_ENUMERATION( | |
454 "SessionRestore.TabActions", | |
455 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED, | |
456 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX); | |
457 } | |
458 | |
459 void SessionRestoreStatsCollector::ReportDeferredTabLoaded() { | |
460 UMA_HISTOGRAM_ENUMERATION( | |
461 "SessionRestore.TabActions", | |
462 SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED, | |
463 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX); | |
464 } | |
OLD | NEW |