1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286

cc / metrics / compositor_frame_reporting_controller.h [blame]

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CC_METRICS_COMPOSITOR_FRAME_REPORTING_CONTROLLER_H_
#define CC_METRICS_COMPOSITOR_FRAME_REPORTING_CONTROLLER_H_

#include <map>
#include <memory>
#include <queue>
#include <vector>

#include "base/containers/circular_deque.h"
#include "base/memory/raw_ptr.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "cc/cc_export.h"
#include "cc/metrics/compositor_frame_reporter.h"
#include "cc/metrics/event_metrics.h"
#include "cc/metrics/frame_sequence_metrics.h"
#include "cc/metrics/predictor_jank_tracker.h"
#include "cc/metrics/scroll_jank_dropped_frame_tracker.h"
#include "services/metrics/public/cpp/ukm_source_id.h"

namespace ukm {
class UkmRecorder;
}

namespace viz {
struct FrameTimingDetails;
}

namespace cc {
class DroppedFrameCounter;
class EventLatencyTracker;
struct BeginMainFrameMetrics;
struct FrameInfo;

// This is used for managing simultaneous CompositorFrameReporter instances
// in the case that the compositor has high latency. Calling one of the
// event functions will begin recording the time of the corresponding
// phase and trace it. If the frame is eventually submitted, then the
// recorded times of each phase will be reported in UMA.
// See CompositorFrameReporter.
class CC_EXPORT CompositorFrameReportingController {
 public:
  // Used as indices for accessing CompositorFrameReporters.
  enum PipelineStage {
    kBeginImplFrame = 0,
    kBeginMainFrame,
    kReadyToCommit,
    kCommit,
    kActivate,
    kNumPipelineStages
  };

  CompositorFrameReportingController(bool should_report_histograms,
                                     bool should_report_ukm,
                                     int layer_tree_host_id);
  virtual ~CompositorFrameReportingController();

  CompositorFrameReportingController(
      const CompositorFrameReportingController&) = delete;
  CompositorFrameReportingController& operator=(
      const CompositorFrameReportingController&) = delete;

  // Events to signal Beginning/Ending of phases.
  virtual void WillBeginImplFrame(const viz::BeginFrameArgs& args);
  virtual void WillBeginMainFrame(const viz::BeginFrameArgs& args);
  virtual void BeginMainFrameAborted(const viz::BeginFrameId& id,
                                     CommitEarlyOutReason reason);
  virtual void WillInvalidateOnImplSide();
  virtual void WillCommit();
  virtual void DidCommit();
  virtual void WillActivate();
  virtual void DidActivate();
  virtual void DidSubmitCompositorFrame(
      SubmitInfo& submit_info,
      const viz::BeginFrameId& current_frame_id,
      const viz::BeginFrameId& last_activated_frame_id);
  virtual void DidNotProduceFrame(const viz::BeginFrameId& id,
                                  FrameSkippedReason skip_reason);
  virtual void OnFinishImplFrame(const viz::BeginFrameId& id);
  virtual void DidPresentCompositorFrame(
      uint32_t frame_token,
      const viz::FrameTimingDetails& details);
  void OnStoppedRequestingBeginFrames();

  void NotifyReadyToCommit(std::unique_ptr<BeginMainFrameMetrics> details);

  void InitializeUkmManager(std::unique_ptr<ukm::UkmRecorder> recorder);
  void SetSourceId(ukm::SourceId source_id);

  void AddActiveTracker(FrameSequenceTrackerType type);
  void RemoveActiveTracker(FrameSequenceTrackerType type);
  void SetScrollingThread(FrameInfo::SmoothEffectDrivingThread thread);

  void SetThreadAffectsSmoothness(
      FrameInfo::SmoothEffectDrivingThread thread_type,
      bool affects_smoothness);

  void set_tick_clock(const base::TickClock* tick_clock) {
    DCHECK(tick_clock);
    tick_clock_ = tick_clock;
  }

  std::unique_ptr<CompositorFrameReporter>* reporters() { return reporters_; }

  void SetDroppedFrameCounter(DroppedFrameCounter* counter);

