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 f892d1ad107b4bdbb27b03cb5d161c475de593a2..262500f5bb68f8d2152b00ac21dea7b6199d1142 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); |
+} |