[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / frame_sequence_tracker.h
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef CC_METRICS_FRAME_SEQUENCE_TRACKER_H_
6 #define CC_METRICS_FRAME_SEQUENCE_TRACKER_H_
7
8 #include <deque>
9 #include <memory>
10 #include <sstream>
11
12 #include "base/containers/circular_deque.h"
13 #include "base/containers/flat_set.h"
14 #include "base/time/time.h"
15 #include "cc/cc_export.h"
16 #include "cc/metrics/frame_sequence_metrics.h"
17
18 namespace gfx {
19 struct PresentationFeedback;
20 }
21
22 namespace viz {
23 struct BeginFrameAck;
24 struct BeginFrameArgs;
25 struct BeginFrameId;
26 }  // namespace viz
27
28 namespace cc {
29 class ThroughputUkmReporter;
30
31 // Tracks a sequence of frames to determine the throughput. It tracks this by
32 // tracking the vsync sequence-numbers (from |BeginFrameArgs::sequence_number|),
33 // and the presentation-timestamps (from |gfx::PresentationFeedback|). It also
34 // tracks which frames were expected to include update from the main-thread, and
35 // which presented frames did include updates from the main-thread.
36 // This object should be created through
37 // FrameSequenceTrackerCollection::CreateTracker() API.
38 class CC_EXPORT FrameSequenceTracker {
39  public:
40   enum class TerminationStatus {
41     kActive,
42     kScheduledForTermination,
43     kReadyForTermination,
44   };
45
46   static const char* GetFrameSequenceTrackerTypeName(
47       FrameSequenceTrackerType type);
48
49   ~FrameSequenceTracker();
50
51   FrameSequenceTracker(const FrameSequenceTracker&) = delete;
52   FrameSequenceTracker& operator=(const FrameSequenceTracker&) = delete;
53
54   // Notifies the tracker when the compositor thread starts to process a
55   // BeginFrameArgs.
56   void ReportBeginImplFrame(const viz::BeginFrameArgs& args);
57
58   // Notifies the tracker when a BeginFrameArgs is dispatched to the main
59   // thread.
60   void ReportBeginMainFrame(const viz::BeginFrameArgs& args);
61
62   void ReportMainFrameProcessed(const viz::BeginFrameArgs& args);
63
64   // Notifies the tracker when the compositor submits a CompositorFrame.
65   // |origin_args| represents the BeginFrameArgs that triggered the update from
66   // the main-thread.
67   void ReportSubmitFrame(uint32_t frame_token,
68                          bool has_missing_content,
69                          const viz::BeginFrameAck& ack,
70                          const viz::BeginFrameArgs& origin_args);
71
72   void ReportFrameEnd(const viz::BeginFrameArgs& args,
73                       const viz::BeginFrameArgs& main_args);
74
75   // Notifies the tracker of the presentation-feedback of a previously submitted
76   // CompositorFrame with |frame_token|.
77   void ReportFramePresented(uint32_t frame_token,
78                             const gfx::PresentationFeedback& feedback);
79
80   // Notifies the tracker that a CompositorFrame is not going to be submitted
81   // for a particular BeginFrameArgs because it did not cause any damage (visual
82   // change). Note that if a begin-main-frame was dispatched, then a separate
83   // call to |ReportMainFrameCausedNoDamage()| is made to notify that the
84   // main-thread did not cause any damage/updates.
85   void ReportImplFrameCausedNoDamage(const viz::BeginFrameAck& ack);
86
87   // Notifies the tracker that a |BeginFrameArgs| either was not dispatched to
88   // the main-thread (because it did not ask for it), or that a |BeginFrameArgs|
89   // that was dispatched to the main-thread did not cause any updates/damage.
90   void ReportMainFrameCausedNoDamage(const viz::BeginFrameArgs& args,
91                                      bool aborted);
92
93   // Notifies that frame production has currently paused. This is typically used
94   // for interactive frame-sequences, e.g. during touch-scroll.
95   void PauseFrameProduction();
96
97   TerminationStatus termination_status() const { return termination_status_; }
98
99   // Returns true if we should ask this tracker to report its throughput data.
100   bool ShouldReportMetricsNow(const viz::BeginFrameArgs& args) const;
101
102   FrameSequenceMetrics* metrics() { return metrics_.get(); }
103   FrameSequenceTrackerType type() const { return metrics_->type(); }
104   int custom_sequence_id() const { return custom_sequence_id_; }
105
106   std::unique_ptr<FrameSequenceMetrics> TakeMetrics();
107
108   // Called by the destructor of FrameSequenceTrackerCollection, asking its
109   // |metrics_| to report.
110   void CleanUp();
111
112   void AddSortedFrame(const viz::BeginFrameArgs& args,
113                       const FrameInfo& frame_info);
114
115  private:
116   friend class FrameSequenceTrackerCollection;
117   friend class FrameSequenceTrackerTest;
118
119   // Constructs a tracker for a typed sequence other than kCustom.
120   FrameSequenceTracker(FrameSequenceTrackerType type,
121                        ThroughputUkmReporter* throughput_ukm_reporter);
122   // Constructs a tracker for a kCustom typed sequence.
123   FrameSequenceTracker(int custom_sequence_id,
124                        FrameSequenceMetrics::CustomReporter custom_reporter);
125
126   FrameSequenceMetrics::ThroughputData& impl_throughput() {
127     return metrics_->impl_throughput();
128   }
129   FrameSequenceMetrics::ThroughputData& main_throughput() {
130     return metrics_->main_throughput();
131   }
132
133   void ScheduleTerminate();
134
135   struct TrackedFrameData {
136     // Represents the |BeginFrameArgs::source_id| and
137     // |BeginFrameArgs::sequence_number| fields of the last processed
138     // BeginFrameArgs.
139     uint64_t previous_source = 0;
140     uint64_t previous_sequence = 0;
141
142     // The difference in |BeginFrameArgs::sequence_number| fields of the last
143     // two processed BeginFrameArgs.
144     uint32_t previous_sequence_delta = 0;
145   };
146
147   struct CheckerboardingData {
148     CheckerboardingData();
149     ~CheckerboardingData();
150
151     // Tracks whether the last presented frame had checkerboarding. This is used
152     // to track how many vsyncs showed frames with checkerboarding.
153     bool last_frame_had_checkerboarding = false;
154
155     base::TimeTicks last_frame_timestamp;
156
157     // A list of frame-tokens that had checkerboarding.
158     base::circular_deque<uint32_t> frames;
159   };
160
161   void UpdateTrackedFrameData(TrackedFrameData* frame_data,
162                               uint64_t source_id,
163                               uint64_t sequence_number,
164                               uint64_t throttled_frame_count);
165
166   bool ShouldIgnoreBeginFrameSource(uint64_t source_id) const;
167
168   bool ShouldIgnoreSequence(uint64_t sequence_number) const;
169
170   const int custom_sequence_id_;
171
172   TerminationStatus termination_status_ = TerminationStatus::kActive;
173
174   TrackedFrameData begin_impl_frame_data_;
175   TrackedFrameData begin_main_frame_data_;
176
177   std::unique_ptr<FrameSequenceMetrics> metrics_;
178
179   CheckerboardingData checkerboarding_;
180
181   // Tracks the list of frame-tokens for compositor-frames that included new
182   // updates from the main-thread, whose presentation-feedback have not been
183   // received yet. When the presentation-feedback for a frame is received, the
184   // corresponding frame-token is removed from this collection.
185   base::circular_deque<uint32_t> main_frames_;
186
187   // Keeps track of the sequence-number of the first received begin-main-frame.
188   // This is used to ignore submitted frames that include updates from earlier
189   // begin-main-frames.
190   uint64_t first_received_main_sequence_ = 0;
191
192   // Keeps track of the first submitted compositor-frame. This is used to ignore
193   // reports from frames that were submitted before this tracker had been
194   // created.
195   uint32_t first_submitted_frame_ = 0;
196
197   // Keeps track of the latest submitted compositor-frame, so that it can
198   // determine when it has received presentation-feedback for submitted frames.
199   // This is used to decide when to terminate this FrameSequenceTracker object.
200   uint32_t last_submitted_frame_ = 0;
201
202   // Keeps track of the begin-main-frames that need to be processed. There can
203   // be multiple in-flight, as BeginMainFrame to ReadyToCommit can be longer
204   // than one `viz::BeginFrameArgs.interval`. When this occurs the Compositor
205   // can send the `n+1` sequence_number, only for the Commit for `n` to arrive
206   // and lead to frame production.
207   std::deque<uint64_t> pending_main_sequences_;
208   uint64_t aborted_main_frame_ = 0;
209   uint64_t no_damage_draw_main_frames_ = 0;
210
211   // Keeps track of the last sequence-number that produced a frame from the
212   // main-thread.
213   uint64_t last_submitted_main_sequence_ = 0;
214
215   // Keeps track of the last sequence-number that produced a frame that did not
216   // have any damage from the main-thread.
217   uint64_t last_no_main_damage_sequence_ = 0;
218
219   // The time when this tracker is created, or the time when it was previously
220   // scheduled to report histogram.
221   base::TimeTicks first_frame_timestamp_;
222
223   // Tracks the presentation timestamp of the previous frame.
224   base::TimeTicks last_frame_presentation_timestamp_;
225
226   // Keeps track of whether the impl-frame being processed did not have any
227   // damage from the compositor (i.e. 'impl damage').
228   bool frame_had_no_compositor_damage_ = false;
229
230   // Keeps track of whether a CompositorFrame is submitted during the frame.
231   bool compositor_frame_submitted_ = false;
232   bool submitted_frame_had_new_main_content_ = false;
233
234   // Keeps track of whether the frame-states should be reset.
235   bool reset_all_state_ = false;
236
237   // A frame that is ignored at ReportSubmitFrame should never be presented.
238   // TODO(xidachen): this should not be necessary. Some webview tests seem to
239   // present a frame even if it is ignored by ReportSubmitFrame.
240   base::flat_set<uint32_t> ignored_frame_tokens_;
241
242   // Report the throughput metrics every 5 seconds.
243   const base::TimeDelta time_delta_to_report_ = base::Seconds(5);
244
245   uint64_t last_started_impl_sequence_ = 0;
246   uint64_t last_processed_impl_sequence_ = 0;
247
248   uint64_t last_processed_main_sequence_ = 0;
249   uint64_t last_processed_main_sequence_latency_ = 0;
250
251   // Handle off-screen main damage case. In this case, the sequence is typically
252   // like: b(1)B(0,1)E(1)n(1)e(1)b(2)n(2)e(2)...b(10)E(2)B(10,10)n(10)e(10).
253   // Note that between two 'E's, all the impl frames caused no damage, and
254   // no main frames were submitted or caused no damage.
255   bool had_impl_frame_submitted_between_commits_ = false;
256   uint64_t previous_begin_main_sequence_ = 0;
257   // TODO(xidachen): remove this one.
258   uint64_t current_begin_main_sequence_ = 0;
259
260   // True when an impl-impl is not ended. A tracker is ready for termination
261   // only when the last impl-frame is ended (ReportFrameEnd).
262   bool is_inside_frame_ = false;
263
264 #if DCHECK_IS_ON()
265   // This stringstream represents a sequence of frame reporting activities on
266   // the current tracker. Each letter can be one of the following:
267   // {'B', 'N', 'b', 'n', 'S', 'P'}, where
268   // 'B' = ReportBeginMainFrame(), 'N' = ReportMainFrameCausedNoDamage(),
269   // 'b' = ReportBeginImplFrame(), 'n' = ReportMainFrameCausedNoDamage(),
270   // 'S' = ReportSubmitFrame() and 'P' = ReportFramePresented().
271   // Note that |frame_sequence_trace_| is only defined and populated
272   // when DCHECK is on.
273   std::stringstream frame_sequence_trace_;
274
275   // |frame_sequence_trace_| can be very long, in some cases we just need a
276   // substring of it. This var tells us how many chars can be ignored from the
277   // beginning of that debug string.
278   unsigned ignored_trace_char_count_ = 0;
279
280   // If ReportBeginImplFrame is never called on a arg, then ReportBeginMainFrame
281   // should ignore that arg.
282   base::flat_set<viz::BeginFrameId> impl_frames_;
283 #endif
284 };
285
286 }  // namespace cc
287
288 #endif  // CC_METRICS_FRAME_SEQUENCE_TRACKER_H_