  void SetFrameSequenceTrackerCollection(
      FrameSequenceTrackerCollection* frame_sequence_trackers) {
    global_trackers_.frame_sequence_trackers = frame_sequence_trackers;
  }

  void set_event_latency_tracker(EventLatencyTracker* event_latency_tracker) {
    global_trackers_.event_latency_tracker = event_latency_tracker;
  }

  void BeginMainFrameStarted(base::TimeTicks begin_main_frame_start_time) {
    begin_main_frame_start_time_ = begin_main_frame_start_time;
  }

  void SetNeedsRasterPropertiesAnimated(bool needs_raster_properties_animated) {
    needs_raster_properties_animated_ = needs_raster_properties_animated;
  }

  bool HasReporterAt(PipelineStage stage) const;

  void SetVisible(bool visible);

 protected:
  struct SubmittedCompositorFrame {
    uint32_t frame_token;
    std::unique_ptr<CompositorFrameReporter> reporter;
    SubmittedCompositorFrame();
    SubmittedCompositorFrame(uint32_t frame_token,
                             std::unique_ptr<CompositorFrameReporter> reporter);
    SubmittedCompositorFrame(SubmittedCompositorFrame&& other);
    ~SubmittedCompositorFrame();
  };
  base::TimeTicks Now() const;

  bool next_activate_has_invalidation() const {
    return next_activate_has_invalidation_;
  }

 private:
  void AdvanceReporterStage(PipelineStage start, PipelineStage target);
  bool CanSubmitImplFrame(const viz::BeginFrameId& id) const;
  bool CanSubmitMainFrame(const viz::BeginFrameId& id) const;
  std::unique_ptr<CompositorFrameReporter> RestoreReporterAtBeginImpl(
      const viz::BeginFrameId& id);
  CompositorFrameReporter::SmoothThread GetSmoothThread() const;
  CompositorFrameReporter::SmoothEffectDrivingThread GetScrollingThread() const;
  CompositorFrameReporter::SmoothThread GetSmoothThreadAtTime(
      base::TimeTicks timestamp) const;
  CompositorFrameReporter::SmoothEffectDrivingThread GetScrollThreadAtTime(
      base::TimeTicks timestamp) const;

  // Checks whether there are reporters containing updates from the main
  // thread, and returns a pointer to that reporter (if any). Otherwise
  // returns nullptr.
  CompositorFrameReporter* GetOutstandingUpdatesFromMain(
      const viz::BeginFrameId& id) const;

  // If the display-compositor skips over some frames (e.g. when the gpu is
  // busy, or the client is non-responsive), then it will not issue any
  // |BeginFrameArgs| for those frames. However, |CompositorFrameReporter|
  // instances should still be created for these frames. The following
  // functions accomplish this.
  void ProcessSkippedFramesIfNecessary(const viz::BeginFrameArgs& args);
  void MaybePassEventMetricsFromDroppedFrames(
      CompositorFrameReporter& reporter,
      uint32_t frame_token,
      bool next_reporter_from_same_frame);
  void StoreEventMetricsFromDroppedFrames(CompositorFrameReporter& reporter,
                                          uint32_t frame_token);
  void CreateReportersForDroppedFrames(
      const viz::BeginFrameArgs& old_args,
      const viz::BeginFrameArgs& new_args) const;

  // The arg is a reference to the unique_ptr, because depending on the state
  // that reporter is in, its ownership might be pass or not.
  void SetPartialUpdateDeciderWhenWaitingOnMain(
      std::unique_ptr<CompositorFrameReporter>& reporter);

  void AddSortedFrame(const viz::BeginFrameArgs& args,
                      const FrameInfo& frame_info);

  const bool should_report_histograms_;
  const int layer_tree_host_id_;

  viz::BeginFrameId last_submitted_frame_id_;

  bool next_activate_has_invalidation_ = false;
  ActiveTrackers active_trackers_;
  FrameInfo::SmoothEffectDrivingThread scrolling_thread_ =
      FrameInfo::SmoothEffectDrivingThread::kUnknown;

