Index: chrome/browser/sessions/session_restore_stats_collector.cc |
diff --git a/chrome/browser/sessions/session_restore_stats_collector.cc b/chrome/browser/sessions/session_restore_stats_collector.cc |
index f593b6eb299186711d4b4546b118c676c3f6413b..c1299b2a245a6d28e75241e56ccb8b1fd6133c0b 100644 |
--- a/chrome/browser/sessions/session_restore_stats_collector.cc |
+++ b/chrome/browser/sessions/session_restore_stats_collector.cc |
@@ -17,6 +17,51 @@ using content::NavigationController; |
using content::RenderWidgetHost; |
using content::WebContents; |
+namespace { |
+ |
+// Metric names. |
+const char kSessionRestoreActions[] = "SessionRestore.Actions"; |
+const char kSessionRestoreTabCount[] = "SessionRestore.TabCount"; |
+const char kSessionRestoreTabActions[] = "SessionRestore.TabActions"; |
+ |
+// The enumeration values stored in the kSessionRestoreActions histogram. |
+enum SessionRestoreActionsUma { |
+ // Counts the total number of session restores that have occurred. |
+ kSessionRestoreActionsUma_Initiated = 0, |
sky
2015/05/12 15:27:56
SESSION_RESTORE_ACTION_UMA_INITIATED (see chrome s
chrisha
2015/05/13 21:18:01
Done.
|
+ // Counts the number of session restores that have been deferred tab loadings |
+ // for whatever reason (almost certainly due to memory pressure). |
+ kSessionRestoreActionsUma_DeferredTabs = 1, |
+ // The size of this enum. Must be the last entry. |
+ kSessionRestoreActionsUma_Max, |
+}; |
+ |
+// The enumeration of values stored in the kSessionRestoreTabActions histogram. |
+enum SessionRestoreTabActionsUma { |
+ // Incremented for each tab created in a session restore. |
+ kSessionRestoreTabActionsUma_TabCreated = 0, |
+ // Incremented for each tab started to load by the session restore. |
+ kSessionRestoreTabActionsUma_TabLoading = 1, |
+ // Incremented for each tab that session restore decides not to load. |
+ kSessionRestoreTabActionsUma_TabLoadingDeferred = 2, |
+ // Incremented for each tab that is successfully loaded. |
+ kSessionRestoreTabActionsUma_TabLoaded = 3, |
+ // Incremented for each session-restore-deferred tab that subsequently starts |
+ // to load. |
+ kSessionRestoreTabActionsUma_DeferredTabLoading = 4, |
+ // Incremented for each non-deferred not-yet-loaded tab closed by the user. |
+ kSessionRestoreTabActionsUma_NonDeferredNotLoadingTabClosed = 5, |
+ // Incremented for each non-deferred actively-loading tab closed by the user. |
+ kSessionRestoreTabActionsUma_NonDeferredLoadingTabClosed = 6, |
+ // Incremented for each deferred not-yet-loaded tab closed by the user. |
+ kSessionRestoreTabActionsUma_DeferredNotLoadingTabClosed = 7, |
+ // Incremented for each deferred actively-loading tab closed by the user. |
+ kSessionRestoreTabActionsUma_DeferredLoadingTabClosed = 8, |
+ // The size of this enum. Must be the last entry. |
+ kSessionRestoreTabActionsUma_Max, |
+}; |
+ |
+} // namespace |
+ |
// static |
void SessionRestoreStatsCollector::TrackTabs( |
const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, |
@@ -27,12 +72,22 @@ void SessionRestoreStatsCollector::TrackTabs( |
shared_collector_->AddTabs(tabs); |
} |
+// static |
+void SessionRestoreStatsCollector::DeferTab( |
+ content::NavigationController* tab) { |
+ // It only makes sense for this to have been called *after* DeferTab, so a |
+ // stats collector will always exist. |
sky
2015/05/12 15:27:56
DCHECK(shared_collector_)
chrisha
2015/05/13 21:18:01
Done.
|
+ shared_collector_->DeferTabImpl(tab); |
+} |
+ |
SessionRestoreStatsCollector::SessionRestoreStatsCollector( |
const base::TimeTicks& restore_started) |
: got_first_foreground_load_(false), |
got_first_paint_(false), |
restore_started_(restore_started), |
tab_count_(0), |
+ tab_deferred_count_(0), |
+ session_restore_id_(0), |
max_parallel_tab_loads_(0) { |
this_retainer_ = this; |
registrar_.Add( |
@@ -58,6 +113,16 @@ void SessionRestoreStatsCollector::Observe( |
// a load has finished. |
NavigationController* tab = |
content::Source<NavigationController>(source).ptr(); |
+ bool is_deferred = IsDeferred(tab); |
+ |
+ // Record the appropriate tab loading event type. |
+ auto tab_action = |
+ is_deferred ? kSessionRestoreTabActionsUma_TabLoading : |
+ kSessionRestoreTabActionsUma_DeferredTabLoading; |
+ UMA_HISTOGRAM_ENUMERATION(kSessionRestoreTabActions, |
+ tab_action, |
+ kSessionRestoreTabActionsUma_Max); |
+ |
RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); |
DCHECK(render_widget_host); |
render_widget_hosts_loading_.insert(render_widget_host); |
@@ -65,15 +130,46 @@ void SessionRestoreStatsCollector::Observe( |
} |
case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { |
WebContents* web_contents = content::Source<WebContents>(source).ptr(); |
- RemoveTab(&web_contents->GetController()); |
+ NavigationController* tab = &web_contents->GetController(); |
+ bool is_deferred = IsDeferred(tab); |
+ |
+ // Record a tab action for the tab that is being closed. If this tab is |
+ // loading it will have a RenderWidgetHost in the tracking set. |
+ RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); |
+ auto tab_action = kSessionRestoreTabActionsUma_Max; |
+ if (render_widget_hosts_loading_.count(render_widget_host) > 0) { |
+ // This tab is loading. |
+ tab_action = is_deferred ? |
+ kSessionRestoreTabActionsUma_DeferredLoadingTabClosed : |
+ kSessionRestoreTabActionsUma_NonDeferredLoadingTabClosed; |
+ } else { |
+ // This tab is not loading. |
+ tab_action = is_deferred ? |
+ kSessionRestoreTabActionsUma_DeferredNotLoadingTabClosed : |
+ kSessionRestoreTabActionsUma_NonDeferredNotLoadingTabClosed; |
+ } |
+ UMA_HISTOGRAM_ENUMERATION(kSessionRestoreTabActions, |
+ tab_action, |
+ kSessionRestoreTabActionsUma_Max); |
+ |
+ RemoveTab(is_deferred, tab); |
break; |
} |
case content::NOTIFICATION_LOAD_STOP: { |
NavigationController* tab = |
content::Source<NavigationController>(source).ptr(); |
+ bool is_deferred = IsDeferred(tab); |
RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); |
render_widget_hosts_to_paint_.insert(render_widget_host); |
- RemoveTab(tab); |
+ |
+ // Note the fact that this tab loaded. |
+ UMA_HISTOGRAM_ENUMERATION(kSessionRestoreTabActions, |
+ kSessionRestoreTabActionsUma_TabLoaded, |
+ kSessionRestoreTabActionsUma_Max); |
+ |
+ RemoveTab(is_deferred, tab); |
+ |
+ // Update UMA stats for foreground tabs. |
if (!got_first_foreground_load_ && render_widget_host && |
render_widget_host->GetView() && |
render_widget_host->GetView()->IsShowing()) { |
@@ -163,8 +259,25 @@ void SessionRestoreStatsCollector::Observe( |
void SessionRestoreStatsCollector::AddTabs( |
const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) { |
+ // Increment the session restore ID so to distinguish which tabs belong to |
+ // which conceptual session restore. |
+ ++session_restore_id_; |
+ |
+ // Each session restore makes a call to AddTabs with all of its tabs to be |
+ // restored all at once. Record statistics about the session restore as a |
+ // whole. |
+ UMA_HISTOGRAM_COUNTS_100(kSessionRestoreTabCount, tabs.size()); |
+ UMA_HISTOGRAM_ENUMERATION(kSessionRestoreActions, |
+ kSessionRestoreActionsUma_Initiated, |
+ kSessionRestoreActionsUma_Max); |
+ |
tab_count_ += tabs.size(); |
for (auto& tab : tabs) { |
+ // Record actions for each individual tab. |
+ UMA_HISTOGRAM_ENUMERATION(kSessionRestoreTabActions, |
+ kSessionRestoreTabActionsUma_TabCreated, |
+ kSessionRestoreTabActionsUma_Max); |
+ |
RegisterForNotifications(&tab.contents()->GetController()); |
if (tab.is_active()) { |
RenderWidgetHost* render_widget_host = |
@@ -174,32 +287,74 @@ void SessionRestoreStatsCollector::AddTabs( |
} |
} |
-void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) { |
+void SessionRestoreStatsCollector::DeferTabImpl( |
+ content::NavigationController* tab) { |
+ // We simply move this tab from the tracked set to the deferred set. |
+ ++tab_deferred_count_; |
+ auto tracked_it = tabs_tracked_.find(tab); |
+ int session_id = tracked_it->second; |
+ tabs_deferred_.insert(*tracked_it); |
+ tabs_tracked_.erase(tracked_it); |
+ |
+ // Only indicate that the session has had deferred tabs if this is the first |
+ // tab associated with that session being deferred. |
+ if (deferred_tabs_seen_.insert(session_id).second) { |
+ // It is assumed that tabs are being deferred due to memory pressure as this |
+ // is currently the only mechanism in which this can happen. |
+ UMA_HISTOGRAM_ENUMERATION(kSessionRestoreActions, |
+ kSessionRestoreActionsUma_DeferredTabs, |
+ kSessionRestoreActionsUma_Max); |
+ } |
+ |
+ UMA_HISTOGRAM_ENUMERATION(kSessionRestoreTabActions, |
+ kSessionRestoreTabActionsUma_TabLoadingDeferred, |
+ kSessionRestoreTabActionsUma_Max); |
+} |
+ |
+void SessionRestoreStatsCollector::RemoveTab(bool is_deferred, |
+ NavigationController* tab) { |
+ // Stop observing this tab. |
registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, |
content::Source<WebContents>(tab->GetWebContents())); |
registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP, |
content::Source<NavigationController>(tab)); |
registrar_.Remove(this, content::NOTIFICATION_LOAD_START, |
content::Source<NavigationController>(tab)); |
- if (render_widget_hosts_loading_.size() > max_parallel_tab_loads_) |
+ |
+ // Keep track of the maximum number of automatically loaded tabs that are |
+ // loading at the same time. |
+ if (!is_deferred && |
+ render_widget_hosts_loading_.size() > max_parallel_tab_loads_) { |
max_parallel_tab_loads_ = render_widget_hosts_loading_.size(); |
+ } |
+ |
RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab); |
render_widget_hosts_loading_.erase(render_widget_host); |
- tabs_tracked_.erase(tab); |
+ |
+ // Remove the tab from the appropriate list. |
+ if (is_deferred) { |
+ tabs_deferred_.erase(tab); |
+ } else { |
+ tabs_tracked_.erase(tab); |
+ } |
sky
2015/05/12 15:27:56
Would be nice to have some DCHECKs here that tab i
chrisha
2015/05/13 21:18:02
I moved to using a map that tracks the 'deferred'
|
// If there are no more tabs loading or being tracked, restore is done and |
// record the time. Note that we are not yet finished, as we might still be |
// waiting for our first paint, which can happen after all tabs are done |
// loading. |
- // TODO(georgesak): review behaviour of ForegroundTabFirstPaint. |
+ // NOTE: This is only concerned with tabs that are being actively tracked, |
+ // and not deferred tabs. Deferred tabs are still tracked, but don't |
+ // affect the AllTabsLoaded metric. |
+ // TODO(georgesak): Review behaviour of ForegroundTabFirstPaint. |
if (tabs_tracked_.empty() && render_widget_hosts_loading_.empty()) { |
sky
2015/05/12 15:27:56
Lets say tabs_tracked_ goes empty, adoesn't that m
chrisha
2015/05/13 21:18:02
Yes, that's true. This is no worse than before in
sky
2015/05/14 00:12:40
Not sure there. I think you're change makes it wor
chrisha
2015/05/14 21:27:02
The 'deferred state' of a tab doesn't change it's
sky
2015/05/14 21:51:50
Ok.
|
base::TimeDelta time_to_load = base::TimeTicks::Now() - restore_started_; |
UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.AllTabsLoaded", time_to_load, |
base::TimeDelta::FromMilliseconds(10), |
base::TimeDelta::FromSeconds(100), 100); |
// Record a time for the number of tabs, to help track down contention. |
+ int tabs_loaded = tab_count_ - tab_deferred_count_; |
std::string time_for_count = |
- base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_); |
+ base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tabs_loaded); |
base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet( |
time_for_count, base::TimeDelta::FromMilliseconds(10), |
base::TimeDelta::FromSeconds(100), 100, |
@@ -219,7 +374,7 @@ void SessionRestoreStatsCollector::RegisterForNotifications( |
content::Source<NavigationController>(tab)); |
registrar_.Add(this, content::NOTIFICATION_LOAD_START, |
content::Source<NavigationController>(tab)); |
- tabs_tracked_.insert(tab); |
+ tabs_tracked_.insert(std::make_pair(tab, session_restore_id_)); |
} |
RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost( |
@@ -234,6 +389,13 @@ RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost( |
return nullptr; |
} |
+bool SessionRestoreStatsCollector::IsDeferred( |
+ content::NavigationController* tab) { |
+ if (tabs_deferred_.count(tab) > 0) |
sky
2015/05/12 15:27:56
nit: return tabs_deffered_.count(tab) > 0
chrisha
2015/05/13 21:18:01
(I have a tendency to write code this way because
|
+ return true; |
+ return false; |
+} |
+ |
// static |
SessionRestoreStatsCollector* SessionRestoreStatsCollector::shared_collector_ = |
nullptr; |