910e62b5创建于 1月15日历史提交
// 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 <array>
#include <map>
#include <memory>
#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/frame_sorter.h"
#include "cc/metrics/predictor_jank_tracker.h"
#include "cc/metrics/scroll_jank_dropped_frame_tracker.h"
#include "cc/metrics/scroll_jank_v4_processor.h"
#include "services/metrics/public/cpp/ukm_source_id.h"

namespace ukm {
class UkmRecorder;
}

namespace viz {
class FrameTimingDetails;
}

namespace cc {
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,
                                     bool is_trees_in_viz_client);
  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,
                                  bool will_throttle_main);
  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,
                                 bool waiting_for_main);
  virtual void DidPresentCompositorFrame(
      uint32_t frame_token,
      const viz::FrameTimingDetails& details);
  void OnStoppedRequestingBeginFrames();

  // Virtual to stub out CFRC in Viz for TreesInViz.
  virtual void NotifyReadyToCommit(
      std::unique_ptr<BeginMainFrameMetrics> details);

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

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

  std::array<std::unique_ptr<CompositorFrameReporter>,
             PipelineStage::kNumPipelineStages>&
  ReportersForTesting() {
    return reporters_;
  }

  void SetFrameSorter(FrameSorter* frame_sorter) {
    global_trackers_.frame_sorter = frame_sorter;
  }

  void SetFrameSequenceTrackerCollection(
      FrameSequenceTrackerCollection* frame_sequence_trackers) {
    if (global_trackers_.frame_sorter) {
      global_trackers_.frame_sorter->AddObserver(frame_sequence_trackers);
    }
    global_trackers_.frame_sequence_trackers = frame_sequence_trackers;
  }

  void ClearFrameSequenceTrackerCollection() {
    if (global_trackers_.frame_sorter &&
        global_trackers_.frame_sequence_trackers) {
      global_trackers_.frame_sorter->RemoveObserver(
          global_trackers_.frame_sequence_trackers);
    }
    global_trackers_.frame_sequence_trackers = nullptr;
  }

  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_;
  }

  void set_trees_in_viz_client_for_testing(bool new_value) {
    is_trees_in_viz_client_ = new_value;
  }

 private:
  using SmoothThread = CompositorFrameReporter::SmoothThread;
  using SmoothEffectDrivingThread =
      CompositorFrameReporter::SmoothEffectDrivingThread;

  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);

  // 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);

  // 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);

  const bool should_report_histograms_;
  const int layer_tree_host_id_;
  bool is_trees_in_viz_client_;

  viz::BeginFrameId last_submitted_frame_id_;

  bool next_activate_has_invalidation_ = false;

  // 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<ScrollJankV4Processor> scroll_jank_v4_processor_;

  std::array<std::unique_ptr<CompositorFrameReporter>,
             PipelineStage::kNumPipelineStages>
      reporters_;

  // 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;
    SmoothThread smooth_thread = 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_;

  // 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_