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

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: Address review comments. 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 scoped_refptr<StatsReportingDelegate> reporting_delegate)
69 : got_done_tracking_non_deferred_tabs_(false),
70 got_first_foreground_load_(false),
48 got_first_paint_(false), 71 got_first_paint_(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),
75 reporting_delegate_(reporting_delegate) {
52 this_retainer_ = this; 76 this_retainer_ = this;
53 registrar_.Add(
54 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
55 content::NotificationService::AllSources());
56 } 77 }
57 78
58 SessionRestoreStatsCollector::~SessionRestoreStatsCollector() { 79 SessionRestoreStatsCollector::~SessionRestoreStatsCollector() {
59 DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 80 }
60 tabs_tracked_.empty() && render_widget_hosts_loading_.empty()); 81
61 DCHECK(shared_collector_ == this); 82 void SessionRestoreStatsCollector::TrackTabs(
62 shared_collector_ = nullptr; 83 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) {
84 DCHECK(!got_done_tracking_non_deferred_tabs_);
85
86 // If this is the first call to TrackTabs then start observing events.
87 if (tab_loader_stats_.tab_count == 0) {
88 registrar_.Add(
89 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
90 content::NotificationService::AllSources());
91 }
92
93 tab_loader_stats_.tab_count += tabs.size();
94 waiting_for_load_tab_count_ += tabs.size();
95 for (auto& tab : tabs) {
96 TabState* tab_state = RegisterForNotifications(
97 &tab.contents()->GetController());
98 // Active tabs have already started loading.
99 if (tab.is_active())
100 MarkTabAsLoading(tab_state);
101 }
102 }
103
104 void SessionRestoreStatsCollector::DeferTab(NavigationController* tab) {
105 TabState* tab_state = GetTabState(tab);
106
107 // If the tab is no longer being tracked it has already finished loading.
108 // This can occur if the user forces the tab to load before the entire session
109 // restore is over, and the TabLoader then decides it would defer loading of
110 // that tab.
111 if (!tab_state)
112 return;
113
114 // Mark this tab as deferred, if its still being tracked. A tab should not be
115 // marked as deferred twice.
116 DCHECK(!tab_state->is_deferred);
117 tab_state->is_deferred = true;
118
119 // A tab that didn't start loading before it was deferred is not to be
120 // actively monitored for loading. It's possible for
121 // waiting_for_load_tab_count_ to transition to zero here, but this will be
122 // picked up on the next call to 'Observe'.
123 if (tab_state->loading_state == TAB_IS_NOT_LOADING) {
124 DCHECK_LT(0u, waiting_for_load_tab_count_);
125 --waiting_for_load_tab_count_;
126 }
127
128 reporting_delegate_->ReportTabDeferred();
63 } 129 }
64 130
65 void SessionRestoreStatsCollector::Observe( 131 void SessionRestoreStatsCollector::Observe(
66 int type, 132 int type,
67 const content::NotificationSource& source, 133 const content::NotificationSource& source,
68 const content::NotificationDetails& details) { 134 const content::NotificationDetails& details) {
69 switch (type) { 135 switch (type) {
70 case content::NOTIFICATION_LOAD_START: { 136 case content::NOTIFICATION_LOAD_START: {
71 // Add this render_widget_host to the set of those we're waiting for 137 // 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 138 // the tab loader (only for non-deferred tabs) or because the user clicked
73 // a load has finished. 139 // on the tab.
74 NavigationController* tab = 140 NavigationController* tab = Source<NavigationController>(source).ptr();
75 content::Source<NavigationController>(source).ptr(); 141 TabState* tab_state = GetTabState(tab);
76 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); 142 MarkTabAsLoading(tab_state);
77 DCHECK(render_widget_host);
78 render_widget_hosts_loading_.insert(render_widget_host);
79 break; 143 break;
80 } 144 }
81 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { 145 case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
82 WebContents* web_contents = content::Source<WebContents>(source).ptr(); 146 // This happens when a tab has been closed. A tab can be in any state
83 RemoveTab(&web_contents->GetController()); 147 // when this occurs. Simply stop tracking the tab.
148 WebContents* web_contents = Source<WebContents>(source).ptr();
149 NavigationController* tab = &web_contents->GetController();
150 RemoveTab(tab);
84 break; 151 break;
85 } 152 }
86 case content::NOTIFICATION_LOAD_STOP: { 153 case content::NOTIFICATION_LOAD_STOP: {
87 NavigationController* tab = 154 // This occurs to loading tabs when they have finished loading. The tab
88 content::Source<NavigationController>(source).ptr(); 155 // may or may not already have painted at this point.
89 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); 156
90 render_widget_hosts_to_paint_.insert(render_widget_host); 157 // Update the tab state and any global state as necessary.
91 RemoveTab(tab); 158 NavigationController* tab = Source<NavigationController>(source).ptr();
92 if (!got_first_foreground_load_ && render_widget_host && 159 TabState* tab_state = GetTabState(tab);
93 render_widget_host->GetView() && 160 DCHECK(tab_state);
94 render_widget_host->GetView()->IsShowing()) { 161 tab_state->loading_state = TAB_IS_LOADED;
162 DCHECK_LT(0u, loading_tab_count_);
163 --loading_tab_count_;
164 if (!tab_state->is_deferred) {
165 DCHECK_LT(0u, waiting_for_load_tab_count_);
166 --waiting_for_load_tab_count_;
167 }
168
169 if (tab_state->is_deferred) {
170 reporting_delegate_->ReportDeferredTabLoaded();
171 } else {
172 DCHECK(!got_done_tracking_non_deferred_tabs_);
173 ++tab_loader_stats_.tabs_loaded;
174 }
175
176 // Update statistics for foreground tabs.
177 if (!got_first_foreground_load_ &&
178 tab_state->render_widget_host &&
179 tab_state->render_widget_host->GetView() &&
180 tab_state->render_widget_host->GetView()->IsShowing()) {
95 got_first_foreground_load_ = true; 181 got_first_foreground_load_ = true;
96 base::TimeDelta time_to_load = 182 base::TimeDelta time_to_load =
97 base::TimeTicks::Now() - restore_started_; 183 base::TimeTicks::Now() - restore_started_;
98 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded", 184 DCHECK(!got_done_tracking_non_deferred_tabs_);
99 time_to_load, 185 tab_loader_stats_.foreground_tab_first_loaded = time_to_load;
100 base::TimeDelta::FromMilliseconds(10), 186 }
101 base::TimeDelta::FromSeconds(100), 100); 187
102 // Record a time for the number of tabs, to help track down 188 // By default tabs transition to being tracked for paint events after the
103 // contention. 189 // load event has been seen. However, if the first paint event has already
104 std::string time_for_count = base::StringPrintf( 190 // been seen then this is not necessary and the tab can be removed.
105 "SessionRestore.ForegroundTabFirstLoaded_%d", tab_count_); 191 if (got_first_paint_)
106 base::HistogramBase* counter_for_count = 192 RemoveTab(tab);
107 base::Histogram::FactoryTimeGet( 193
108 time_for_count, base::TimeDelta::FromMilliseconds(10), 194 break;
109 base::TimeDelta::FromSeconds(100), 100, 195 }
110 base::Histogram::kUmaTargetedHistogramFlag); 196 case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
111 counter_for_count->AddTime(time_to_load); 197 // This notification is across all tabs in the browser so notifications
198 // will arrive for tabs that the collector is not explicitly tracking.
199
200 // Only process this event if first paint hasn't been seen and this is a
201 // paint of a visible tab.
202 RenderWidgetHost* render_widget_host =
203 Source<RenderWidgetHost>(source).ptr();
204 if (!got_first_paint_ &&
205 render_widget_host->GetView() &&
206 render_widget_host->GetView()->IsShowing()) {
207 got_first_paint_ = true;
208 TabState* tab_state = GetTabState(render_widget_host);
209 if (tab_state) {
210 // This is a paint for a tab that is explicitly being tracked so
211 // update the statistics. Otherwise the host is for a tab that's not
212 // being tracked thus some other tab has visibility and has rendered
213 // and there's no point in tracking the time to first paint. This can
214 // happen because the user opened a different tab or restored tabs
215 // to an already existing browser and an existing tab was in the
216 // foreground.
217 base::TimeDelta time_to_paint =
218 base::TimeTicks::Now() - restore_started_;
219 DCHECK(!got_done_tracking_non_deferred_tabs_);
220 tab_loader_stats_.foreground_tab_first_paint = time_to_paint;
221 }
222
223 // Once first paint has been observed the entire to-paint tracking
224 // mechanism is no longer needed.
225 registrar_.Remove(
226 this,
227 content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
228 content::NotificationService::AllSources());
229
230 // Remove any tabs that have loaded. These were only being kept around
231 // while waiting for a paint event.
232 std::vector<NavigationController*> loaded_tabs;
233 for (auto& map_entry : tabs_tracked_) {
234 TabState& tab_state = map_entry.second;
235 if (tab_state.loading_state == TAB_IS_LOADED)
236 loaded_tabs.push_back(tab_state.controller);
237 }
238 for (auto& tab : loaded_tabs)
239 RemoveTab(tab);
112 } 240 }
113 break; 241 break;
114 } 242 }
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: 243 default:
168 NOTREACHED() << "Unknown notification received:" << type; 244 NOTREACHED() << "Unknown notification received:" << type;
169 break; 245 break;
170 } 246 }
171 247
172 // Check if we are done and if so, reset |this_retainer_| as the collector no 248 // If non-deferred tabs are no longer being tracked then report tab loader
173 // longer needs to stay alive. 249 // statistics.
174 if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) && 250 if (!got_done_tracking_non_deferred_tabs_ && DoneTrackingNonDeferredTabs()) {
175 tabs_tracked_.empty() && render_widget_hosts_loading_.empty()) 251 got_done_tracking_non_deferred_tabs_ = true;
252 tab_loader_stats_.non_deferred_tabs_loaded =
253 base::TimeTicks::Now() - restore_started_;
254 reporting_delegate_->ReportTabLoaderStats(tab_loader_stats_);
255 }
256
257 // If tracking is completely finished then emit collected metrics and destroy
258 // this stats collector.
259 if (got_done_tracking_non_deferred_tabs_ && DoneTracking())
176 this_retainer_ = nullptr; 260 this_retainer_ = nullptr;
177 } 261 }
178 262
179 void SessionRestoreStatsCollector::AddTabs( 263 void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) {
180 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) { 264 // Stop observing this tab.
181 tab_count_ += tabs.size(); 265 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
182 for (auto& tab : tabs) { 266 Source<WebContents>(tab->GetWebContents()));
183 RegisterForNotifications(&tab.contents()->GetController()); 267 registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP,
184 if (tab.is_active()) { 268 Source<NavigationController>(tab));
185 RenderWidgetHost* render_widget_host = 269 registrar_.Remove(this, content::NOTIFICATION_LOAD_START,
186 GetRenderWidgetHost(&tab.contents()->GetController()); 270 Source<NavigationController>(tab));
187 render_widget_hosts_loading_.insert(render_widget_host); 271
188 } 272 auto tab_it = tabs_tracked_.find(tab);
273 DCHECK(tab_it != tabs_tracked_.end());
274 TabState& tab_state = tab_it->second;
275
276 // If this tab was waiting for a NOTIFICATION_LOAD_STOP event then update
277 // the loading counts. It is possible for the waiting_for_load_tab_count_ to
278 // transition to zero here, but this transition will be picked up by the logic
279 // in 'Observe', the only function to call 'RemoveTab'.
280 if (tab_state.loading_state == TAB_IS_LOADING) {
281 DCHECK_LT(0u, loading_tab_count_);
282 loading_tab_count_--;
189 } 283 }
284 if (tab_state.loading_state != TAB_IS_LOADED) {
285 DCHECK_LT(0u, waiting_for_load_tab_count_);
286 waiting_for_load_tab_count_--;
287 }
288
289 // Remove the tab from the |tracked_tabs_| map.
290 tabs_tracked_.erase(tab_it);
190 } 291 }
191 292
192 void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) { 293 SessionRestoreStatsCollector::TabState*
193 registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 294 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) { 295 NavigationController* tab) {
231 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 296 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
232 content::Source<WebContents>(tab->GetWebContents())); 297 Source<WebContents>(tab->GetWebContents()));
233 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, 298 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
234 content::Source<NavigationController>(tab)); 299 Source<NavigationController>(tab));
235 registrar_.Add(this, content::NOTIFICATION_LOAD_START, 300 registrar_.Add(this, content::NOTIFICATION_LOAD_START,
236 content::Source<NavigationController>(tab)); 301 Source<NavigationController>(tab));
237 tabs_tracked_.insert(tab); 302 auto result = tabs_tracked_.insert(std::make_pair(tab, TabState(tab)));
303 DCHECK(result.second);
304 TabState* tab_state = &result.first->second;
305 return tab_state;
238 } 306 }
239 307
240 RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost( 308 RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost(
241 NavigationController* tab) { 309 NavigationController* tab) {
242 WebContents* web_contents = tab->GetWebContents(); 310 WebContents* web_contents = tab->GetWebContents();
243 if (web_contents) { 311 if (web_contents) {
244 content::RenderWidgetHostView* render_widget_host_view = 312 content::RenderWidgetHostView* render_widget_host_view =
245 web_contents->GetRenderWidgetHostView(); 313 web_contents->GetRenderWidgetHostView();
246 if (render_widget_host_view) 314 if (render_widget_host_view)
247 return render_widget_host_view->GetRenderWidgetHost(); 315 return render_widget_host_view->GetRenderWidgetHost();
248 } 316 }
249 return nullptr; 317 return nullptr;
250 } 318 }
251 319
252 // static 320 SessionRestoreStatsCollector::TabState*
253 SessionRestoreStatsCollector* SessionRestoreStatsCollector::shared_collector_ = 321 SessionRestoreStatsCollector::GetTabState(NavigationController* tab) {
254 nullptr; 322 // This lookup can fail because DeferTab calls can arrive for tabs that have
323 // already loaded (user forced) and are no longer tracked.
324 auto it = tabs_tracked_.find(tab);
325 if (it == tabs_tracked_.end())
326 return nullptr;
327 return &it->second;
328 }
329
330 SessionRestoreStatsCollector::TabState*
331 SessionRestoreStatsCollector::GetTabState(RenderWidgetHost* tab) {
332 for (auto& pair : tabs_tracked_) {
333 if (pair.second.render_widget_host == tab)
334 return &pair.second;
335 }
336 // It's possible for this lookup to fail as paint events can be received for
337 // tabs that aren't being tracked.
338 return nullptr;
339 }
340
341 void SessionRestoreStatsCollector::MarkTabAsLoading(TabState* tab_state) {
342 DCHECK(tab_state->loading_state == TAB_IS_NOT_LOADING);
sky 2015/06/03 22:00:07 DCHECK_EQ
chrisha 2015/06/04 14:04:47 Done.
343 if (tab_state->loading_state != TAB_IS_NOT_LOADING)
344 return;
345 tab_state->loading_state = TAB_IS_LOADING;
346 ++loading_tab_count_;
347
348 DCHECK(!got_done_tracking_non_deferred_tabs_);
349 tab_loader_stats_.parallel_tab_loads = std::max(
350 tab_loader_stats_.parallel_tab_loads,
351 loading_tab_count_);
352
353 // Get the RenderWidgetHost for the tab and add it to the secondary index.
354 RenderWidgetHost* render_widget_host = GetRenderWidgetHost(
355 tab_state->controller);
356 DCHECK(render_widget_host);
357 tab_state->render_widget_host = render_widget_host;
358 }
359
360 bool SessionRestoreStatsCollector::DoneTrackingNonDeferredTabs() const {
361 // This should only be called when it hasn't yet returned true.
362 DCHECK(!got_done_tracking_non_deferred_tabs_);
363 return got_first_paint_ && waiting_for_load_tab_count_ == 0;
364 }
365
366 bool SessionRestoreStatsCollector::DoneTracking() const {
367 // This should only be called once DoneTrackingNonDeferredTabs has returned
368 // true.
369 DCHECK(got_done_tracking_non_deferred_tabs_);
370 return tabs_tracked_.empty();
371 }
372
373
374 SessionRestoreStatsCollector::UmaStatsReportingDelegate::
375 UmaStatsReportingDelegate()
376 : got_report_tab_deferred_(false) {
377 }
378
379 void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
380 ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) {
381 UMA_HISTOGRAM_COUNTS_100("SessionRestore.TabCount",
382 tab_loader_stats.tab_count);
383
384 UMA_HISTOGRAM_ENUMERATION(kSessionRestoreActions,
385 SESSION_RESTORE_ACTIONS_UMA_INITIATED,
386 SESSION_RESTORE_ACTIONS_UMA_MAX);
387
388 for (size_t i = 0; i < tab_loader_stats.tab_count; ++i) {
389 UMA_HISTOGRAM_ENUMERATION("SessionRestore.TabActions",
390 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED,
391 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX);
392 }
393
394 for (size_t i = 0; i < tab_loader_stats.tabs_loaded; ++i) {
395 UMA_HISTOGRAM_ENUMERATION("SessionRestore.TabActions",
396 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED,
397 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX);
398 }
399
400 if (!tab_loader_stats.foreground_tab_first_loaded.is_zero()) {
401 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded",
402 tab_loader_stats.foreground_tab_first_loaded,
403 base::TimeDelta::FromMilliseconds(10),
404 base::TimeDelta::FromSeconds(100), 100);
405
406 // Record a time for the number of tabs, to help track down contention.
407 std::string time_for_count = base::StringPrintf(
408 "SessionRestore.ForegroundTabFirstLoaded_%d",
409 tab_loader_stats.tab_count);
410 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
411 time_for_count, base::TimeDelta::FromMilliseconds(10),
412 base::TimeDelta::FromSeconds(100), 100,
413 base::Histogram::kUmaTargetedHistogramFlag);
414 counter_for_count->AddTime(tab_loader_stats.foreground_tab_first_loaded);
415 }
416
417 if (!tab_loader_stats.foreground_tab_first_paint.is_zero()) {
418 UMA_HISTOGRAM_CUSTOM_TIMES(
419 "SessionRestore.ForegroundTabFirstPaint3",
420 tab_loader_stats.foreground_tab_first_paint,
421 base::TimeDelta::FromMilliseconds(100),
422 base::TimeDelta::FromMinutes(16), 50);
423
424 std::string time_for_count = base::StringPrintf(
425 "SessionRestore.ForegroundTabFirstPaint3_%d",
426 tab_loader_stats.tab_count);
427 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
428 time_for_count, base::TimeDelta::FromMilliseconds(100),
429 base::TimeDelta::FromMinutes(16), 50,
430 base::Histogram::kUmaTargetedHistogramFlag);
431 counter_for_count->AddTime(tab_loader_stats.foreground_tab_first_paint);
432 }
433
434 if (!tab_loader_stats.non_deferred_tabs_loaded.is_zero()) {
435 UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.AllTabsLoaded",
436 tab_loader_stats.non_deferred_tabs_loaded,
437 base::TimeDelta::FromMilliseconds(10),
438 base::TimeDelta::FromSeconds(100), 100);
439
440 // Record a time for the number of tabs, to help track down contention.
441 std::string time_for_count =
442 base::StringPrintf("SessionRestore.AllTabsLoaded_%d",
443 tab_loader_stats.tab_count);
444 base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
445 time_for_count, base::TimeDelta::FromMilliseconds(10),
446 base::TimeDelta::FromSeconds(100), 100,
447 base::Histogram::kUmaTargetedHistogramFlag);
448 counter_for_count->AddTime(tab_loader_stats.non_deferred_tabs_loaded);
449 }
450
451 UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
452 tab_loader_stats.parallel_tab_loads);
453 }
454
455 void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
456 ReportTabDeferred() {
457 if (!got_report_tab_deferred_) {
458 got_report_tab_deferred_ = true;
459
460 UMA_HISTOGRAM_ENUMERATION(kSessionRestoreActions,
461 SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS,
462 SESSION_RESTORE_ACTIONS_UMA_MAX);
463 }
464
465 UMA_HISTOGRAM_ENUMERATION(
466 "SessionRestore.TabActions",
467 SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED,
468 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX);
469 }
470
471 void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
472 ReportDeferredTabLoaded() {
473 UMA_HISTOGRAM_ENUMERATION(
474 "SessionRestore.TabActions",
475 SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED,
476 SESSION_RESTORE_TAB_ACTIONS_UMA_MAX);
477 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698