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 using content::NavigationController; | 16 using content::NavigationController; |
17 using content::RenderWidgetHost; | 17 using content::RenderWidgetHost; |
18 using content::WebContents; | 18 using content::WebContents; |
19 | 19 |
20 namespace { | |
21 | |
22 // Metric names. | |
23 const char kSessionRestoreActions[] = "SessionRestore.Actions"; | |
24 const char kSessionRestoreTabCount[] = "SessionRestore.TabCount"; | |
25 const char kSessionRestoreTabActions[] = "SessionRestore.TabActions"; | |
26 | |
27 // The enumeration values stored in the kSessionRestoreActions histogram. | |
28 enum SessionRestoreActionsUma { | |
29 // Counts the total number of session restores that have occurred. | |
30 SESSION_RESTORE_ACTIONS_UMA_INITIATED = 0, | |
31 // Counts the number of session restores that have been deferred tab loadings | |
32 // for whatever reason (almost certainly due to memory pressure). | |
33 SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS = 1, | |
34 // The size of this enum. Must be the last entry. | |
35 SESSION_RESTORE_ACTIONS_UMA_MAX, | |
36 }; | |
37 | |
38 // The enumeration of values stored in the kSessionRestoreTabActions histogram. | |
39 enum SessionRestoreTabActionsUma { | |
40 // Incremented for each tab created in a session restore. | |
41 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED = 0, | |
42 // Incremented for each tab that session restore decides not to load. | |
43 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED = 1, | |
44 // Incremented for each tab that is successfully loaded. | |
45 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED = 2, | |
46 // Incremented for each session-restore-deferred tab that is subsequently | |
47 // loaded. | |
48 SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED = 3, | |
49 // The size of this enum. Must be the last entry. | |
50 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX, | |
51 }; | |
52 | |
53 } // namespace | |
54 | |
20 // static | 55 // static |
21 void SessionRestoreStatsCollector::TrackTabs( | 56 void SessionRestoreStatsCollector::TrackTabs( |
22 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, | 57 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, |
23 const base::TimeTicks& restore_started) { | 58 const base::TimeTicks& restore_started) { |
24 if (!shared_collector_) | 59 if (!shared_collector_) |
25 shared_collector_ = new SessionRestoreStatsCollector(restore_started); | 60 shared_collector_ = new SessionRestoreStatsCollector(restore_started); |
26 | 61 |
27 shared_collector_->AddTabs(tabs); | 62 shared_collector_->AddTabs(tabs); |
28 } | 63 } |
29 | 64 |
30 // static | 65 // static |
31 void SessionRestoreStatsCollector::TrackActiveTabs( | 66 void SessionRestoreStatsCollector::DeferTab( |
32 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, | 67 content::NavigationController* tab) { |
33 const base::TimeTicks& restore_started) { | 68 // It only makes sense for this to have been called *after* TrackTabs, so a |
34 if (!shared_collector_) | 69 // stats collector will always exist. |
35 shared_collector_ = new SessionRestoreStatsCollector(restore_started); | 70 DCHECK(shared_collector_); |
36 | 71 shared_collector_->DeferTabImpl(tab); |
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 } | 72 } |
44 | 73 |
45 SessionRestoreStatsCollector::SessionRestoreStatsCollector( | 74 SessionRestoreStatsCollector::SessionRestoreStatsCollector( |
46 const base::TimeTicks& restore_started) | 75 const base::TimeTicks& restore_started) |
47 : got_first_foreground_load_(false), | 76 : got_first_foreground_load_(false), |
48 got_first_paint_(false), | 77 got_first_paint_(false), |
49 restore_started_(restore_started), | 78 restore_started_(restore_started), |
50 tab_count_(0), | 79 render_widget_hosts_loading_deferred_count_(0u), |
51 max_parallel_tab_loads_(0) { | 80 tabs_tracked_deferred_count_(0u), |
81 tab_count_(0u), | |
82 tab_deferred_count_(0u), | |
83 max_parallel_tab_loads_(0u) { | |
52 this_retainer_ = this; | 84 this_retainer_ = this; |
53 registrar_.Add( | 85 registrar_.Add( |
54 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | 86 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, |
55 content::NotificationService::AllSources()); | 87 content::NotificationService::AllSources()); |
56 } | 88 } |
57 | 89 |
58 SessionRestoreStatsCollector::~SessionRestoreStatsCollector() { | 90 SessionRestoreStatsCollector::~SessionRestoreStatsCollector() { |
59 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && | 91 // The collector should only be destroyed when tracking is entirely |
60 tabs_tracked_.empty() && render_widget_hosts_loading_.empty()); | 92 // finished. It should already have beend detached from being the shared |
61 DCHECK(shared_collector_ == this); | 93 // collector. |
62 shared_collector_ = nullptr; | 94 DCHECK(shared_collector_ != this); |
95 DCHECK(DoneTracking()); | |
63 } | 96 } |
64 | 97 |
65 void SessionRestoreStatsCollector::Observe( | 98 void SessionRestoreStatsCollector::Observe( |
66 int type, | 99 int type, |
67 const content::NotificationSource& source, | 100 const content::NotificationSource& source, |
68 const content::NotificationDetails& details) { | 101 const content::NotificationDetails& details) { |
69 switch (type) { | 102 switch (type) { |
70 case content::NOTIFICATION_LOAD_START: { | 103 case content::NOTIFICATION_LOAD_START: { |
71 // Add this render_widget_host to the set of those we're waiting for | |
72 // paints on. We want to only record stats for paints that occur after | |
73 // a load has finished. | |
74 NavigationController* tab = | 104 NavigationController* tab = |
75 content::Source<NavigationController>(source).ptr(); | 105 content::Source<NavigationController>(source).ptr(); |
106 bool is_deferred = IsDeferred(tab); | |
107 | |
108 // Add this render_widget_host to the set of those that are loading. | |
76 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); | 109 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); |
77 DCHECK(render_widget_host); | 110 DCHECK(render_widget_host); |
78 render_widget_hosts_loading_.insert(render_widget_host); | 111 render_widget_hosts_loading_.insert( |
112 std::make_pair(render_widget_host, is_deferred)); | |
113 if (is_deferred) | |
114 ++render_widget_hosts_loading_deferred_count_; | |
115 | |
79 break; | 116 break; |
80 } | 117 } |
81 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { | 118 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { |
82 WebContents* web_contents = content::Source<WebContents>(source).ptr(); | 119 WebContents* web_contents = content::Source<WebContents>(source).ptr(); |
83 RemoveTab(&web_contents->GetController()); | 120 NavigationController* tab = &web_contents->GetController(); |
121 RemoveTab(tab); | |
84 break; | 122 break; |
85 } | 123 } |
86 case content::NOTIFICATION_LOAD_STOP: { | 124 case content::NOTIFICATION_LOAD_STOP: { |
125 // Remove the tab from the tracking maps. | |
87 NavigationController* tab = | 126 NavigationController* tab = |
88 content::Source<NavigationController>(source).ptr(); | 127 content::Source<NavigationController>(source).ptr(); |
89 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); | 128 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); |
90 render_widget_hosts_to_paint_.insert(render_widget_host); | 129 auto tab_it = tabs_tracked_.find(tab); |
130 bool is_deferred = tab_it->second; | |
91 RemoveTab(tab); | 131 RemoveTab(tab); |
132 | |
133 // If first paint hasn't yet been seen then add this tab to the set of | |
134 // those being tracked for first paints. | |
135 if (!got_first_paint_ && render_widget_host) | |
136 render_widget_hosts_to_paint_.insert(render_widget_host); | |
137 | |
138 // Note the fact that this tab loaded. | |
139 auto tab_action = is_deferred ? | |
140 SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED : | |
141 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED; | |
142 UMA_HISTOGRAM_ENUMERATION(kSessionRestoreTabActions, | |
143 tab_action, | |
144 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX); | |
145 | |
146 // Update UMA stats for foreground tabs. | |
92 if (!got_first_foreground_load_ && render_widget_host && | 147 if (!got_first_foreground_load_ && render_widget_host && |
93 render_widget_host->GetView() && | 148 render_widget_host->GetView() && |
94 render_widget_host->GetView()->IsShowing()) { | 149 render_widget_host->GetView()->IsShowing()) { |
95 got_first_foreground_load_ = true; | 150 got_first_foreground_load_ = true; |
96 base::TimeDelta time_to_load = | 151 base::TimeDelta time_to_load = |
97 base::TimeTicks::Now() - restore_started_; | 152 base::TimeTicks::Now() - restore_started_; |
98 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded", | 153 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded", |
99 time_to_load, | 154 time_to_load, |
100 base::TimeDelta::FromMilliseconds(10), | 155 base::TimeDelta::FromMilliseconds(10), |
101 base::TimeDelta::FromSeconds(100), 100); | 156 base::TimeDelta::FromSeconds(100), 100); |
102 // Record a time for the number of tabs, to help track down | 157 // Record a time for the number of tabs, to help track down |
103 // contention. | 158 // contention. |
104 std::string time_for_count = base::StringPrintf( | 159 std::string time_for_count = base::StringPrintf( |
105 "SessionRestore.ForegroundTabFirstLoaded_%d", tab_count_); | 160 "SessionRestore.ForegroundTabFirstLoaded_%d", tab_count_); |
106 base::HistogramBase* counter_for_count = | 161 base::HistogramBase* counter_for_count = |
107 base::Histogram::FactoryTimeGet( | 162 base::Histogram::FactoryTimeGet( |
108 time_for_count, base::TimeDelta::FromMilliseconds(10), | 163 time_for_count, base::TimeDelta::FromMilliseconds(10), |
109 base::TimeDelta::FromSeconds(100), 100, | 164 base::TimeDelta::FromSeconds(100), 100, |
110 base::Histogram::kUmaTargetedHistogramFlag); | 165 base::Histogram::kUmaTargetedHistogramFlag); |
111 counter_for_count->AddTime(time_to_load); | 166 counter_for_count->AddTime(time_to_load); |
112 } | 167 } |
113 break; | 168 break; |
114 } | 169 } |
115 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: { | 170 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: { |
171 // This notification is across all tabs in the browser so notifications | |
172 // will arrive for tabs that the collector is not explicitly tracking. | |
173 | |
174 // Only process this event if first paint hasn't been seen and this is a | |
175 // paint of a visible tab. | |
116 RenderWidgetHost* render_widget_host = | 176 RenderWidgetHost* render_widget_host = |
117 content::Source<RenderWidgetHost>(source).ptr(); | 177 content::Source<RenderWidgetHost>(source).ptr(); |
118 if (!got_first_paint_ && render_widget_host->GetView() && | 178 if (!got_first_paint_ && |
179 render_widget_host->GetView() && | |
119 render_widget_host->GetView()->IsShowing()) { | 180 render_widget_host->GetView()->IsShowing()) { |
120 if (render_widget_hosts_to_paint_.find(render_widget_host) != | 181 // If this is a paint for a tab that is explicitly being tracked for |
121 render_widget_hosts_to_paint_.end()) { | 182 // paint events then record the appropriate UMA statistic. |
183 auto render_widget_host_it = | |
184 render_widget_hosts_to_paint_.find(render_widget_host); | |
185 if (render_widget_host_it != render_widget_hosts_to_paint_.end()) { | |
186 // Stop tracking this tab. | |
187 render_widget_hosts_to_paint_.erase(render_widget_host_it); | |
188 | |
122 // Got a paint for one of our renderers, so record time. | 189 // Got a paint for one of our renderers, so record time. |
123 got_first_paint_ = true; | 190 got_first_paint_ = true; |
124 base::TimeDelta time_to_paint = | 191 base::TimeDelta time_to_paint = |
125 base::TimeTicks::Now() - restore_started_; | 192 base::TimeTicks::Now() - restore_started_; |
126 // TODO(danduong): to remove this with 467680, to make sure we | 193 // TODO(danduong): to remove this with 467680, to make sure we |
127 // don't forget to clean this up. | 194 // don't forget to clean this up. |
128 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint", | 195 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint", |
129 time_to_paint, | 196 time_to_paint, |
130 base::TimeDelta::FromMilliseconds(10), | 197 base::TimeDelta::FromMilliseconds(10), |
131 base::TimeDelta::FromSeconds(100), 100); | 198 base::TimeDelta::FromSeconds(100), 100); |
132 // Record a time for the number of tabs, to help track down | 199 // Record a time for the number of tabs, to help track down |
133 // contention. | 200 // contention. |
134 std::string time_for_count = base::StringPrintf( | 201 std::string time_for_count = base::StringPrintf( |
135 "SessionRestore.ForegroundTabFirstPaint_%d", tab_count_); | 202 "SessionRestore.ForegroundTabFirstPaint_%d", tab_count_); |
136 base::HistogramBase* counter_for_count = | 203 base::HistogramBase* counter_for_count = |
137 base::Histogram::FactoryTimeGet( | 204 base::Histogram::FactoryTimeGet( |
138 time_for_count, base::TimeDelta::FromMilliseconds(10), | 205 time_for_count, base::TimeDelta::FromMilliseconds(10), |
139 base::TimeDelta::FromSeconds(100), 100, | 206 base::TimeDelta::FromSeconds(100), 100, |
140 base::Histogram::kUmaTargetedHistogramFlag); | 207 base::Histogram::kUmaTargetedHistogramFlag); |
141 counter_for_count->AddTime(time_to_paint); | 208 counter_for_count->AddTime(time_to_paint); |
142 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint2", | 209 UMA_HISTOGRAM_CUSTOM_TIMES( |
143 time_to_paint, | 210 "SessionRestore.ForegroundTabFirstPaint2", |
144 base::TimeDelta::FromMilliseconds(100), | 211 time_to_paint, |
145 base::TimeDelta::FromMinutes(16), 50); | 212 base::TimeDelta::FromMilliseconds(100), |
213 base::TimeDelta::FromMinutes(16), 50); | |
146 // Record a time for the number of tabs, to help track down | 214 // Record a time for the number of tabs, to help track down |
147 // contention. | 215 // contention. |
148 std::string time_for_count2 = base::StringPrintf( | 216 std::string time_for_count2 = base::StringPrintf( |
149 "SessionRestore.ForegroundTabFirstPaint2_%d", tab_count_); | 217 "SessionRestore.ForegroundTabFirstPaint2_%d", tab_count_); |
150 base::HistogramBase* counter_for_count2 = | 218 base::HistogramBase* counter_for_count2 = |
151 base::Histogram::FactoryTimeGet( | 219 base::Histogram::FactoryTimeGet( |
152 time_for_count2, base::TimeDelta::FromMilliseconds(100), | 220 time_for_count2, base::TimeDelta::FromMilliseconds(100), |
153 base::TimeDelta::FromMinutes(16), 50, | 221 base::TimeDelta::FromMinutes(16), 50, |
154 base::Histogram::kUmaTargetedHistogramFlag); | 222 base::Histogram::kUmaTargetedHistogramFlag); |
155 counter_for_count2->AddTime(time_to_paint); | 223 counter_for_count2->AddTime(time_to_paint); |
156 } else if (render_widget_hosts_loading_.find(render_widget_host) == | 224 } else if (render_widget_hosts_loading_.find(render_widget_host) == |
157 render_widget_hosts_loading_.end()) { | 225 render_widget_hosts_loading_.end()) { |
158 // If this is a host for a tab we're not loading some other tab | 226 // If this is a host for a tab we're not tracking then some other tab |
159 // has rendered and there's no point tracking the time. This could | 227 // has rendered and there's no point tracking the time. This could |
160 // happen because the user opened a different tab or restored tabs | 228 // happen because the user opened a different tab or restored tabs |
161 // to an already existing browser and an existing tab painted. | 229 // to an already existing browser and an existing tab painted. |
162 got_first_paint_ = true; | 230 got_first_paint_ = true; |
163 } | 231 } |
232 | |
233 if (got_first_paint_) { | |
234 // If the first paint has been observed the entire to-paint tracking | |
235 // mechanism is no longer needed. | |
236 registrar_.Remove( | |
237 this, | |
238 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | |
239 content::NotificationService::AllSources()); | |
240 render_widget_hosts_to_paint_.clear(); | |
241 } | |
164 } | 242 } |
165 break; | 243 break; |
166 } | 244 } |
167 default: | 245 default: |
168 NOTREACHED() << "Unknown notification received:" << type; | 246 NOTREACHED() << "Unknown notification received:" << type; |
169 break; | 247 break; |
170 } | 248 } |
171 | 249 |
172 // Check if we are done and if so, reset |this_retainer_| as the collector no | 250 // If non-deferred tabs are no longer being tracked then detach this collector |
173 // longer needs to stay alive. | 251 // from being the shared collector. This allows new session restores to get |
174 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && | 252 // new stats collectors. It also means that multiple stats collectors can |
175 tabs_tracked_.empty() && render_widget_hosts_loading_.empty()) | 253 // exist simultaneously. |
254 if (shared_collector_ == this && DoneTrackingNonDeferredTabs()) | |
255 shared_collector_ = nullptr; | |
256 | |
257 // If tracking is completely finished destroy this stats collector. | |
258 if (shared_collector_ != this && DoneTracking()) | |
176 this_retainer_ = nullptr; | 259 this_retainer_ = nullptr; |
177 } | 260 } |
178 | 261 |
179 void SessionRestoreStatsCollector::AddTabs( | 262 void SessionRestoreStatsCollector::AddTabs( |
180 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) { | 263 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) { |
264 // A new session restore is starting. | |
265 if (tab_count_ == 0) { | |
266 // Each session restore makes a call to AddTabs with all of its tabs to be | |
267 // restored all at once. Record statistics about all simultaneous session | |
268 // restores (ie: multi-profile) as a whole. | |
269 UMA_HISTOGRAM_COUNTS_100(kSessionRestoreTabCount, tabs.size()); | |
270 UMA_HISTOGRAM_ENUMERATION(kSessionRestoreActions, | |
271 SESSION_RESTORE_ACTIONS_UMA_INITIATED, | |
272 SESSION_RESTORE_ACTIONS_UMA_MAX); | |
273 } | |
274 | |
181 tab_count_ += tabs.size(); | 275 tab_count_ += tabs.size(); |
182 for (auto& tab : tabs) { | 276 for (auto& tab : tabs) { |
277 // Record actions for each individual tab. | |
278 UMA_HISTOGRAM_ENUMERATION(kSessionRestoreTabActions, | |
279 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED, | |
280 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX); | |
281 | |
183 RegisterForNotifications(&tab.contents()->GetController()); | 282 RegisterForNotifications(&tab.contents()->GetController()); |
184 if (tab.is_active()) { | 283 if (tab.is_active()) { |
185 RenderWidgetHost* render_widget_host = | 284 RenderWidgetHost* render_widget_host = |
186 GetRenderWidgetHost(&tab.contents()->GetController()); | 285 GetRenderWidgetHost(&tab.contents()->GetController()); |
187 render_widget_hosts_loading_.insert(render_widget_host); | 286 render_widget_hosts_loading_.insert( |
287 std::make_pair(render_widget_host, false)); | |
188 } | 288 } |
189 } | 289 } |
190 } | 290 } |
191 | 291 |
292 void SessionRestoreStatsCollector::DeferTabImpl( | |
293 content::NavigationController* tab) { | |
294 auto tab_it = tabs_tracked_.find(tab); | |
295 // If the tab is no longer being tracked it has already started loading, | |
296 // likely due to user action. Ignore the call to defer the tab. | |
297 // TODO(chrisha): Is it worth explicitly tracking these events as well? | |
chrisha
2015/05/13 21:18:02
Consider this a question... your thoughts?
| |
298 if (tab_it == tabs_tracked_.end()) | |
299 return; | |
300 | |
301 // Mark this tab as deferred, if its still being tracked. A tab should not be | |
302 // marked as deferred twice. | |
303 DCHECK(!tab_it->second); | |
304 tab_it->second = true; | |
305 ++tabs_tracked_deferred_count_; | |
306 ++tab_deferred_count_; | |
307 | |
308 // It is possible that the tab is loading so also look in the loading render | |
309 // widget host map in this case. | |
310 auto render_widget_host = GetRenderWidgetHost(tab); | |
311 auto render_widget_host_it = render_widget_hosts_loading_.find( | |
312 render_widget_host); | |
313 if (render_widget_host_it != render_widget_hosts_loading_.end()) { | |
314 DCHECK(!render_widget_host_it->second); | |
315 render_widget_host_it->second = true; | |
316 ++render_widget_hosts_loading_deferred_count_; | |
317 } | |
318 | |
319 // If this is the first tab being deferred indicate that the session has had | |
320 // deferred tabs. | |
321 if (tab_deferred_count_ == 1) { | |
322 // It is assumed that tabs are being deferred due to memory pressure as this | |
323 // is currently the only mechanism in which this can happen. | |
324 UMA_HISTOGRAM_ENUMERATION(kSessionRestoreActions, | |
325 SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS, | |
326 SESSION_RESTORE_ACTIONS_UMA_MAX); | |
327 } | |
328 | |
329 UMA_HISTOGRAM_ENUMERATION( | |
330 kSessionRestoreTabActions, | |
331 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED, | |
332 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX); | |
333 } | |
334 | |
192 void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) { | 335 void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) { |
336 // Stop observing this tab. | |
193 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 337 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
194 content::Source<WebContents>(tab->GetWebContents())); | 338 content::Source<WebContents>(tab->GetWebContents())); |
195 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP, | 339 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP, |
196 content::Source<NavigationController>(tab)); | 340 content::Source<NavigationController>(tab)); |
197 registrar_.Remove(this, content::NOTIFICATION_LOAD_START, | 341 registrar_.Remove(this, content::NOTIFICATION_LOAD_START, |
198 content::Source<NavigationController>(tab)); | 342 content::Source<NavigationController>(tab)); |
343 | |
344 // Remove the tab from the tracked_tabs map and be sure to update the count | |
345 // of deferred tracked tabs if necessary. | |
346 auto tab_it = tabs_tracked_.find(tab); | |
347 bool is_deferred = tab_it->second; | |
348 tabs_tracked_.erase(tab_it); | |
349 if (is_deferred) | |
350 --tabs_tracked_deferred_count_; | |
351 | |
352 // Keep track of the maximum number of tabs that are loading at the same time. | |
353 // NOTE: This counts session restore loaded tabs and *user* loaded tabs, | |
354 // both deferred and otherwise. This preserves the original behaviour of | |
355 // this metric. | |
199 if (render_widget_hosts_loading_.size() > max_parallel_tab_loads_) | 356 if (render_widget_hosts_loading_.size() > max_parallel_tab_loads_) |
200 max_parallel_tab_loads_ = render_widget_hosts_loading_.size(); | 357 max_parallel_tab_loads_ = render_widget_hosts_loading_.size(); |
358 | |
359 // Remove the tab from the loading render widget host map. If the tab is | |
360 // present in this map and deferred, then also update the deferred count. | |
201 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); | 361 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); |
202 render_widget_hosts_loading_.erase(render_widget_host); | 362 if (is_deferred && render_widget_hosts_loading_.erase(render_widget_host)) |
203 tabs_tracked_.erase(tab); | 363 --render_widget_hosts_loading_deferred_count_; |
204 | 364 |
205 // If there are no more tabs loading or being tracked, restore is done and | 365 // Calculate the number of non-deferred tracked and loading tabs. These are |
206 // record the time. Note that we are not yet finished, as we might still be | 366 // used to determine whether session restore has completed tab loading. |
207 // waiting for our first paint, which can happen after all tabs are done | 367 size_t tracked = tabs_tracked_.size() - tabs_tracked_deferred_count_; |
208 // loading. | 368 size_t loading = render_widget_hosts_loading_.size() - |
209 // TODO(georgesak): review behaviour of ForegroundTabFirstPaint. | 369 render_widget_hosts_loading_deferred_count_; |
210 if (tabs_tracked_.empty() && render_widget_hosts_loading_.empty()) { | 370 |
371 // If there are no more non-deferred tabs loading or being tracked, the active | |
372 // portion of restore is done so record the time. Note that stats collection | |
373 // is not yet finished, as there can be deferred tabs and pending paint | |
374 // events. | |
375 // NOTE: This is only concerned with tabs that are being actively tracked, | |
376 // and not deferred tabs. Deferred tabs are still tracked, but don't | |
377 // affect the AllTabsLoaded metric. | |
378 // TODO(georgesak): Review behaviour of ForegroundTabFirstPaint. | |
379 if (tracked == 0 && loading == 0) { | |
211 base::TimeDelta time_to_load = base::TimeTicks::Now() - restore_started_; | 380 base::TimeDelta time_to_load = base::TimeTicks::Now() - restore_started_; |
212 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.AllTabsLoaded", time_to_load, | 381 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.AllTabsLoaded", time_to_load, |
213 base::TimeDelta::FromMilliseconds(10), | 382 base::TimeDelta::FromMilliseconds(10), |
214 base::TimeDelta::FromSeconds(100), 100); | 383 base::TimeDelta::FromSeconds(100), 100); |
215 // Record a time for the number of tabs, to help track down contention. | 384 // Record a time for the number of tabs, to help track down contention. |
216 std::string time_for_count = | 385 std::string time_for_count = |
217 base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_); | 386 base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_); |
218 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet( | 387 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet( |
219 time_for_count, base::TimeDelta::FromMilliseconds(10), | 388 time_for_count, base::TimeDelta::FromMilliseconds(10), |
220 base::TimeDelta::FromSeconds(100), 100, | 389 base::TimeDelta::FromSeconds(100), 100, |
221 base::Histogram::kUmaTargetedHistogramFlag); | 390 base::Histogram::kUmaTargetedHistogramFlag); |
222 counter_for_count->AddTime(time_to_load); | 391 counter_for_count->AddTime(time_to_load); |
223 | 392 |
224 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads", | 393 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads", |
225 max_parallel_tab_loads_); | 394 max_parallel_tab_loads_); |
226 } | 395 } |
227 } | 396 } |
228 | 397 |
229 void SessionRestoreStatsCollector::RegisterForNotifications( | 398 void SessionRestoreStatsCollector::RegisterForNotifications( |
230 NavigationController* tab) { | 399 NavigationController* tab) { |
231 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, | 400 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
232 content::Source<WebContents>(tab->GetWebContents())); | 401 content::Source<WebContents>(tab->GetWebContents())); |
233 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, | 402 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
234 content::Source<NavigationController>(tab)); | 403 content::Source<NavigationController>(tab)); |
235 registrar_.Add(this, content::NOTIFICATION_LOAD_START, | 404 registrar_.Add(this, content::NOTIFICATION_LOAD_START, |
236 content::Source<NavigationController>(tab)); | 405 content::Source<NavigationController>(tab)); |
237 tabs_tracked_.insert(tab); | 406 // All tabs are non-deferred to start with. |
407 tabs_tracked_.insert(std::make_pair(tab, false)); | |
238 } | 408 } |
239 | 409 |
240 RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost( | 410 RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost( |
241 NavigationController* tab) { | 411 NavigationController* tab) { |
242 WebContents* web_contents = tab->GetWebContents(); | 412 WebContents* web_contents = tab->GetWebContents(); |
243 if (web_contents) { | 413 if (web_contents) { |
244 content::RenderWidgetHostView* render_widget_host_view = | 414 content::RenderWidgetHostView* render_widget_host_view = |
245 web_contents->GetRenderWidgetHostView(); | 415 web_contents->GetRenderWidgetHostView(); |
246 if (render_widget_host_view) | 416 if (render_widget_host_view) |
247 return render_widget_host_view->GetRenderWidgetHost(); | 417 return render_widget_host_view->GetRenderWidgetHost(); |
248 } | 418 } |
249 return nullptr; | 419 return nullptr; |
250 } | 420 } |
251 | 421 |
422 bool SessionRestoreStatsCollector::IsDeferred( | |
423 content::NavigationController* tab) const { | |
424 auto tab_it = tabs_tracked_.find(tab); | |
425 DCHECK(tab_it != tabs_tracked_.end()); | |
426 return tab_it->second; | |
427 } | |
428 | |
429 bool SessionRestoreStatsCollector::DoneTrackingNonDeferredTabs() const { | |
430 // If first paint hasn't been seen and tabs are being tracked for paints | |
431 // (ie: a first paint could yet be seen) then the stats collector is not done. | |
432 if (!got_first_paint_ && !render_widget_hosts_to_paint_.empty()) | |
433 return false; | |
434 | |
435 // No non-deferred tabs should be in the tracked map. | |
436 size_t tracked = tabs_tracked_.size() - tabs_tracked_deferred_count_; | |
437 if (tracked > 0) | |
438 return false; | |
439 | |
440 // No non-deferred tabs should be in the loading map. | |
441 size_t loading = render_widget_hosts_loading_.size() - | |
442 render_widget_hosts_loading_deferred_count_; | |
443 if (loading > 0) | |
444 return false; | |
445 | |
446 return true; | |
447 } | |
448 | |
449 bool SessionRestoreStatsCollector::DoneTracking() const { | |
450 // This should only be called once all non-deferred tabs have finished | |
451 // tracking. | |
452 DCHECK(DoneTrackingNonDeferredTabs()); | |
453 return render_widget_hosts_loading_.empty() && tabs_tracked_.empty(); | |
454 } | |
455 | |
252 // static | 456 // static |
253 SessionRestoreStatsCollector* SessionRestoreStatsCollector::shared_collector_ = | 457 SessionRestoreStatsCollector* SessionRestoreStatsCollector::shared_collector_ = |
254 nullptr; | 458 nullptr; |
OLD | NEW |