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

cc / metrics / frame_sequence_tracker.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_FRAME_SEQUENCE_TRACKER_H_
#define CC_METRICS_FRAME_SEQUENCE_TRACKER_H_

#include <deque>
#include <memory>
#include <sstream>

#include "base/containers/circular_deque.h"
#include "base/containers/flat_set.h"
#include "base/time/time.h"
#include "cc/cc_export.h"
#include "cc/metrics/frame_sequence_metrics.h"

namespace gfx {
struct PresentationFeedback;
}

namespace viz {
struct BeginFrameArgs;
struct BeginFrameId;
}  // namespace viz

namespace cc {
// Tracks a sequence of frames to determine the throughput. It tracks this by
// tracking the vsync sequence-numbers (from |BeginFrameArgs::sequence_number|),
// and the presentation-timestamps (from |gfx::PresentationFeedback|).
// This object should be created through
// FrameSequenceTrackerCollection::CreateTracker() API.
class CC_EXPORT FrameSequenceTracker {
 public:
  enum class TerminationStatus {
    kActive,
    kScheduledForTermination,
    kReadyForTermination,
  };

  static const char* GetFrameSequenceTrackerTypeName(
      FrameSequenceTrackerType type);

  ~FrameSequenceTracker();

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

  // Notifies the tracker when the compositor thread starts to process a
  // BeginFrameArgs.
  void ReportBeginImplFrame(const viz::BeginFrameArgs& args);

  // Notifies the tracker when the compositor thread has finished processing a
  // BeginFrameArgs.
  void ReportFrameEnd(const viz::BeginFrameArgs& args,
                      const viz::BeginFrameArgs& main_args);

  // Notifies that frame production has currently paused. This is typically used
  // for interactive frame-sequences, e.g. during touch-scroll.
  void PauseFrameProduction();

  TerminationStatus termination_status() const { return termination_status_; }

  // Returns true if we should ask this tracker to report its throughput data.
  bool ShouldReportMetricsNow(const viz::BeginFrameArgs& args) const;

  FrameSequenceMetrics* metrics() { return metrics_.get(); }
  FrameSequenceTrackerType type() const { return metrics_->type(); }
  int custom_sequence_id() const { return custom_sequence_id_; }

  std::unique_ptr<FrameSequenceMetrics> TakeMetrics();

  // Called by the destructor of FrameSequenceTrackerCollection, asking its
  // |metrics_| to report.
  void CleanUp();

  // Called by FrameSorter, this delivers `frame_info` merging both Compositor
  // and Main thread updates for the given `args`. These are sorted by the
  // `viz::BeginFrameArgs::frame_id` so we do not have to perform our own
  // analysis of interleaving frames.
  void AddSortedFrame(const viz::BeginFrameArgs& args,
                      const FrameInfo& frame_info);

 private:
  friend class FrameSequenceTrackerCollection;
  friend class FrameSequenceTrackerTest;

  // Constructs a tracker for a typed sequence other than kCustom.
  explicit FrameSequenceTracker(FrameSequenceTrackerType type);
  // Constructs a tracker for a kCustom typed sequence.
  FrameSequenceTracker(int custom_sequence_id,
                       FrameSequenceMetrics::CustomReporter custom_reporter);

  void ScheduleTerminate();

  struct TrackedFrameData {
    // Represents the |BeginFrameArgs::source_id| and
    // |BeginFrameArgs::sequence_number| fields of the last processed
    // BeginFrameArgs.
    uint64_t previous_source = 0;
    uint64_t previous_sequence = 0;
  };

  bool ShouldIgnoreBeginFrameSource(uint64_t source_id) const;
  void ResetAllStateIfPaused();

  const int custom_sequence_id_;

  TerminationStatus termination_status_ = TerminationStatus::kActive;

  TrackedFrameData begin_impl_frame_data_;

  std::unique_ptr<FrameSequenceMetrics> metrics_;

  // Keeps track of whether the frame-states should be reset.
  bool reset_all_state_ = false;

  // Report the throughput metrics every 5 seconds.
  const base::TimeDelta time_delta_to_report_ = base::Seconds(5);

  // True when an impl-impl is not ended. A tracker is ready for termination
  // only when the last impl-frame is ended (ReportFrameEnd).
  bool is_inside_frame_ = false;

  // The args for the first frame that started after the tracker was created.
  viz::BeginFrameArgs first_begin_frame_args_;

  // Frame id of the last ended frame when the tracker is active.
  viz::BeginFrameId last_ended_frame_id_;
  // Frame id of the last sorted frame that the tracker was notified. If this is
  // at least equal to `last_ended_frame_id_` then we are no longer awaiting
  // frame feedback and can terminate immediately.
  viz::BeginFrameId last_sorted_frame_id_;
};

}  // namespace cc

#endif  // CC_METRICS_FRAME_SEQUENCE_TRACKER_H_