Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ | 5 #ifndef CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |
| 6 #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ | 6 #define CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |
| 7 | 7 |
| 8 #include <set> | 8 #include <map> |
| 9 | 9 |
| 10 #include "base/callback_list.h" | 10 #include "base/callback_list.h" |
| 11 #include "chrome/browser/sessions/session_restore.h" | 11 #include "chrome/browser/sessions/session_restore.h" |
| 12 #include "chrome/browser/sessions/session_restore_delegate.h" | 12 #include "chrome/browser/sessions/session_restore_delegate.h" |
| 13 #include "content/public/browser/notification_observer.h" | 13 #include "content/public/browser/notification_observer.h" |
| 14 #include "content/public/browser/notification_registrar.h" | 14 #include "content/public/browser/notification_registrar.h" |
| 15 #include "content/public/browser/render_widget_host.h" | 15 #include "content/public/browser/render_widget_host.h" |
| 16 | 16 |
| 17 namespace content { | 17 namespace content { |
| 18 class NavigationController; | 18 class NavigationController; |
| 19 } | 19 } |
| 20 | 20 |
| 21 // SessionRestoreStatsCollector observes SessionRestore events ands records UMA | 21 // SessionRestoreStatsCollector observes SessionRestore events ands records UMA |
| 22 // accordingly. | 22 // accordingly. |
| 23 // | |
| 24 // A SessionRestoreStatsCollector is tied to an instance of a session restore, | |
| 25 // currently being instantianted and owned by the TabLoader. It has two main | |
| 26 // phases to its life: | |
| 27 // | |
| 28 // 1. The session restore is active and ongoing (the TabLoader is still | |
| 29 // scheduling tabs for loading). This phases ends when there are no | |
| 30 // non-deferred tabs left to be loaded. During this phases statistics are | |
| 31 // gathered in a structure before being emitted as UMA metrics at the end of | |
| 32 // this phase. At this point the TabLoader ceases to exist and destroys it's | |
| 33 // reference to the SessionRestoreStatsCollector. | |
| 34 // 2. If any tabs have been deferred the SessionRestoreStatsCollector continues | |
| 35 // tracking deferred tabs. This continues to observe the tabs to see which | |
| 36 // (if any) of the deferred tabs are subsequently forced to be loaded by the | |
| 37 // user. Since such tabs may exist until the end of the browsers life the | |
| 38 // statistics are emitted immediately, or risk being lost entirely. When | |
| 39 // there are no longer deferred tabs to track the | |
| 40 // SessionRestoreStatsCollector will destroy itself. | |
| 41 // | |
| 42 // TODO(chrisha): Many of these metrics don't make sense to collect in the | |
| 43 // presence of an unavailable network, or when tabs are closed during loading. | |
| 44 // Rethink the collection in these cases. | |
| 23 class SessionRestoreStatsCollector | 45 class SessionRestoreStatsCollector |
| 24 : public content::NotificationObserver, | 46 : public content::NotificationObserver, |
| 25 public base::RefCounted<SessionRestoreStatsCollector> { | 47 public base::RefCounted<SessionRestoreStatsCollector> { |
| 26 public: | 48 public: |
| 27 // Called to start tracking tabs. If a restore is already occuring, the tabs | 49 // Houses all of the statistics gathered by the SessionRestoreStatsCollector |
| 28 // are added to the existing list of tracked tabs. | 50 // while the underlying TabLoader is active. These statistics are all reported |
| 29 static void TrackTabs( | 51 // at once via the reporting delegate. |
| 30 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, | 52 struct TabLoaderStats { |
| 31 const base::TimeTicks& restore_started); | 53 // Constructor that initializes everything to zero. |
| 32 | 54 TabLoaderStats(); |
| 33 // Called to start tracking only active tabs. If a restore is already | 55 |
| 34 // occuring, the tabs are added to the existing list of tracked tabs. | 56 // The number of tabs involved all overlapping session restores being |
|
sky
2015/06/03 22:00:08
'in' all?
chrisha
2015/06/04 14:04:47
Done.
| |
| 35 static void TrackActiveTabs( | 57 // tracked by this SessionRestoreStatsCollector. This corresponds to the |
| 36 const std::vector<SessionRestoreDelegate::RestoredTab>& tabs, | 58 // "SessionRestore.TabCount" metric and one bucket of the |
| 37 const base::TimeTicks& restore_started); | 59 // "SessionRestore.TabActions" histogram. |
| 60 size_t tab_count; | |
| 61 | |
| 62 // The number of tabs loaded automatically because they are active, and | |
| 63 // explicitly caused to be loaded by the TabLoader. This corresponds to one | |
| 64 // bucket of the "SessionRestore.TabActions" histogram. | |
| 65 size_t tabs_loaded; | |
| 66 | |
| 67 // The time elapsed between |restore_started| and reception of the first | |
| 68 // NOTIFICATION_LOAD_STOP event for any of the active tabs involved in the | |
| 69 // session restore. If this is zero it is because it has not been | |
| 70 // recorded (all visible tabs were closed before they finished loading, or | |
| 71 // the user switched to an already loaded tab before a visible session | |
| 72 // restore tab finished loading). Corresponds to | |
| 73 // "SessionRestore.ForegroundTabFirstLoaded" and its _XX variants. | |
| 74 base::TimeDelta foreground_tab_first_loaded; | |
| 75 | |
| 76 // The time elapsed between |restore_started| and reception of the first | |
| 77 // NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE event for any of | |
| 78 // the tabs involved in the session restore. If this is zero it is because | |
| 79 // it has not been recorded (all visible tabs were closed or switched away | |
| 80 // from before they were painted). Corresponds to | |
| 81 // "SessionRestore.ForegroundTabFirstPaint3" and its _XX variants. | |
| 82 base::TimeDelta foreground_tab_first_paint; | |
| 83 | |
| 84 // The time taken for all non-deferred tabs to be loaded. This corresponds | |
| 85 // to the "SessionRestore.AllTabsLoaded" metric and its _XX variants | |
| 86 // (vaguely named for historical reasons, as it predates the concept of | |
| 87 // deferred tabs). | |
| 88 base::TimeDelta non_deferred_tabs_loaded; | |
| 89 | |
| 90 // The maximum number of tabs loading in parallel. This corresponds to the | |
| 91 // "SessionRestore.ParallelTabLoads" metric. | |
| 92 size_t parallel_tab_loads; | |
| 93 }; | |
| 94 | |
| 95 // The StatsReportingDelegate is responsible for delivering statistics | |
| 96 // reported by the SessionRestoreStatsCollector. | |
| 97 class StatsReportingDelegate; | |
| 98 | |
| 99 // An implementation of StatsReportingDelegate for reporting via UMA. | |
| 100 class UmaStatsReportingDelegate; | |
| 101 | |
| 102 // Constructs a SessionRestoreStatsCollector. | |
| 103 SessionRestoreStatsCollector( | |
| 104 const base::TimeTicks& restore_started, | |
| 105 scoped_refptr<StatsReportingDelegate> reporting_delegate); | |
| 106 | |
| 107 // Adds new tabs to the list of tracked tabs. | |
| 108 void TrackTabs(const std::vector<SessionRestoreDelegate::RestoredTab>& tabs); | |
| 109 | |
| 110 // Called to indicate that the loading of a tab has been deferred by session | |
| 111 // restore. | |
| 112 void DeferTab(content::NavigationController* tab); | |
| 113 | |
| 114 // Exposed for unittesting. | |
| 115 const TabLoaderStats& tab_loader_stats() const { return tab_loader_stats_; } | |
| 38 | 116 |
| 39 private: | 117 private: |
| 40 friend class base::RefCounted<SessionRestoreStatsCollector>; | 118 friend class base::RefCounted<SessionRestoreStatsCollector>; |
| 41 | 119 |
| 42 using RenderWidgetHostSet = std::set<content::RenderWidgetHost*>; | 120 // Indicates whether the loading state of a tab. |
| 43 | 121 enum TabLoadingState { |
| 44 explicit SessionRestoreStatsCollector(const base::TimeTicks& restore_started); | 122 TAB_IS_NOT_LOADING, |
| 123 TAB_IS_LOADING, | |
| 124 TAB_IS_LOADED | |
| 125 }; | |
| 126 | |
| 127 // State that is tracked for a tab while it is being observed. | |
| 128 struct TabState { | |
| 129 explicit TabState(content::NavigationController* controller); | |
| 130 | |
| 131 // The NavigationController associated with the tab. This is the primary | |
| 132 // index for it and is never null. | |
| 133 content::NavigationController* controller; | |
| 134 | |
| 135 // The RenderWidgetHost associated with the tab. This is the secondary | |
| 136 // index and starts out being null. If it is not null it is because the tab | |
| 137 // is actively loading or waiting to be painted. | |
| 138 content::RenderWidgetHost* render_widget_host; | |
| 139 | |
| 140 // Set to true if the tab has been deferred by the TabLoader. | |
| 141 bool is_deferred; | |
| 142 | |
| 143 // The current loading state of the tab. | |
| 144 TabLoadingState loading_state; | |
| 145 }; | |
| 146 | |
| 147 // Maps a NavigationController to its state. This is the primary map and | |
| 148 // physically houses the state. | |
| 149 using NavigationControllerMap = std::map<content::NavigationController*, | |
| 150 TabState>; | |
| 151 | |
| 45 ~SessionRestoreStatsCollector() override; | 152 ~SessionRestoreStatsCollector() override; |
| 46 | 153 |
| 47 // NotificationObserver method. | 154 // NotificationObserver method. This is the workhorse of the class and drives |
| 155 // all state transitions. | |
| 48 void Observe(int type, | 156 void Observe(int type, |
| 49 const content::NotificationSource& source, | 157 const content::NotificationSource& source, |
| 50 const content::NotificationDetails& details) override; | 158 const content::NotificationDetails& details) override; |
| 51 | 159 |
| 52 // Adds new tabs to the list of tracked tabs. | 160 // Called when a tab is no longer tracked. This is called by the 'Observe' |
| 53 void AddTabs(const std::vector<SessionRestoreDelegate::RestoredTab>& tabs); | 161 // notification callback. Takes care of unregistering all observers and |
| 54 | 162 // removing the tab from all internal data structures. |
| 55 // Called when a tab is no longer tracked. | |
| 56 void RemoveTab(content::NavigationController* tab); | 163 void RemoveTab(content::NavigationController* tab); |
| 57 | 164 |
| 58 // Registers for relevant notifications for a tab. | 165 // Registers for relevant notifications for a tab and inserts the tab into |
| 59 void RegisterForNotifications(content::NavigationController* tab); | 166 // to tabs_tracked_ map. Return a pointer to the newly created TabState. |
| 167 TabState* RegisterForNotifications(content::NavigationController* tab); | |
| 60 | 168 |
| 61 // Returns the RenderWidgetHost of a tab. | 169 // Returns the RenderWidgetHost of a tab. |
| 62 content::RenderWidgetHost* GetRenderWidgetHost( | 170 content::RenderWidgetHost* GetRenderWidgetHost( |
| 63 content::NavigationController* tab); | 171 content::NavigationController* tab); |
| 64 | 172 |
| 65 // Have we recorded the times for a foreground tab load? | 173 // Returns the tab state, nullptr if not found. |
| 174 TabState* GetTabState(content::NavigationController* tab); | |
| 175 TabState* GetTabState(content::RenderWidgetHost* tab); | |
| 176 | |
| 177 // Marks a tab as loading. | |
| 178 void MarkTabAsLoading(TabState* tab_state); | |
| 179 | |
| 180 // Returns true if done tracking non-deferred tabs. When this returns true | |
| 181 // the TabLoader will have finished its work and aggregate statistics will be | |
| 182 // emitted via Record | |
| 183 bool DoneTrackingNonDeferredTabs() const; | |
| 184 | |
| 185 // Returns true when no longer tracking any tabs. When this returns true the | |
| 186 // collector will destory itself. Called from Observe. | |
| 187 bool DoneTracking() const; | |
| 188 | |
| 189 // Has DoneTrackingNonDeferredTabs returned true? | |
| 190 bool got_done_tracking_non_deferred_tabs_; | |
| 191 | |
| 192 // Has the time for foreground tab load been recorded? | |
| 66 bool got_first_foreground_load_; | 193 bool got_first_foreground_load_; |
| 67 | 194 |
| 68 // Have we recorded the times for a foreground tab paint? | 195 // Has the time for foreground tab paint been recorded? |
| 69 bool got_first_paint_; | 196 bool got_first_paint_; |
| 70 | 197 |
| 71 // The time the restore process started. | 198 // The time the restore process started. |
| 72 base::TimeTicks restore_started_; | 199 const base::TimeTicks restore_started_; |
| 73 | 200 |
| 74 // The renderers we have started loading into. | 201 // List of tracked tabs, mapped to their TabState. |
| 75 RenderWidgetHostSet render_widget_hosts_loading_; | 202 NavigationControllerMap tabs_tracked_; |
| 76 | 203 |
| 77 // The renderers we have loaded and are waiting on to paint. | 204 // Counts the number of non-deferred tabs that the |
| 78 RenderWidgetHostSet render_widget_hosts_to_paint_; | 205 // SessionRestoreStatsCollector is waiting to see load. |
| 79 | 206 size_t waiting_for_load_tab_count_; |
| 80 // List of tracked tabs. | 207 |
| 81 std::set<content::NavigationController*> tabs_tracked_; | 208 // Counts the current number of actively loading tabs. |
| 82 | 209 size_t loading_tab_count_; |
| 83 // The number of tabs that have been restored. | |
| 84 int tab_count_; | |
| 85 | |
| 86 // Max number of tabs that were loaded in parallel (for metrics). | |
| 87 size_t max_parallel_tab_loads_; | |
| 88 | 210 |
| 89 // Notification registrar. | 211 // Notification registrar. |
| 90 content::NotificationRegistrar registrar_; | 212 content::NotificationRegistrar registrar_; |
| 91 | 213 |
| 92 // To keep the collector alive as long as needed. | 214 // Statistics gathered regarding the TabLoader. |
| 215 TabLoaderStats tab_loader_stats_; | |
| 216 | |
| 217 // The reporting delegate used to report gathered statistics. | |
| 218 scoped_refptr<StatsReportingDelegate> reporting_delegate_; | |
| 219 | |
| 220 // For keeping SessionRestoreStatsCollector alive while it is still working | |
| 221 // even if no TabLoader references it. The object only lives on if it still | |
| 222 // has deferred tabs remaining from an interrupted session restore. | |
| 93 scoped_refptr<SessionRestoreStatsCollector> this_retainer_; | 223 scoped_refptr<SessionRestoreStatsCollector> this_retainer_; |
| 94 | 224 |
| 95 // The shared SessionRestoreNotifier instance for all SessionRestores running | |
| 96 // at this time. | |
| 97 static SessionRestoreStatsCollector* shared_collector_; | |
| 98 | |
| 99 DISALLOW_COPY_AND_ASSIGN(SessionRestoreStatsCollector); | 225 DISALLOW_COPY_AND_ASSIGN(SessionRestoreStatsCollector); |
| 100 }; | 226 }; |
| 101 | 227 |
| 228 // An abstract reporting delegate is used as a testing seam. | |
| 229 class SessionRestoreStatsCollector::StatsReportingDelegate | |
| 230 : public base::RefCounted<StatsReportingDelegate> { | |
|
sky
2015/06/03 22:00:08
Do you really need this ref counted?
chrisha
2015/06/04 14:04:47
There's a lifetime management issue. Three options
sky
2015/06/04 19:38:02
2 sgtm
| |
| 231 public: | |
| 232 StatsReportingDelegate() { } | |
| 233 | |
| 234 // Called when TabLoader has completed its work. | |
| 235 virtual void ReportTabLoaderStats( | |
| 236 const TabLoaderStats& tab_loader_stats) = 0; | |
| 237 // Called when a tab has been deferred. | |
| 238 virtual void ReportTabDeferred() = 0; | |
| 239 // Called when a deferred tab has been loaded. | |
| 240 virtual void ReportDeferredTabLoaded() = 0; | |
| 241 | |
| 242 private: | |
| 243 friend class base::RefCounted<StatsReportingDelegate>; | |
| 244 | |
| 245 DISALLOW_COPY_AND_ASSIGN(StatsReportingDelegate); | |
| 246 }; | |
| 247 | |
| 248 // The default reporting delegate, which reports statistics via UMA. | |
| 249 class SessionRestoreStatsCollector::UmaStatsReportingDelegate | |
| 250 : public StatsReportingDelegate { | |
| 251 public: | |
| 252 UmaStatsReportingDelegate(); | |
| 253 | |
| 254 // StatsReportingDelegate implementation. | |
| 255 void ReportTabLoaderStats( | |
| 256 const TabLoaderStats& tab_loader_stats) override; | |
| 257 void ReportTabDeferred() override; | |
| 258 void ReportDeferredTabLoaded() override; | |
| 259 | |
| 260 private: | |
| 261 // Has ReportTabDeferred been called? | |
| 262 bool got_report_tab_deferred_; | |
| 263 | |
| 264 DISALLOW_COPY_AND_ASSIGN(UmaStatsReportingDelegate); | |
| 265 }; | |
| 266 | |
| 102 #endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ | 267 #endif // CHROME_BROWSER_SESSIONS_SESSION_RESTORE_STATS_COLLECTOR_H_ |
| OLD | NEW |