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

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: Sweeping refactor. 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 "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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698