summaryrefslogtreecommitdiffstats
path: root/chrome/browser/sessions/session_restore_stats_collector.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/sessions/session_restore_stats_collector.cc')
-rw-r--r--chrome/browser/sessions/session_restore_stats_collector.cc565
1 files changed, 403 insertions, 162 deletions
diff --git a/chrome/browser/sessions/session_restore_stats_collector.cc b/chrome/browser/sessions/session_restore_stats_collector.cc
index f892d1a..262500f 100644
--- a/chrome/browser/sessions/session_restore_stats_collector.cc
+++ b/chrome/browser/sessions/session_restore_stats_collector.cc
@@ -8,58 +8,137 @@
#include "base/metrics/histogram.h"
#include "base/strings/stringprintf.h"
+#include "base/time/default_tick_clock.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
+namespace {
+
using content::NavigationController;
using content::RenderWidgetHost;
+using content::Source;
using content::WebContents;
-// static
-void SessionRestoreStatsCollector::TrackTabs(
- const std::vector<SessionRestoreDelegate::RestoredTab>& tabs,
- const base::TimeTicks& restore_started) {
- if (!shared_collector_)
- shared_collector_ = new SessionRestoreStatsCollector(restore_started);
+// The enumeration values stored in the "SessionRestore.Actions" histogram.
+enum SessionRestoreActionsUma {
+ // Counts the total number of session restores that have occurred.
+ SESSION_RESTORE_ACTIONS_UMA_INITIATED = 0,
+ // Counts the number of session restores that have seen deferred tab loadings
+ // for whatever reason (almost certainly due to memory pressure).
+ SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS = 1,
+ // The size of this enum. Must be the last entry.
+ SESSION_RESTORE_ACTIONS_UMA_MAX,
+};
- shared_collector_->AddTabs(tabs);
+// Emits a SessionRestore.Actions UMA event.
+void EmitUmaSessionRestoreActionEvent(SessionRestoreActionsUma action) {
+ UMA_HISTOGRAM_ENUMERATION("SessionRestore.Actions", action,
+ SESSION_RESTORE_ACTIONS_UMA_MAX);
}
-// static
-void SessionRestoreStatsCollector::TrackActiveTabs(
- const std::vector<SessionRestoreDelegate::RestoredTab>& tabs,
- const base::TimeTicks& restore_started) {
- if (!shared_collector_)
- shared_collector_ = new SessionRestoreStatsCollector(restore_started);
+// The enumeration of values stored in the "SessionRestore.TabActions"
+// histogram.
+enum SessionRestoreTabActionsUma {
+ // Incremented for each tab created in a session restore.
+ SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED = 0,
+ // Incremented for each tab that session restore decides not to load.
+ SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED = 1,
+ // Incremented for each tab that is successfully loaded.
+ SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED = 2,
+ // Incremented for each session-restore-deferred tab that is subsequently
+ // loaded.
+ SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED = 3,
+ // The size of this enum. Must be the last entry.
+ SESSION_RESTORE_TAB_ACTIONS_UMA_MAX,
+};
- std::vector<SessionRestoreDelegate::RestoredTab> active_tabs;
- for (auto tab : tabs) {
- if (tab.is_active())
- active_tabs.push_back(tab);
- }
- shared_collector_->AddTabs(active_tabs);
+// Emits a SessionRestore.TabActions UMA event.
+void EmitUmaSessionRestoreTabActionEvent(SessionRestoreTabActionsUma action) {
+ UMA_HISTOGRAM_ENUMERATION("SessionRestore.TabActions", action,
+ SESSION_RESTORE_TAB_ACTIONS_UMA_MAX);
+}
+
+} // namespace
+
+SessionRestoreStatsCollector::TabLoaderStats::TabLoaderStats()
+ : tab_count(0u), tabs_loaded(0u), parallel_tab_loads(0u) {
+}
+
+SessionRestoreStatsCollector::TabState::TabState(
+ NavigationController* controller)
+ : controller(controller),
+ render_widget_host(nullptr),
+ is_deferred(false),
+ loading_state(TAB_IS_NOT_LOADING) {
}
SessionRestoreStatsCollector::SessionRestoreStatsCollector(
- const base::TimeTicks& restore_started)
- : got_first_foreground_load_(false),
+ const base::TimeTicks& restore_started,
+ scoped_ptr<StatsReportingDelegate> reporting_delegate)
+ : done_tracking_non_deferred_tabs_(false),
+ got_first_foreground_load_(false),
got_first_paint_(false),
restore_started_(restore_started),
- tab_count_(0),
- max_parallel_tab_loads_(0) {
+ waiting_for_load_tab_count_(0u),
+ loading_tab_count_(0u),
+ deferred_tab_count_(0u),
+ tick_clock_(new base::DefaultTickClock()),
+ reporting_delegate_(reporting_delegate.Pass()) {
this_retainer_ = this;
- registrar_.Add(
- this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
- content::NotificationService::AllSources());
}
SessionRestoreStatsCollector::~SessionRestoreStatsCollector() {
- DCHECK((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
- tabs_tracked_.empty() && render_widget_hosts_loading_.empty());
- DCHECK(shared_collector_ == this);
- shared_collector_ = nullptr;
+}
+
+void SessionRestoreStatsCollector::TrackTabs(
+ const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) {
+ DCHECK(!done_tracking_non_deferred_tabs_);
+
+ // If this is the first call to TrackTabs then start observing events.
+ if (tab_loader_stats_.tab_count == 0) {
+ registrar_.Add(
+ this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
+ content::NotificationService::AllSources());
+ }
+
+ tab_loader_stats_.tab_count += tabs.size();
+ waiting_for_load_tab_count_ += tabs.size();
+ for (const auto& tab : tabs) {
+ TabState* tab_state =
+ RegisterForNotifications(&tab.contents()->GetController());
+ // Active tabs have already started loading.
+ if (tab.is_active())
+ MarkTabAsLoading(tab_state);
+ }
+}
+
+void SessionRestoreStatsCollector::DeferTab(NavigationController* tab) {
+ TabState* tab_state = GetTabState(tab);
+
+ // If the tab is no longer being tracked it has already finished loading.
+ // This can occur if the user forces the tab to load before the entire session
+ // restore is over, and the TabLoader then decides it would defer loading of
+ // that tab.
+ if (!tab_state)
+ return;
+
+ // Mark this tab as deferred, if its still being tracked. A tab should not be
+ // marked as deferred twice.
+ DCHECK(!tab_state->is_deferred);
+ tab_state->is_deferred = true;
+ ++deferred_tab_count_;
+
+ // A tab that didn't start loading before it was deferred is not to be
+ // actively monitored for loading.
+ if (tab_state->loading_state == TAB_IS_NOT_LOADING) {
+ DCHECK_LT(0u, waiting_for_load_tab_count_);
+ if (--waiting_for_load_tab_count_ == 0)
+ ReleaseIfDoneTracking();
+ }
+
+ reporting_delegate_->ReportTabDeferred();
}
void SessionRestoreStatsCollector::Observe(
@@ -68,99 +147,112 @@ void SessionRestoreStatsCollector::Observe(
const content::NotificationDetails& details) {
switch (type) {
case content::NOTIFICATION_LOAD_START: {
- // Add this render_widget_host to the set of those we're waiting for
- // paints on. We want to only record stats for paints that occur after
- // a load has finished.
- NavigationController* tab =
- content::Source<NavigationController>(source).ptr();
- RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab);
- DCHECK(render_widget_host);
- render_widget_hosts_loading_.insert(render_widget_host);
+ // This occurs when a tab has started to load. This can be because of
+ // the tab loader (only for non-deferred tabs) or because the user clicked
+ // on the tab.
+ NavigationController* tab = Source<NavigationController>(source).ptr();
+ TabState* tab_state = GetTabState(tab);
+ MarkTabAsLoading(tab_state);
break;
}
case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: {
- WebContents* web_contents = content::Source<WebContents>(source).ptr();
- RemoveTab(&web_contents->GetController());
+ // This happens when a tab has been closed. A tab can be in any state
+ // when this occurs. Simply stop tracking the tab.
+ WebContents* web_contents = Source<WebContents>(source).ptr();
+ NavigationController* tab = &web_contents->GetController();
+ RemoveTab(tab);
break;
}
case content::NOTIFICATION_LOAD_STOP: {
- NavigationController* tab =
- content::Source<NavigationController>(source).ptr();
- RenderWidgetHost* render_widget_host = GetRenderWidgetHost(tab);
- render_widget_hosts_to_paint_.insert(render_widget_host);
- RemoveTab(tab);
- if (!got_first_foreground_load_ && render_widget_host &&
- render_widget_host->GetView() &&
- render_widget_host->GetView()->IsShowing()) {
+ // This occurs to loading tabs when they have finished loading. The tab
+ // may or may not already have painted at this point.
+
+ // Update the tab state and any global state as necessary.
+ NavigationController* tab = Source<NavigationController>(source).ptr();
+ TabState* tab_state = GetTabState(tab);
+ DCHECK(tab_state);
+ tab_state->loading_state = TAB_IS_LOADED;
+ DCHECK_LT(0u, loading_tab_count_);
+ --loading_tab_count_;
+ if (!tab_state->is_deferred) {
+ DCHECK_LT(0u, waiting_for_load_tab_count_);
+ --waiting_for_load_tab_count_;
+ }
+
+ if (tab_state->is_deferred) {
+ reporting_delegate_->ReportDeferredTabLoaded();
+ } else {
+ DCHECK(!done_tracking_non_deferred_tabs_);
+ ++tab_loader_stats_.tabs_loaded;
+ }
+
+ // Update statistics for foreground tabs.
+ base::TimeDelta time_to_load = tick_clock_->NowTicks() - restore_started_;
+ if (!got_first_foreground_load_ && tab_state->render_widget_host &&
+ tab_state->render_widget_host->GetView() &&
+ tab_state->render_widget_host->GetView()->IsShowing()) {
got_first_foreground_load_ = true;
- base::TimeDelta time_to_load =
- base::TimeTicks::Now() - restore_started_;
- UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded",
- 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.
- std::string time_for_count = base::StringPrintf(
- "SessionRestore.ForegroundTabFirstLoaded_%d", tab_count_);
- base::HistogramBase* counter_for_count =
- base::Histogram::FactoryTimeGet(
- time_for_count, base::TimeDelta::FromMilliseconds(10),
- base::TimeDelta::FromSeconds(100), 100,
- base::Histogram::kUmaTargetedHistogramFlag);
- counter_for_count->AddTime(time_to_load);
+ DCHECK(!done_tracking_non_deferred_tabs_);
+ tab_loader_stats_.foreground_tab_first_loaded = time_to_load;
}
+
+ // Update statistics for all tabs, if this wasn't a deferred tab. This is
+ // done here and not in ReleaseIfDoneTracking because it is possible to
+ // wait for a paint long after all loads have completed.
+ if (!done_tracking_non_deferred_tabs_ && !tab_state->is_deferred)
+ tab_loader_stats_.non_deferred_tabs_loaded = time_to_load;
+
+ // By default tabs transition to being tracked for paint events after the
+ // load event has been seen. However, if the first paint event has already
+ // been seen then this is not necessary and the tab can be removed.
+ if (got_first_paint_)
+ RemoveTab(tab);
+
break;
}
case content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE: {
+ // This notification is across all tabs in the browser so notifications
+ // will arrive for tabs that the collector is not explicitly tracking.
+
+ // Only process this event if first paint hasn't been seen and this is a
+ // paint of a visible tab.
RenderWidgetHost* render_widget_host =
- content::Source<RenderWidgetHost>(source).ptr();
+ Source<RenderWidgetHost>(source).ptr();
if (!got_first_paint_ && render_widget_host->GetView() &&
render_widget_host->GetView()->IsShowing()) {
- if (render_widget_hosts_to_paint_.find(render_widget_host) !=
- render_widget_hosts_to_paint_.end()) {
- // Got a paint for one of our renderers, so record time.
- got_first_paint_ = true;
- base::TimeDelta time_to_paint =
- base::TimeTicks::Now() - restore_started_;
- // TODO(danduong): to remove this with 467680, to make sure we
- // don't forget to clean this up.
- UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint",
- time_to_paint,
- base::TimeDelta::FromMilliseconds(10),
- base::TimeDelta::FromSeconds(100), 100);
- // Record a time for the number of tabs, to help track down
- // contention.
- std::string time_for_count = base::StringPrintf(
- "SessionRestore.ForegroundTabFirstPaint_%d", tab_count_);
- base::HistogramBase* counter_for_count =
- base::Histogram::FactoryTimeGet(
- time_for_count, base::TimeDelta::FromMilliseconds(10),
- base::TimeDelta::FromSeconds(100), 100,
- base::Histogram::kUmaTargetedHistogramFlag);
- counter_for_count->AddTime(time_to_paint);
- UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint2",
- time_to_paint,
- base::TimeDelta::FromMilliseconds(100),
- base::TimeDelta::FromMinutes(16), 50);
- // Record a time for the number of tabs, to help track down
- // contention.
- std::string time_for_count2 = base::StringPrintf(
- "SessionRestore.ForegroundTabFirstPaint2_%d", tab_count_);
- base::HistogramBase* counter_for_count2 =
- base::Histogram::FactoryTimeGet(
- time_for_count2, base::TimeDelta::FromMilliseconds(100),
- base::TimeDelta::FromMinutes(16), 50,
- base::Histogram::kUmaTargetedHistogramFlag);
- counter_for_count2->AddTime(time_to_paint);
- } else if (render_widget_hosts_loading_.find(render_widget_host) ==
- render_widget_hosts_loading_.end()) {
- // If this is a host for a tab we're not loading some other tab
- // has rendered and there's no point tracking the time. This could
+ got_first_paint_ = true;
+ TabState* tab_state = GetTabState(render_widget_host);
+ if (tab_state) {
+ // This is a paint for a tab that is explicitly being tracked so
+ // update the statistics. Otherwise the host is for a tab that's not
+ // being tracked thus some other tab has visibility and has rendered
+ // and there's no point in tracking the time to first paint. This can
// happen because the user opened a different tab or restored tabs
- // to an already existing browser and an existing tab painted.
- got_first_paint_ = true;
+ // to an already existing browser and an existing tab was in the
+ // foreground.
+ base::TimeDelta time_to_paint =
+ tick_clock_->NowTicks() - restore_started_;
+ DCHECK(!done_tracking_non_deferred_tabs_);
+ tab_loader_stats_.foreground_tab_first_paint = time_to_paint;
}
+
+ // Once first paint has been observed the entire to-paint tracking
+ // mechanism is no longer needed.
+ registrar_.Remove(
+ this,
+ content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
+ content::NotificationService::AllSources());
+
+ // Remove any tabs that have loaded. These were only being kept around
+ // while waiting for a paint event.
+ std::vector<NavigationController*> loaded_tabs;
+ for (auto& map_entry : tabs_tracked_) {
+ TabState& tab_state = map_entry.second;
+ if (tab_state.loading_state == TAB_IS_LOADED)
+ loaded_tabs.push_back(tab_state.controller);
+ }
+ for (auto& tab : loaded_tabs)
+ RemoveTab(tab);
}
break;
}
@@ -169,72 +261,69 @@ void SessionRestoreStatsCollector::Observe(
break;
}
- // Check if we are done and if so, reset |this_retainer_| as the collector no
- // longer needs to stay alive.
- if ((got_first_paint_ || render_widget_hosts_to_paint_.empty()) &&
- tabs_tracked_.empty() && render_widget_hosts_loading_.empty())
- this_retainer_ = nullptr;
-}
-
-void SessionRestoreStatsCollector::AddTabs(
- const std::vector<SessionRestoreDelegate::RestoredTab>& tabs) {
- tab_count_ += tabs.size();
- for (auto& tab : tabs) {
- RegisterForNotifications(&tab.contents()->GetController());
- if (tab.is_active()) {
- RenderWidgetHost* render_widget_host =
- GetRenderWidgetHost(&tab.contents()->GetController());
- render_widget_hosts_loading_.insert(render_widget_host);
- }
- }
+ ReleaseIfDoneTracking();
}
void SessionRestoreStatsCollector::RemoveTab(NavigationController* tab) {
+ // Stop observing this tab.
registrar_.Remove(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::Source<WebContents>(tab->GetWebContents()));
+ Source<WebContents>(tab->GetWebContents()));
registrar_.Remove(this, content::NOTIFICATION_LOAD_STOP,
- content::Source<NavigationController>(tab));
+ Source<NavigationController>(tab));
registrar_.Remove(this, content::NOTIFICATION_LOAD_START,
- content::Source<NavigationController>(tab));
- if (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);
-
- // 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.
- if (tabs_tracked_.empty() && render_widget_hosts_loading_.empty()) {
- 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.
- std::string time_for_count =
- base::StringPrintf("SessionRestore.AllTabsLoaded_%d", tab_count_);
- base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
- time_for_count, base::TimeDelta::FromMilliseconds(10),
- base::TimeDelta::FromSeconds(100), 100,
- base::Histogram::kUmaTargetedHistogramFlag);
- counter_for_count->AddTime(time_to_load);
+ Source<NavigationController>(tab));
- UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
- max_parallel_tab_loads_);
+ auto tab_it = tabs_tracked_.find(tab);
+ DCHECK(tab_it != tabs_tracked_.end());
+ TabState& tab_state = tab_it->second;
+
+ // If this tab was waiting for a NOTIFICATION_LOAD_STOP event then update
+ // the loading counts.
+ if (tab_state.loading_state == TAB_IS_LOADING) {
+ DCHECK_LT(0u, loading_tab_count_);
+ --loading_tab_count_;
+ }
+
+ // Only non-deferred not-loading/not-loaded tabs are waiting to be loaded.
+ if (tab_state.loading_state != TAB_IS_LOADED && !tab_state.is_deferred) {
+ DCHECK_LT(0u, waiting_for_load_tab_count_);
+ // It's possible for waiting_for_load_tab_count_ to reach zero here. This
+ // function is only called from 'Observe', so the transition will be
+ // noticed there.
+ --waiting_for_load_tab_count_;
+ }
+
+ if (tab_state.is_deferred)
+ --deferred_tab_count_;
+
+ // Remove the tab from the |tracked_tabs_| map.
+ tabs_tracked_.erase(tab_it);
+
+ // It is possible for all restored contents to be destroyed or forcibly
+ // renavigated before a first paint has arrived. This can be detected by
+ // tabs_tracked_ containing only deferred tabs. At this point the paint
+ // mechanism can be disabled and stats collection will stop.
+ if (tabs_tracked_.size() == deferred_tab_count_ && !got_first_paint_) {
+ got_first_paint_ = true;
+ registrar_.Remove(
+ this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
+ content::NotificationService::AllSources());
}
}
-void SessionRestoreStatsCollector::RegisterForNotifications(
+SessionRestoreStatsCollector::TabState*
+SessionRestoreStatsCollector::RegisterForNotifications(
NavigationController* tab) {
registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
- content::Source<WebContents>(tab->GetWebContents()));
+ Source<WebContents>(tab->GetWebContents()));
registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
- content::Source<NavigationController>(tab));
+ Source<NavigationController>(tab));
registrar_.Add(this, content::NOTIFICATION_LOAD_START,
- content::Source<NavigationController>(tab));
- tabs_tracked_.insert(tab);
+ Source<NavigationController>(tab));
+ auto result = tabs_tracked_.insert(std::make_pair(tab, TabState(tab)));
+ DCHECK(result.second);
+ TabState* tab_state = &result.first->second;
+ return tab_state;
}
RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost(
@@ -249,6 +338,158 @@ RenderWidgetHost* SessionRestoreStatsCollector::GetRenderWidgetHost(
return nullptr;
}
-// static
-SessionRestoreStatsCollector* SessionRestoreStatsCollector::shared_collector_ =
- nullptr;
+SessionRestoreStatsCollector::TabState*
+SessionRestoreStatsCollector::GetTabState(NavigationController* tab) {
+ // This lookup can fail because DeferTab calls can arrive for tabs that have
+ // already loaded (user forced) and are no longer tracked.
+ auto it = tabs_tracked_.find(tab);
+ if (it == tabs_tracked_.end())
+ return nullptr;
+ return &it->second;
+}
+
+SessionRestoreStatsCollector::TabState*
+SessionRestoreStatsCollector::GetTabState(RenderWidgetHost* tab) {
+ for (auto& pair : tabs_tracked_) {
+ if (pair.second.render_widget_host == tab)
+ return &pair.second;
+ }
+ // It's possible for this lookup to fail as paint events can be received for
+ // tabs that aren't being tracked.
+ return nullptr;
+}
+
+void SessionRestoreStatsCollector::MarkTabAsLoading(TabState* tab_state) {
+ // If the tab has already started or finished loading then a user navigation
+ // has caused the tab to be forcibly reloaded. This tab can be removed from
+ // observation.
+ if (tab_state->loading_state == TAB_IS_LOADED) {
+ RemoveTab(tab_state->controller);
+ return;
+ }
+
+ DCHECK_EQ(TAB_IS_NOT_LOADING, tab_state->loading_state);
+ if (tab_state->loading_state != TAB_IS_NOT_LOADING)
+ return;
+ tab_state->loading_state = TAB_IS_LOADING;
+ ++loading_tab_count_;
+
+ if (!done_tracking_non_deferred_tabs_) {
+ tab_loader_stats_.parallel_tab_loads =
+ std::max(tab_loader_stats_.parallel_tab_loads, loading_tab_count_);
+ }
+
+ // Get the RenderWidgetHost for the tab and add it to the secondary index.
+ RenderWidgetHost* render_widget_host =
+ GetRenderWidgetHost(tab_state->controller);
+ DCHECK(render_widget_host);
+ tab_state->render_widget_host = render_widget_host;
+}
+
+void SessionRestoreStatsCollector::ReleaseIfDoneTracking() {
+ // If non-deferred tabs are no longer being tracked then report tab loader
+ // statistics.
+ if (!done_tracking_non_deferred_tabs_ && got_first_paint_ &&
+ waiting_for_load_tab_count_ == 0) {
+ done_tracking_non_deferred_tabs_ = true;
+ reporting_delegate_->ReportTabLoaderStats(tab_loader_stats_);
+ }
+
+ // If tracking is completely finished then emit collected metrics and destroy
+ // this stats collector.
+ if (done_tracking_non_deferred_tabs_ && tabs_tracked_.empty())
+ this_retainer_ = nullptr;
+}
+
+SessionRestoreStatsCollector::UmaStatsReportingDelegate::
+ UmaStatsReportingDelegate()
+ : got_report_tab_deferred_(false) {
+}
+
+void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
+ ReportTabLoaderStats(const TabLoaderStats& tab_loader_stats) {
+ UMA_HISTOGRAM_COUNTS_100("SessionRestore.TabCount",
+ tab_loader_stats.tab_count);
+
+ EmitUmaSessionRestoreActionEvent(SESSION_RESTORE_ACTIONS_UMA_INITIATED);
+
+ for (size_t i = 0; i < tab_loader_stats.tab_count; ++i) {
+ EmitUmaSessionRestoreTabActionEvent(
+ SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_CREATED);
+ }
+
+ for (size_t i = 0; i < tab_loader_stats.tabs_loaded; ++i) {
+ EmitUmaSessionRestoreTabActionEvent(
+ SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADED);
+ }
+
+ if (!tab_loader_stats.foreground_tab_first_loaded.is_zero()) {
+ UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstLoaded",
+ tab_loader_stats.foreground_tab_first_loaded,
+ base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromSeconds(100), 100);
+
+ // Record a time for the number of tabs, to help track down contention.
+ std::string time_for_count = base::StringPrintf(
+ "SessionRestore.ForegroundTabFirstLoaded_%u",
+ static_cast<unsigned int>(tab_loader_stats.tab_count));
+ base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
+ time_for_count, base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromSeconds(100), 100,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ counter_for_count->AddTime(tab_loader_stats.foreground_tab_first_loaded);
+ }
+
+ if (!tab_loader_stats.foreground_tab_first_paint.is_zero()) {
+ UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.ForegroundTabFirstPaint3",
+ tab_loader_stats.foreground_tab_first_paint,
+ base::TimeDelta::FromMilliseconds(100),
+ base::TimeDelta::FromMinutes(16), 50);
+
+ std::string time_for_count = base::StringPrintf(
+ "SessionRestore.ForegroundTabFirstPaint3_%u",
+ static_cast<unsigned int>(tab_loader_stats.tab_count));
+ base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
+ time_for_count, base::TimeDelta::FromMilliseconds(100),
+ base::TimeDelta::FromMinutes(16), 50,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ counter_for_count->AddTime(tab_loader_stats.foreground_tab_first_paint);
+ }
+
+ if (!tab_loader_stats.non_deferred_tabs_loaded.is_zero()) {
+ UMA_HISTOGRAM_CUSTOM_TIMES("SessionRestore.AllTabsLoaded",
+ tab_loader_stats.non_deferred_tabs_loaded,
+ base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromSeconds(100), 100);
+
+ // Record a time for the number of tabs, to help track down contention.
+ std::string time_for_count = base::StringPrintf(
+ "SessionRestore.AllTabsLoaded_%u",
+ static_cast<unsigned int>(tab_loader_stats.tab_count));
+ base::HistogramBase* counter_for_count = base::Histogram::FactoryTimeGet(
+ time_for_count, base::TimeDelta::FromMilliseconds(10),
+ base::TimeDelta::FromSeconds(100), 100,
+ base::Histogram::kUmaTargetedHistogramFlag);
+ counter_for_count->AddTime(tab_loader_stats.non_deferred_tabs_loaded);
+ }
+
+ UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
+ tab_loader_stats.parallel_tab_loads);
+}
+
+void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
+ ReportTabDeferred() {
+ if (!got_report_tab_deferred_) {
+ got_report_tab_deferred_ = true;
+ EmitUmaSessionRestoreActionEvent(SESSION_RESTORE_ACTIONS_UMA_DEFERRED_TABS);
+ }
+
+ EmitUmaSessionRestoreTabActionEvent(
+ SESSION_RESTORE_TAB_ACTIONS_UMA_TAB_LOADING_DEFERRED);
+}
+
+void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
+ ReportDeferredTabLoaded() {
+ EmitUmaSessionRestoreTabActionEvent(
+ SESSION_RESTORE_TAB_ACTIONS_UMA_DEFERRED_TAB_LOADED);
+}