Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(472)

Side by Side Diff: chrome/browser/sessions/session_restore_stats_collector.cc

Issue 1136523004: [Sessions] Add detailed logging of SessionRestore events. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix typo. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "base/time/default_tick_clock.h"
11 #include "content/public/browser/notification_service.h" 12 #include "content/public/browser/notification_service.h"
12 #include "content/public/browser/notification_types.h" 13 #include "content/public/browser/notification_types.h"
13 #include "content/public/browser/render_widget_host_view.h" 14 #include "content/public/browser/render_widget_host_view.h"
14 #include "content/public/browser/web_contents.h" 15 #include "content/public/browser/web_contents.h"
15 16
17 namespace {
18
16 using content::NavigationController; 19 using content::NavigationController;
17 using content::RenderWidgetHost; 20 using content::RenderWidgetHost;
21 using content::Source;
18 using content::WebContents; 22 using content::WebContents;
19 23
20 // static 24 // The enumeration values stored in the "SessionRestore.Actions" histogram.
21 void SessionRestoreStatsCollector::TrackTabs( 25 enum SessionRestoreActionsUma {
22 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, 26 // Counts the total number of session restores that have occurred.
23 const base::TimeTicks& restore_started) { 27 SESSION_RESTORE_ACTIONS_UMA_INITIATED = 0,
24 if (!shared_collector_) 28 // Counts the number of session restores that have seen deferred tab loadings
25 shared_collector_ = new SessionRestoreStatsCollector(restore_started); 29 // for whatever reason (almost certainly due to memory pressure).
30 SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS = 1,
31 // The size of this enum. Must be the last entry.
32 SESSION_RESTORE_ACTIONS_UMA_MAX,
33 };
26 34
27 shared_collector_->AddTabs(tabs); 35 // Emits a SessionRestore.Actions UMA event.
36 void EmitUmaSessionRestoreActionEvent(SessionRestoreActionsUma action) {
37 UMA_HISTOGRAM_ENUMERATION("SessionRestore.Actions", action,
38 SESSION_RESTORE_ACTIONS_UMA_MAX);
28 } 39 }
29 40
30 // static 41 // The enumeration of values stored in the "SessionRestore.TabActions"
31 void SessionRestoreStatsCollector::TrackActiveTabs( 42 // histogram.
32 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, 43 enum SessionRestoreTabActionsUma {
33 const base::TimeTicks& restore_started) { 44 // Incremented for each tab created in a session restore.
34 if (!shared_collector_) 45 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED = 0,
35 shared_collector_ = new SessionRestoreStatsCollector(restore_started); 46 // Incremented for each tab that session restore decides not to load.
47 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED = 1,
48 // Incremented for each tab that is successfully loaded.
49 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED = 2,
50 // Incremented for each session-restore-deferred tab that is subsequently
51 // loaded.
52 SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED = 3,
53 // The size of this enum. Must be the last entry.
54 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX,
55 };
36 56
37 std::vector<SessionRestoreDelegate::RestoredTab> active_tabs; 57 // Emits a SessionRestore.TabActions UMA event.
38 for (auto tab : tabs) { 58 void EmitUmaSessionRestoreTabActionEvent(SessionRestoreTabActionsUma action) {
39 if (tab.is_active()) 59 UMA_HISTOGRAM_ENUMERATION("SessionRestore.TabActions", action,
40 active_tabs.push_back(tab); 60 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX);
41 } 61 }
42 shared_collector_->AddTabs(active_tabs); 62
63 } // namespace
64
65 SessionRestoreStatsCollector::TabLoaderStats::TabLoaderStats()
66 : tab_count(0u), tabs_loaded(0u), parallel_tab_loads(0u) {
67 }
68
69 SessionRestoreStatsCollector::TabState::TabState(
70 NavigationController* controller)
71 : controller(controller),
72 render_widget_host(nullptr),
73 is_deferred(false),
74 loading_state(TAB_IS_NOT_LOADING) {
43 } 75 }
44 76
45 SessionRestoreStatsCollector::SessionRestoreStatsCollector( 77 SessionRestoreStatsCollector::SessionRestoreStatsCollector(
46 const base::TimeTicks& restore_started) 78 const base::TimeTicks& restore_started,
47 : got_first_foreground_load_(false), 79 scoped_ptr<StatsReportingDelegate> reporting_delegate)
80 : done_tracking_non_deferred_tabs_(false),
81 got_first_foreground_load_(false),
48 got_first_paint_(false), 82 got_first_paint_(false),
49 restore_started_(restore_started), 83 restore_started_(restore_started),
50 tab_count_(0), 84 waiting_for_load_tab_count_(0u),
51 max_parallel_tab_loads_(0) { 85 loading_tab_count_(0u),
86 deferred_tab_count_(0u),
87 tick_clock_(new base::DefaultTickClock()),
88 reporting_delegate_(reporting_delegate.Pass()) {
52 this_retainer_ = this; 89 this_retainer_ = this;
53 registrar_.Add(
54 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
55 content::NotificationService::AllSources());
56 } 90 }
57 91
58 SessionRestoreStatsCollector::~SessionRestoreStatsCollector() { 92 SessionRestoreStatsCollector::~SessionRestoreStatsCollector() {
59 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 93 }
60 tabs_tracked_.empty() && render_widget_hosts_loading_.empty()); 94
61 DCHECK(shared_collector_ == this); 95 void SessionRestoreStatsCollector::TrackTabs(
62 shared_collector_ = nullptr; 96 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) {
97 DCHECK(!done_tracking_non_deferred_tabs_);
98
99 // If this is the first call to TrackTabs then start observing events.
100 if (tab_loader_stats_.tab_count == 0) {
101 registrar_.Add(
102 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
103 content::NotificationService::AllSources());
104 }
105
106 tab_loader_stats_.tab_count += tabs.size();
107 waiting_for_load_tab_count_ += tabs.size();
108 for (const auto& tab : tabs) {
109 TabState* tab_state =
110 RegisterForNotifications(&tab.contents()->GetController());
111 // Active tabs have already started loading.
112 if (tab.is_active())
113 MarkTabAsLoading(tab_state);
114 }
115 }
116
117 void SessionRestoreStatsCollector::DeferTab(NavigationController* tab) {
118 TabState* tab_state = GetTabState(tab);
119
120 // If the tab is no longer being tracked it has already finished loading.
121 // This can occur if the user forces the tab to load before the entire session
122 // restore is over, and the TabLoader then decides it would defer loading of
123 // that tab.
124 if (!tab_state)
125 return;
126
127 // Mark this tab as deferred, if its still being tracked. A tab should not be
128 // marked as deferred twice.
129 DCHECK(!tab_state->is_deferred);
130 tab_state->is_deferred = true;
131 ++deferred_tab_count_;
132
133 // A tab that didn't start loading before it was deferred is not to be
134 // actively monitored for loading.
135 if (tab_state->loading_state == TAB_IS_NOT_LOADING) {
136 DCHECK_LT(0u, waiting_for_load_tab_count_);
137 if (--waiting_for_load_tab_count_ == 0)
138 ReleaseIfDoneTracking();
139 }
140
141 reporting_delegate_->ReportTabDeferred();
63 } 142 }
64 143
65 void SessionRestoreStatsCollector::Observe( 144 void SessionRestoreStatsCollector::Observe(
66 int type, 145 int type,
67 const content::NotificationSource& source, 146 const content::NotificationSource& source,
68 const content::NotificationDetails& details) { 147 const content::NotificationDetails& details) {
69 switch (type) { 148 switch (type) {
70 case content::NOTIFICATION_LOAD_START: { 149 case content::NOTIFICATION_LOAD_START: {
71 // Add this render_widget_host to the set of those we're waiting for 150 // 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 151 // the tab loader (only for non-deferred tabs) or because the user clicked
73 // a load has finished. 152 // on the tab.
74 NavigationController* tab = 153 NavigationController* tab = Source<NavigationController>(source).ptr();
75 content::Source<NavigationController>(source).ptr(); 154 TabState* tab_state = GetTabState(tab);
76 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); 155 MarkTabAsLoading(tab_state);
77 DCHECK(render_widget_host);
78 render_widget_hosts_loading_.insert(render_widget_host);
79 break; 156 break;
80 } 157 }
81 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { 158 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
82 WebContents* web_contents = content::Source<WebContents>(source).ptr(); 159 // This happens when a tab has been closed. A tab can be in any state
83 RemoveTab(&web_contents->GetController()); 160 // when this occurs. Simply stop tracking the tab.
161 WebContents* web_contents = Source<WebContents>(source).ptr();
162 NavigationController* tab = &web_contents->GetController();
163 RemoveTab(tab);
84 break; 164 break;
85 } 165 }
86 case content::NOTIFICATION_LOAD_STOP: { 166 case content::NOTIFICATION_LOAD_STOP: {
87 NavigationController* tab = 167 // This occurs to loading tabs when they have finished loading. The tab
88 content::Source<NavigationController>(source).ptr(); 168 // may or may not already have painted at this point.
89 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); 169
90 render_widget_hosts_to_paint_.insert(render_widget_host); 170 // Update the tab state and any global state as necessary.
91 RemoveTab(tab); 171 NavigationController* tab = Source<NavigationController>(source).ptr();
92 if (!got_first_foreground_load_ && render_widget_host && 172 TabState* tab_state = GetTabState(tab);
93 render_widget_host->GetView() && 173 DCHECK(tab_state);
174 tab_state->loading_state = TAB_IS_LOADED;
175 DCHECK_LT(0u, loading_tab_count_);
176 --loading_tab_count_;
177 if (!tab_state->is_deferred) {
178 DCHECK_LT(0u, waiting_for_load_tab_count_);
179 --waiting_for_load_tab_count_;
180 }
181
182 if (tab_state->is_deferred) {
183 reporting_delegate_->ReportDeferredTabLoaded();
184 } else {
185 DCHECK(!done_tracking_non_deferred_tabs_);
186 ++tab_loader_stats_.tabs_loaded;
187 }
188
189 // Update statistics for foreground tabs.
190 base::TimeDelta time_to_load = tick_clock_->NowTicks() - restore_started_;
191 if (!got_first_foreground_load_ && tab_state->render_widget_host &&
192 tab_state->render_widget_host->GetView() &&
193 tab_state->render_widget_host->GetView()->IsShowing()) {
194 got_first_foreground_load_ = true;
195 DCHECK(!done_tracking_non_deferred_tabs_);
196 tab_loader_stats_.foreground_tab_first_loaded = time_to_load;
197 }
198
199 // Update statistics for all tabs, if this wasn't a deferred tab. This is
200 // done here and not in ReleaseIfDoneTracking because it is possible to
201 // wait for a paint long after all loads have completed.
202 if (!done_tracking_non_deferred_tabs_ && !tab_state->is_deferred)
203 tab_loader_stats_.non_deferred_tabs_loaded = time_to_load;
204
205 // By default tabs transition to being tracked for paint events after the
206 // load event has been seen. However, if the first paint event has already
207 // been seen then this is not necessary and the tab can be removed.
208 if (got_first_paint_)
209 RemoveTab(tab);
210
211 break;
212 }
213 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
214 // This notification is across all tabs in the browser so notifications
215 // will arrive for tabs that the collector is not explicitly tracking.
216
217 // Only process this event if first paint hasn't been seen and this is a
218 // paint of a visible tab.
219 RenderWidgetHost* render_widget_host =
220 Source<RenderWidgetHost>(source).ptr();
221 if (!got_first_paint_ && render_widget_host->GetView() &&
94 render_widget_host->GetView()->IsShowing()) { 222 render_widget_host->GetView()->IsShowing()) {
95 got_first_foreground_load_ = true; 223 got_first_paint_ = true;
96 base::TimeDelta time_to_load = 224 TabState* tab_state = GetTabState(render_widget_host);
97 base::TimeTicks::Now() - restore_started_; 225 if (tab_state) {
98 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded", 226 // This is a paint for a tab that is explicitly being tracked so
99 time_to_load, 227 // update the statistics. Otherwise the host is for a tab that's not
100 base::TimeDelta::FromMilliseconds(10), 228 // being tracked thus some other tab has visibility and has rendered
101 base::TimeDelta::FromSeconds(100), 100); 229 // and there's no point in tracking the time to first paint. This can
102 // Record a time for the number of tabs, to help track down 230 // happen because the user opened a different tab or restored tabs
103 // contention. 231 // to an already existing browser and an existing tab was in the
104 std::string time_for_count = base::StringPrintf( 232 // foreground.
105 "SessionRestore.ForegroundTabFirstLoaded_%d", tab_count_); 233 base::TimeDelta time_to_paint =
106 base::HistogramBase* counter_for_count = 234 tick_clock_->NowTicks() - restore_started_;
107 base::Histogram::FactoryTimeGet( 235 DCHECK(!done_tracking_non_deferred_tabs_);
108 time_for_count, base::TimeDelta::FromMilliseconds(10), 236 tab_loader_stats_.foreground_tab_first_paint = time_to_paint;
109 base::TimeDelta::FromSeconds(100), 100, 237 }
110 base::Histogram::kUmaTargetedHistogramFlag); 238
111 counter_for_count->AddTime(time_to_load); 239 // Once first paint has been observed the entire to-paint tracking
240 // mechanism is no longer needed.
241 registrar_.Remove(
242 this,
243 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
244 content::NotificationService::AllSources());
245
246 // Remove any tabs that have loaded. These were only being kept around
247 // while waiting for a paint event.
248 std::vector<NavigationController*> loaded_tabs;
249 for (auto& map_entry : tabs_tracked_) {
250 TabState& tab_state = map_entry.second;
251 if (tab_state.loading_state == TAB_IS_LOADED)
252 loaded_tabs.push_back(tab_state.controller);
253 }
254 for (auto& tab : loaded_tabs)
255 RemoveTab(tab);
112 } 256 }
113 break; 257 break;
114 } 258 }
115 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
116 RenderWidgetHost* render_widget_host =
117 content::Source<RenderWidgetHost>(source).ptr();
118 if (!got_first_paint_ && render_widget_host->GetView() &&
119 render_widget_host->GetView()->IsShowing()) {
120 if (render_widget_hosts_to_paint_.find(render_widget_host) !=
121 render_widget_hosts_to_paint_.end()) {
122 // Got a paint for one of our renderers, so record time.
123 got_first_paint_ = true;
124 base::TimeDelta time_to_paint =
125 base::TimeTicks::Now() - restore_started_;
126 // TODO(danduong): to remove this with 467680, to make sure we
127 // don't forget to clean this up.
128 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint",
129 time_to_paint,
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
160 // happen because the user opened a different tab or restored tabs
161 // to an already existing browser and an existing tab painted.
162 got_first_paint_ = true;
163 }
164 }
165 break;
166 }
167 default: 259 default:
168 NOTREACHED() << "Unknown notification received:" << type; 260 NOTREACHED() << "Unknown notification received:" << type;
169 break; 261 break;
170 } 262 }
171 263
172 // Check if we are done and if so, reset |this_retainer_| as the collector no 264 ReleaseIfDoneTracking();
173 // longer needs to stay alive.
174 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
175 tabs_tracked_.empty() && render_widget_hosts_loading_.empty())
176 this_retainer_ = nullptr;
177 } 265 }
178 266
179 void SessionRestoreStatsCollector::AddTabs( 267 void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) {
180 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) { 268 // Stop observing this tab.
181 tab_count_ += tabs.size(); 269 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
182 for (auto& tab : tabs) { 270 Source<WebContents>(tab->GetWebContents()));
183 RegisterForNotifications(&tab.contents()->GetController()); 271 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP,
184 if (tab.is_active()) { 272 Source<NavigationController>(tab));
185 RenderWidgetHost* render_widget_host = 273 registrar_.Remove(this, content::NOTIFICATION_LOAD_START,
186 GetRenderWidgetHost(&tab.contents()->GetController()); 274 Source<NavigationController>(tab));
187 render_widget_hosts_loading_.insert(render_widget_host); 275
188 } 276 auto tab_it = tabs_tracked_.find(tab);
277 DCHECK(tab_it != tabs_tracked_.end());
278 TabState& tab_state = tab_it->second;
279
280 // If this tab was waiting for a NOTIFICATION_LOAD_STOP event then update
281 // the loading counts.
282 if (tab_state.loading_state == TAB_IS_LOADING) {
283 DCHECK_LT(0u, loading_tab_count_);
284 --loading_tab_count_;
285 }
286
287 // Only non-deferred not-loading/not-loaded tabs are waiting to be loaded.
288 if (tab_state.loading_state != TAB_IS_LOADED && !tab_state.is_deferred) {
289 DCHECK_LT(0u, waiting_for_load_tab_count_);
290 // It's possible for waiting_for_load_tab_count_ to reach zero here. This
291 // function is only called from 'Observe', so the transition will be
292 // noticed there.
293 --waiting_for_load_tab_count_;
294 }
295
296 if (tab_state.is_deferred)
297 --deferred_tab_count_;
298
299 // Remove the tab from the |tracked_tabs_| map.
300 tabs_tracked_.erase(tab_it);
301
302 // It is possible for all restored contents to be destroyed or forcibly
303 // renavigated before a first paint has arrived. This can be detected by
304 // tabs_tracked_ containing only deferred tabs. At this point the paint
305 // mechanism can be disabled and stats collection will stop.
306 if (tabs_tracked_.size() == deferred_tab_count_ && !got_first_paint_) {
307 got_first_paint_ = true;
308 registrar_.Remove(
309 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
310 content::NotificationService::AllSources());
189 } 311 }
190 } 312 }
191 313
192 void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) { 314 SessionRestoreStatsCollector::TabState*
193 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 315 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) { 316 NavigationController* tab) {
231 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 317 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
232 content::Source<WebContents>(tab->GetWebContents())); 318 Source<WebContents>(tab->GetWebContents()));
233 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 319 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
234 content::Source<NavigationController>(tab)); 320 Source<NavigationController>(tab));
235 registrar_.Add(this, content::NOTIFICATION_LOAD_START, 321 registrar_.Add(this, content::NOTIFICATION_LOAD_START,
236 content::Source<NavigationController>(tab)); 322 Source<NavigationController>(tab));
237 tabs_tracked_.insert(tab); 323 auto result = tabs_tracked_.insert(std::make_pair(tab, TabState(tab)));
324 DCHECK(result.second);
325 TabState* tab_state = &result.first->second;
326 return tab_state;
238 } 327 }
239 328
240 RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost( 329 RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost(
241 NavigationController* tab) { 330 NavigationController* tab) {
242 WebContents* web_contents = tab->GetWebContents(); 331 WebContents* web_contents = tab->GetWebContents();
243 if (web_contents) { 332 if (web_contents) {
244 content::RenderWidgetHostView* render_widget_host_view = 333 content::RenderWidgetHostView* render_widget_host_view =
245 web_contents->GetRenderWidgetHostView(); 334 web_contents->GetRenderWidgetHostView();
246 if (render_widget_host_view) 335 if (render_widget_host_view)
247 return render_widget_host_view->GetRenderWidgetHost(); 336 return render_widget_host_view->GetRenderWidgetHost();
248 } 337 }
249 return nullptr; 338 return nullptr;
250 } 339 }
251 340
252 // static 341 SessionRestoreStatsCollector::TabState*
253 SessionRestoreStatsCollector* SessionRestoreStatsCollector::shared_collector_ = 342 SessionRestoreStatsCollector::GetTabState(NavigationController* tab) {
254 nullptr; 343 // This lookup can fail because DeferTab calls can arrive for tabs that have
344 // already loaded (user forced) and are no longer tracked.
345 auto it = tabs_tracked_.find(tab);
346 if (it == tabs_tracked_.end())
347 return nullptr;
348 return &it->second;
349 }
350
351 SessionRestoreStatsCollector::TabState*
352 SessionRestoreStatsCollector::GetTabState(RenderWidgetHost* tab) {
353 for (auto& pair : tabs_tracked_) {
354 if (pair.second.render_widget_host == tab)
355 return &pair.second;
356 }
357 // It's possible for this lookup to fail as paint events can be received for
358 // tabs that aren't being tracked.
359 return nullptr;
360 }
361
362 void SessionRestoreStatsCollector::MarkTabAsLoading(TabState* tab_state) {
363 // If the tab has already started or finished loading then a user navigation
364 // has caused the tab to be forcibly reloaded. This tab can be removed from
365 // observation.
366 if (tab_state->loading_state == TAB_IS_LOADED) {
367 RemoveTab(tab_state->controller);
368 return;
369 }
370
371 DCHECK_EQ(TAB_IS_NOT_LOADING, tab_state->loading_state);
372 if (tab_state->loading_state != TAB_IS_NOT_LOADING)
373 return;
374 tab_state->loading_state = TAB_IS_LOADING;
375 ++loading_tab_count_;
376
377 if (!done_tracking_non_deferred_tabs_) {
378 tab_loader_stats_.parallel_tab_loads =
379 std::max(tab_loader_stats_.parallel_tab_loads, loading_tab_count_);
380 }
381
382 // Get the RenderWidgetHost for the tab and add it to the secondary index.
383 RenderWidgetHost* render_widget_host =
384 GetRenderWidgetHost(tab_state->controller);
385 DCHECK(render_widget_host);
386 tab_state->render_widget_host = render_widget_host;
387 }
388
389 void SessionRestoreStatsCollector::ReleaseIfDoneTracking() {
390 // If non-deferred tabs are no longer being tracked then report tab loader
391 // statistics.
392 if (!done_tracking_non_deferred_tabs_ && got_first_paint_ &&
393 waiting_for_load_tab_count_ == 0) {
394 done_tracking_non_deferred_tabs_ = true;
395 reporting_delegate_->ReportTabLoaderStats(tab_loader_stats_);
396 }
397
398 // If tracking is completely finished then emit collected metrics and destroy
399 // this stats collector.
400 if (done_tracking_non_deferred_tabs_ && tabs_tracked_.empty())
401 this_retainer_ = nullptr;
402 }
403
404 SessionRestoreStatsCollector::UmaStatsReportingDelegate::
405 UmaStatsReportingDelegate()
406 : got_report_tab_deferred_(false) {
407 }
408
409 void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
410 ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) {
411 UMA_HISTOGRAM_COUNTS_100("SessionRestore.TabCount",
412 tab_loader_stats.tab_count);
413
414 EmitUmaSessionRestoreActionEvent(SESSION_RESTORE_ACTIONS_UMA_INITIATED);
415
416 for (size_t i = 0; i < tab_loader_stats.tab_count; ++i) {
417 EmitUmaSessionRestoreTabActionEvent(
418 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED);
419 }
420
421 for (size_t i = 0; i < tab_loader_stats.tabs_loaded; ++i) {
422 EmitUmaSessionRestoreTabActionEvent(
423 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED);
424 }
425
426 if (!tab_loader_stats.foreground_tab_first_loaded.is_zero()) {
427 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded",
428 tab_loader_stats.foreground_tab_first_loaded,
429 base::TimeDelta::FromMilliseconds(10),
430 base::TimeDelta::FromSeconds(100), 100);
431
432 // Record a time for the number of tabs, to help track down contention.
433 std::string time_for_count = base::StringPrintf(
434 "SessionRestore.ForegroundTabFirstLoaded_%u",
435 static_cast<unsigned int>(tab_loader_stats.tab_count));
436 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
437 time_for_count, base::TimeDelta::FromMilliseconds(10),
438 base::TimeDelta::FromSeconds(100), 100,
439 base::Histogram::kUmaTargetedHistogramFlag);
440 counter_for_count->AddTime(tab_loader_stats.foreground_tab_first_loaded);
441 }
442
443 if (!tab_loader_stats.foreground_tab_first_paint.is_zero()) {
444 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint3",
445 tab_loader_stats.foreground_tab_first_paint,
446 base::TimeDelta::FromMilliseconds(100),
447 base::TimeDelta::FromMinutes(16), 50);
448
449 std::string time_for_count = base::StringPrintf(
450 "SessionRestore.ForegroundTabFirstPaint3_%u",
451 static_cast<unsigned int>(tab_loader_stats.tab_count));
452 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
453 time_for_count, base::TimeDelta::FromMilliseconds(100),
454 base::TimeDelta::FromMinutes(16), 50,
455 base::Histogram::kUmaTargetedHistogramFlag);
456 counter_for_count->AddTime(tab_loader_stats.foreground_tab_first_paint);
457 }
458
459 if (!tab_loader_stats.non_deferred_tabs_loaded.is_zero()) {
460 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.AllTabsLoaded",
461 tab_loader_stats.non_deferred_tabs_loaded,
462 base::TimeDelta::FromMilliseconds(10),
463 base::TimeDelta::FromSeconds(100), 100);
464
465 // Record a time for the number of tabs, to help track down contention.
466 std::string time_for_count = base::StringPrintf(
467 "SessionRestore.AllTabsLoaded_%u",
468 static_cast<unsigned int>(tab_loader_stats.tab_count));
469 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
470 time_for_count, base::TimeDelta::FromMilliseconds(10),
471 base::TimeDelta::FromSeconds(100), 100,
472 base::Histogram::kUmaTargetedHistogramFlag);
473 counter_for_count->AddTime(tab_loader_stats.non_deferred_tabs_loaded);
474 }
475
476 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
477 tab_loader_stats.parallel_tab_loads);
478 }
479
480 void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
481 ReportTabDeferred() {
482 if (!got_report_tab_deferred_) {
483 got_report_tab_deferred_ = true;
484 EmitUmaSessionRestoreActionEvent(SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS);
485 }
486
487 EmitUmaSessionRestoreTabActionEvent(
488 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED);
489 }
490
491 void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
492 ReportDeferredTabLoaded() {
493 EmitUmaSessionRestoreTabActionEvent(
494 SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED);
495 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698