  bool is_compositor_thread_driving_smoothness_ = false;
  bool is_main_thread_driving_smoothness_ = false;
  bool is_raster_thread_driving_smoothness_ = false;
  // Sorted history of smooththread. Element i indicating the smooththread
  // from timestamp of element i-1 until timestamp of element i.
  std::map<base::TimeTicks, CompositorFrameReporter::SmoothThread>
      smooth_thread_history_;
  // Sorted history of scrollthread. Element i indicating the smooththread
  // from timestamp of element i-1 until timestamp of element i.
  std::map<base::TimeTicks, CompositorFrameReporter::SmoothEffectDrivingThread>
      scroll_thread_history_;

  // Must outlive `reporters_` and `submitted_compositor_frames_` (which also
  // have reporters), since destroying the reporters can flush frames to
  // `global_trackers_`.
  GlobalMetricsTrackers global_trackers_;

  // The latency reporter passed to each CompositorFrameReporter. Owned here
  // because it must be common among all reporters.
  // DO NOT reorder this line and the ones below. The latency_ukm_reporter_
  // must outlive the objects in |submitted_compositor_frames_|.
  std::unique_ptr<LatencyUkmReporter> latency_ukm_reporter_;
  std::unique_ptr<PredictorJankTracker> predictor_jank_tracker_;
  std::unique_ptr<ScrollJankDroppedFrameTracker>
      scroll_jank_dropped_frame_tracker_;
  std::unique_ptr<ScrollJankUkmReporter> scroll_jank_ukm_reporter_;

  std::unique_ptr<CompositorFrameReporter>
      reporters_[PipelineStage::kNumPipelineStages];

  // Mapping of frame token to pipeline reporter for submitted compositor
  // frames.
  // DO NOT reorder this line and the one above. The latency_ukm_reporter_
  // must outlive the objects in |submitted_compositor_frames_|.
  base::circular_deque<SubmittedCompositorFrame> submitted_compositor_frames_;

  // Contains information about the latest frame that was started, and the state
  // during that frame. This is used to process skipped frames, as well as
  // making sure a CompositorFrameReporter object for a delayed main-frame is
  // created with the correct state.
  struct {
    viz::BeginFrameArgs args;
    FrameInfo::SmoothEffectDrivingThread scrolling_thread =
        FrameInfo::SmoothEffectDrivingThread::kUnknown;
    ActiveTrackers active_trackers;
    CompositorFrameReporter::SmoothThread smooth_thread =
        CompositorFrameReporter::SmoothThread::kSmoothNone;
  } last_started_compositor_frame_;

  base::TimeTicks begin_main_frame_start_time_;

  raw_ptr<const base::TickClock> tick_clock_ =
      base::DefaultTickClock::GetInstance();

  // When a frame with events metrics fails to be presented, its events metrics
  // will be added to this map. The first following presented frame will get
  // these metrics and report them. The key of map is submission frame token.
  // Frame token is chosen over BeginFrameId as key due to the fact that frames
  // can drop while a long running main still eventually presents, in which
  // cases its more appropriate to check against frame_token instead of
  // BeginFrameId.
  std::map<uint32_t, EventMetricsSet> events_metrics_from_dropped_frames_;

  CompositorFrameReporter::CompositorLatencyInfo
      previous_latency_predictions_main_;
  CompositorFrameReporter::CompositorLatencyInfo
      previous_latency_predictions_impl_;

  // Container that stores the EventLatency stage latency predictions based on
  // previous event traces.
  CompositorFrameReporter::EventLatencyInfo event_latency_predictions_;

  // Reporting controller needs to track transition of the page from invisible
  // to visible in order to discard EventsMetrics impacted by duration of page
  // being invisible
  bool visible_ = true;
  bool waiting_for_did_present_after_visible_ = false;

  // Indicates whether or not we expect the next frame to contain an animation
  // which requires impl invalidation.
  bool needs_raster_properties_animated_ = false;
};

}  // namespace cc

#endif  // CC_METRICS_COMPOSITOR_FRAME_REPORTING_CONTROLLER_H_