page_load_tracker_decorator.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef COMPONENTS_PERFORMANCE_MANAGER_DECORATORS_PAGE_LOAD_TRACKER_DECORATOR_H_
  5. #define COMPONENTS_PERFORMANCE_MANAGER_DECORATORS_PAGE_LOAD_TRACKER_DECORATOR_H_
  6. #include "base/time/time.h"
  7. #include "base/timer/timer.h"
  8. #include "components/performance_manager/public/graph/frame_node.h"
  9. #include "components/performance_manager/public/graph/graph.h"
  10. #include "components/performance_manager/public/graph/node_data_describer.h"
  11. #include "components/performance_manager/public/graph/page_node.h"
  12. #include "components/performance_manager/public/graph/process_node.h"
  13. namespace performance_manager {
  14. class FrameNodeImpl;
  15. class PageNodeImpl;
  16. class ProcessNodeImpl;
  17. // The PageLoadTracker decorator is responsible for determining when a page is
  18. // loading. A page starts loading when incoming data starts arriving for a
  19. // top-level load to a different document. It stops loading when it reaches an
  20. // "almost idle" state, based on CPU and network quiescence, or after an
  21. // absolute timeout. This state is then updated on PageNodes in a graph.
  22. class PageLoadTrackerDecorator : public FrameNode::ObserverDefaultImpl,
  23. public GraphOwnedDefaultImpl,
  24. public NodeDataDescriberDefaultImpl,
  25. public ProcessNode::ObserverDefaultImpl {
  26. public:
  27. class Data;
  28. PageLoadTrackerDecorator();
  29. PageLoadTrackerDecorator(const PageLoadTrackerDecorator&) = delete;
  30. PageLoadTrackerDecorator& operator=(const PageLoadTrackerDecorator&) = delete;
  31. ~PageLoadTrackerDecorator() override;
  32. // FrameNodeObserver implementation:
  33. void OnNetworkAlmostIdleChanged(const FrameNode* frame_node) override;
  34. // GraphOwned implementation:
  35. void OnPassedToGraph(Graph* graph) override;
  36. void OnTakenFromGraph(Graph* graph) override;
  37. // NodeDataDescriber implementation:
  38. base::Value DescribePageNodeData(const PageNode* node) const override;
  39. // ProcessNodeObserver implementation:
  40. void OnMainThreadTaskLoadIsLow(const ProcessNode* process_node) override;
  41. // Invoked by PageLoadTrackerDecoratorHelper when corresponding
  42. // WebContentsObserver methods are invoked, and the WebContents is loading to
  43. // a different document.
  44. static void DidStartLoading(PageNodeImpl* page_node);
  45. static void PrimaryPageChanged(PageNodeImpl* page_node);
  46. static void DidStopLoading(PageNodeImpl* page_node);
  47. protected:
  48. friend class PageLoadTrackerDecoratorTest;
  49. // The amount of time after which a page transitions from
  50. // kWaitingForNavigation to kWaitingForNavigationTimedOut if the page change
  51. // hasn't been committed.
  52. static constexpr base::TimeDelta kWaitingForNavigationTimeout =
  53. base::Seconds(5);
  54. // The amount of time a page has to be idle post-loading in order for it to be
  55. // considered loaded and idle. This is used in UpdateLoadIdleState
  56. // transitions.
  57. static constexpr base::TimeDelta kLoadedAndIdlingTimeout = base::Seconds(1);
  58. // The maximum amount of time post-DidStopLoading a page can be waiting for
  59. // an idle state to occur before the page is simply considered loaded anyways.
  60. // Since PageAlmostIdle is intended as an "initial loading complete" signal,
  61. // it needs to eventually terminate. This is strictly greater than the
  62. // kLoadedAndIdlingTimeout.
  63. //
  64. // This is taken as the 95th percentile of tab loading times on desktop
  65. // (see SessionRestore.ForegroundTabFirstLoaded). This ensures that all tabs
  66. // eventually transition to loaded, even if they keep the main task queue
  67. // busy, or continue loading content.
  68. static constexpr base::TimeDelta kWaitingForIdleTimeout = base::Minutes(1);
  69. // (Un)registers the various node observer flavors of this object with the
  70. // graph. These are invoked by OnPassedToGraph and OnTakenFromGraph, but
  71. // hoisted to their own functions for testing.
  72. void RegisterObservers(Graph* graph);
  73. void UnregisterObservers(Graph* graph);
  74. // These are called when properties/events affecting the load-idle state are
  75. // observed. Frame and Process variants will eventually all redirect to the
  76. // appropriate Page variant, where the real work is done.
  77. void UpdateLoadIdleStateFrame(FrameNodeImpl* frame_node);
  78. void UpdateLoadIdleStateProcess(ProcessNodeImpl* process_node);
  79. static void UpdateLoadIdleStatePage(PageNodeImpl* page_node);
  80. // Schedules a call to UpdateLoadIdleStatePage() for |page_node| after
  81. // |delayed_run_time| - |now| has elapsed.
  82. static void ScheduleDelayedUpdateLoadIdleStatePage(
  83. PageNodeImpl* page_node,
  84. base::TimeTicks now,
  85. base::TimeTicks delayed_run_time);
  86. // Helper function for transitioning to the final state.
  87. static void TransitionToLoadedAndIdle(PageNodeImpl* page_node);
  88. static bool IsIdling(const PageNodeImpl* page_node);
  89. };
  90. class PageLoadTrackerDecorator::Data {
  91. public:
  92. // The state transitions associated with a load. This is more granular than
  93. // the publicly exposed PageNode::LoadingState, to provide the required
  94. // details to implement state transitions.
  95. enum class LoadIdleState {
  96. // Loading started, but the page change hasn't been committed yet. Can
  97. // transition to kLoading, kWaitingForNavigationTimedOut or kLoadedAndIdle
  98. // from here.
  99. kWaitingForNavigation,
  100. // Loading started and a timeout has elapsed, but the page change hasn't
  101. // been committed yet. Can transition to kLoading or kLoadedAndIdle from
  102. // here.
  103. kWaitingForNavigationTimedOut,
  104. // Incoming data has started to arrive for a load. Almost idle signals are
  105. // ignored in this state. Can transition to kLoadedNotIdling and
  106. // kLoadedAndIdling from here.
  107. kLoading,
  108. // Loading has completed, but the page has not started idling. Can
  109. // transition to kLoadedAndIdling, kLoadedAndIdle or kWaitingForNavigation
  110. // from here (the latter occurs when a new load starts before the previous
  111. // ends).
  112. kLoadedNotIdling,
  113. // Loading has completed, and the page is idling. Can transition to
  114. // kLoadedNotIdling, kLoadedAndIdle or kWaitingForNavigation from here (the
  115. // latter occurs when a new load starts before the previous ends).
  116. kLoadedAndIdling,
  117. // Loading has completed and the page has been idling for sufficiently long
  118. // or encountered an error. This is the final state. Once this state has
  119. // been reached a signal will be emitted and no further state transitions
  120. // will be tracked. Committing a new non-same document navigation can start
  121. // the cycle over again.
  122. kLoadedAndIdle
  123. };
  124. static Data* GetOrCreateForTesting(PageNodeImpl* page_node);
  125. static Data* GetForTesting(PageNodeImpl* page_node);
  126. static bool DestroyForTesting(PageNodeImpl* page_node);
  127. // Sets the LoadIdleState for the page, and updates PageNode::IsLoading()
  128. // accordingly.
  129. void SetLoadIdleState(PageNodeImpl* page_node, LoadIdleState load_idle_state);
  130. // Returns the LoadIdleState for the page.
  131. LoadIdleState load_idle_state() const { return load_idle_state_; }
  132. // Whether there is an ongoing different-document load, i.e. DidStartLoading()
  133. // was invoked but not DidStopLoading().
  134. bool is_loading_ = false;
  135. // Whether there is an ongoing different-document load for which data started
  136. // arriving, i.e. both DidStartLoading() and PrimaryPageChanged() were
  137. // invoked but not DidStopLoading().
  138. bool did_commit_ = false;
  139. // Marks the point in time when the state transitioned to
  140. // kWaitingForNavigation. This is used as the basis for the
  141. // kWaitingForNavigationTimeout.
  142. base::TimeTicks loading_started_;
  143. // Marks the point in time when the DidStopLoading signal was received,
  144. // transitioning to kLoadedAndNotIdling or kLoadedAndIdling. This is used as
  145. // the basis for the kWaitingForIdleTimeout.
  146. base::TimeTicks loading_stopped_;
  147. // Marks the point in time when the last transition to kLoadedAndIdling
  148. // occurred. This is used as the basis for the kLoadedAndIdlingTimeout.
  149. base::TimeTicks idling_started_;
  150. // A one-shot timer used to transition state after a timeout.
  151. base::OneShotTimer timer_;
  152. private:
  153. // Initially at kWaitingForNavigation when a load starts. Transitions
  154. // through the states via calls to UpdateLoadIdleState.
  155. LoadIdleState load_idle_state_ = LoadIdleState::kWaitingForNavigation;
  156. };
  157. } // namespace performance_manager
  158. #endif // COMPONENTS_PERFORMANCE_MANAGER_DECORATORS_PAGE_LOAD_TRACKER_DECORATOR_H_