[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / compositor_frame_reporter.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_COMPOSITOR_FRAME_REPORTER_H_
6 #define CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_
7
8 #include <bitset>
9 #include <memory>
10 #include <queue>
11 #include <string>
12 #include <utility>
13 #include <vector>
14
15 #include "base/memory/raw_ptr.h"
16 #include "base/time/default_tick_clock.h"
17 #include "base/time/time.h"
18 #include "cc/base/devtools_instrumentation.h"
19 #include "cc/cc_export.h"
20 #include "cc/metrics/begin_main_frame_metrics.h"
21 #include "cc/metrics/event_metrics.h"
22 #include "cc/metrics/frame_info.h"
23 #include "cc/metrics/frame_sequence_metrics.h"
24 #include "cc/scheduler/scheduler.h"
25 #include "components/viz/common/frame_sinks/begin_frame_args.h"
26 #include "components/viz/common/frame_timing_details.h"
27 #include "third_party/abseil-cpp/absl/types/optional.h"
28
29 namespace viz {
30 struct FrameTimingDetails;
31 }
32
33 namespace cc {
34 class DroppedFrameCounter;
35 class EventLatencyTracker;
36 class FrameSequenceTrackerCollection;
37 class LatencyUkmReporter;
38
39 struct GlobalMetricsTrackers {
40   raw_ptr<DroppedFrameCounter> dropped_frame_counter = nullptr;
41   raw_ptr<LatencyUkmReporter> latency_ukm_reporter = nullptr;
42   raw_ptr<FrameSequenceTrackerCollection> frame_sequence_trackers = nullptr;
43   raw_ptr<EventLatencyTracker> event_latency_tracker = nullptr;
44 };
45
46 // This is used for tracing and reporting the duration of pipeline stages within
47 // a single frame.
48 //
49 // For each stage in the frame pipeline, calling StartStage will start tracing
50 // that stage (and end any currently running stages).
51 //
52 // If the tracked frame is presented (i.e. the frame termination status is
53 // kPresentedFrame), then the duration of each stage along with the total
54 // latency will be reported to UMA. If the tracked frame is not presented (i.e.
55 // the frame termination status is kDidNotPresentFrame or
56 // kReplacedByNewReporter), then the duration is reported under
57 // CompositorLatency.DroppedFrame.*.
58 // The format of each stage reported to UMA is
59 // "CompositorLatency.[DroppedFrame.][Interaction_name.].<StageName>".
60 class CC_EXPORT CompositorFrameReporter {
61  public:
62   enum class FrameTerminationStatus {
63     // The tracked compositor frame was presented.
64     kPresentedFrame,
65
66     // The tracked compositor frame was submitted to the display compositor but
67     // was not presented.
68     kDidNotPresentFrame,
69
70     // Reporter that is currently at a stage is replaced by a new one (e.g. two
71     // BeginImplFrames can happen without issuing BeginMainFrame, so the first
72     // reporter would terminate with this status).
73     kReplacedByNewReporter,
74
75     // Frame that was being tracked did not end up being submitting (e.g. frame
76     // had no damage or LTHI was ended).
77     kDidNotProduceFrame,
78
79     // Default termination status. Should not be reachable.
80     kUnknown
81   };
82
83   // These values are used for indexing the UMA histograms.
84   enum class FrameReportType {
85     kNonDroppedFrame = 0,
86     kMissedDeadlineFrame = 1,
87     kDroppedFrame = 2,
88     kCompositorOnlyFrame = 3,
89     kMaxValue = kCompositorOnlyFrame
90   };
91
92   // These values are used for indexing the UMA histograms.
93   enum class StageType {
94     kBeginImplFrameToSendBeginMainFrame = 0,
95     kSendBeginMainFrameToCommit = 1,
96     kCommit = 2,
97     kEndCommitToActivation = 3,
98     kActivation = 4,
99     kEndActivateToSubmitCompositorFrame = 5,
100     kSubmitCompositorFrameToPresentationCompositorFrame = 6,
101     kTotalLatency = 7,
102     kStageTypeCount
103   };
104
105   enum class VizBreakdown {
106     kSubmitToReceiveCompositorFrame = 0,
107     kReceivedCompositorFrameToStartDraw = 1,
108     kStartDrawToSwapStart = 2,
109     kSwapStartToSwapEnd = 3,
110     kSwapEndToPresentationCompositorFrame = 4,
111
112     // This is a breakdown of SwapStartToSwapEnd stage which is optionally
113     // recorded if querying these timestamps is supported by the platform.
114     kSwapStartToBufferAvailable = 5,
115     kBufferAvailableToBufferReady = 6,
116     kBufferReadyToLatch = 7,
117     kLatchToSwapEnd = 8,
118     kBreakdownCount
119   };
120
121   enum class BlinkBreakdown {
122     kHandleInputEvents = 0,
123     kAnimate = 1,
124     kStyleUpdate = 2,
125     kLayoutUpdate = 3,
126     kAccessibility = 4,
127     kPrepaint = 5,
128     kCompositingInputs = 6,
129     kPaint = 7,
130     kCompositeCommit = 8,
131     kUpdateLayers = 9,
132     kBeginMainSentToStarted = 10,
133     kBreakdownCount
134   };
135
136   // To distinguish between impl and main reporter
137   enum class ReporterType { kImpl = 0, kMain = 1 };
138
139   struct CC_EXPORT StageData {
140     StageType stage_type;
141     base::TimeTicks start_time;
142     base::TimeTicks end_time;
143     StageData();
144     StageData(StageType stage_type,
145               base::TimeTicks start_time,
146               base::TimeTicks end_time);
147     StageData(const StageData&);
148     ~StageData();
149   };
150
151   struct CC_EXPORT EventLatencyInfo {
152     std::vector<base::TimeDelta> dispatch_durations;
153     base::TimeDelta transition_duration;
154     std::vector<base::TimeDelta> compositor_durations;
155     base::TimeDelta total_duration;
156     std::string transition_name;
157     EventLatencyInfo(const int num_dispatch_stages,
158                      const int num_compositor_stages);
159     EventLatencyInfo(const EventLatencyInfo&);
160     ~EventLatencyInfo();
161   };
162
163   using SmoothThread = FrameInfo::SmoothThread;
164
165   // Holds a processed list of Blink breakdowns with an `Iterator` class to
166   // easily iterator over them.
167   class CC_EXPORT ProcessedBlinkBreakdown {
168    public:
169     class Iterator {
170      public:
171       explicit Iterator(const ProcessedBlinkBreakdown* owner);
172       ~Iterator();
173
174       bool IsValid() const;
175       void Advance();
176       BlinkBreakdown GetBreakdown() const;
177       base::TimeDelta GetLatency() const;
178
179      private:
180       raw_ptr<const ProcessedBlinkBreakdown> owner_;
181
182       size_t index_ = 0;
183     };
184
185     ProcessedBlinkBreakdown(base::TimeTicks blink_start_time,
186                             base::TimeTicks begin_main_frame_start,
187                             const BeginMainFrameMetrics& blink_breakdown);
188     ~ProcessedBlinkBreakdown();
189
190     ProcessedBlinkBreakdown(const ProcessedBlinkBreakdown&) = delete;
191     ProcessedBlinkBreakdown& operator=(const ProcessedBlinkBreakdown&) = delete;
192
193     // Returns a new iterator for the Blink breakdowns.
194     Iterator CreateIterator() const;
195
196    private:
197     base::TimeDelta list_[static_cast<int>(BlinkBreakdown::kBreakdownCount)];
198   };
199
200   // Holds a processed list of Viz breakdowns with an `Iterator` class to easily
201   // iterate over them.
202   class CC_EXPORT ProcessedVizBreakdown {
203    public:
204     class Iterator {
205      public:
206       Iterator(const ProcessedVizBreakdown* owner,
207                bool skip_swap_start_to_swap_end);
208       ~Iterator();
209
210       bool IsValid() const;
211       void Advance();
212       VizBreakdown GetBreakdown() const;
213       base::TimeTicks GetStartTime() const;
214       base::TimeTicks GetEndTime() const;
215       base::TimeDelta GetDuration() const;
216
217      private:
218       raw_ptr<const ProcessedVizBreakdown> owner_;
219       const bool skip_swap_start_to_swap_end_;
220
221       size_t index_ = 0;
222     };
223
224     ProcessedVizBreakdown(base::TimeTicks viz_start_time,
225                           const viz::FrameTimingDetails& viz_breakdown);
226     ~ProcessedVizBreakdown();
227
228     ProcessedVizBreakdown(const ProcessedVizBreakdown&) = delete;
229     ProcessedVizBreakdown& operator=(const ProcessedVizBreakdown&) = delete;
230
231     // Returns a new iterator for the Viz breakdowns. If buffer ready breakdowns
232     // are available, `skip_swap_start_to_swap_end_if_breakdown_available` can
233     // be used to skip `kSwapStartToSwapEnd` breakdown.
234     Iterator CreateIterator(
235         bool skip_swap_start_to_swap_end_if_breakdown_available) const;
236
237     base::TimeTicks swap_start() const { return swap_start_; }
238
239    private:
240     absl::optional<std::pair<base::TimeTicks, base::TimeTicks>>
241         list_[static_cast<int>(VizBreakdown::kBreakdownCount)];
242
243     bool buffer_ready_available_ = false;
244     base::TimeTicks swap_start_;
245   };
246
247   // Wrapper for all level of breakdown stages' prediction
248   struct CC_EXPORT CompositorLatencyInfo {
249     CompositorLatencyInfo();
250     explicit CompositorLatencyInfo(base::TimeDelta init_value);
251     ~CompositorLatencyInfo();
252
253     std::vector<base::TimeDelta> top_level_stages;
254     std::vector<base::TimeDelta> blink_breakdown_stages;
255     std::vector<base::TimeDelta> viz_breakdown_stages;
256
257     base::TimeDelta total_latency;
258     base::TimeDelta total_blink_latency;
259     base::TimeDelta total_viz_latency;
260   };
261
262   CompositorFrameReporter(const ActiveTrackers& active_trackers,
263                           const viz::BeginFrameArgs& args,
264                           bool should_report_histograms,
265                           SmoothThread smooth_thread,
266                           FrameInfo::SmoothEffectDrivingThread scrolling_thread,
267                           int layer_tree_host_id,
268                           const GlobalMetricsTrackers& trackers);
269   ~CompositorFrameReporter();
270
271   CompositorFrameReporter(const CompositorFrameReporter& reporter) = delete;
272   CompositorFrameReporter& operator=(const CompositorFrameReporter& reporter) =
273       delete;
274
275   // Name for `CompositorFrameReporter::StageType`, possibly suffixed with the
276   // name of the appropriate breakdown.
277   static const char* GetStageName(
278       StageType stage_type,
279       absl::optional<VizBreakdown> viz_breakdown = absl::nullopt,
280       absl::optional<BlinkBreakdown> blink_breakdown = absl::nullopt,
281       bool impl_only = false);
282
283   // Name for the viz breakdowns which are shown in traces as substages under
284   // PipelineReporter -> SubmitCompositorFrameToPresentationCompositorFrame or
285   // EventLatency -> SubmitCompositorFrameToPresentationCompositorFrame.
286   static const char* GetVizBreakdownName(VizBreakdown breakdown);
287
288   // Creates and returns a clone of the reporter, only if it is currently in the
289   // 'begin impl frame' stage. For any other state, it returns null.
290   // This is used only when there is a partial update. So the cloned reporter
291   // depends in this reporter to decide whether it contains be partial updates
292   // or complete updates.
293   std::unique_ptr<CompositorFrameReporter> CopyReporterAtBeginImplStage();
294
295   // Note that the started stage may be reported to UMA. If the histogram is
296   // intended to be reported then the histograms.xml file must be updated too.
297   void StartStage(StageType stage_type, base::TimeTicks start_time);
298   void TerminateFrame(FrameTerminationStatus termination_status,
299                       base::TimeTicks termination_time);
300   void SetBlinkBreakdown(std::unique_ptr<BeginMainFrameMetrics> blink_breakdown,
301                          base::TimeTicks begin_main_start);
302   void SetVizBreakdown(const viz::FrameTimingDetails& viz_breakdown);
303
304   void AddEventsMetrics(EventMetrics::List events_metrics);
305
306   // Erase and return all EventMetrics objects from our list.
307   EventMetrics::List TakeEventsMetrics();
308
309   size_t stage_history_size_for_testing() const {
310     return stage_history_.size();
311   }
312
313   void OnFinishImplFrame(base::TimeTicks timestamp);
314   void OnAbortBeginMainFrame(base::TimeTicks timestamp);
315   void OnDidNotProduceFrame(FrameSkippedReason skip_reason);
316   void EnableCompositorOnlyReporting();
317   bool did_finish_impl_frame() const { return did_finish_impl_frame_; }
318   base::TimeTicks impl_frame_finish_time() const {
319     return impl_frame_finish_time_;
320   }
321
322   bool did_not_produce_frame() const {
323     return did_not_produce_frame_time_.has_value();
324   }
325   base::TimeTicks did_not_produce_frame_time() const {
326     return *did_not_produce_frame_time_;
327   }
328
329   bool did_abort_main_frame() const {
330     return main_frame_abort_time_.has_value();
331   }
332   base::TimeTicks main_frame_abort_time() const {
333     return *main_frame_abort_time_;
334   }
335
336   FrameSkippedReason frame_skip_reason() const { return *frame_skip_reason_; }
337
338   void set_tick_clock(const base::TickClock* tick_clock) {
339     DCHECK(tick_clock);
340     tick_clock_ = tick_clock;
341   }
342
343   void set_has_missing_content(bool has_missing_content) {
344     has_missing_content_ = has_missing_content;
345   }
346
347   void SetPartialUpdateDecider(CompositorFrameReporter* decider);
348
349   size_t partial_update_dependents_size_for_testing() const {
350     return partial_update_dependents_.size();
351   }
352
353   size_t owned_partial_update_dependents_size_for_testing() const {
354     return owned_partial_update_dependents_.size();
355   }
356
357   void set_is_accompanied_by_main_thread_update(
358       bool is_accompanied_by_main_thread_update) {
359     is_accompanied_by_main_thread_update_ =
360         is_accompanied_by_main_thread_update;
361   }
362
363   void set_is_forked(bool is_forked) { is_forked_ = is_forked; }
364   void set_is_backfill(bool is_backfill) { is_backfill_ = is_backfill; }
365
366   const viz::BeginFrameId& frame_id() const { return args_.frame_id; }
367
368   // Adopts |cloned_reporter|, i.e. keeps |cloned_reporter| alive until after
369   // this reporter terminates. Note that the |cloned_reporter| must have been
370   // created from this reporter using |CopyReporterAtBeginImplStage()|.
371   void AdoptReporter(std::unique_ptr<CompositorFrameReporter> cloned_reporter);
372
373   // If this is a cloned reporter, then this returns a weak-ptr to the original
374   // reporter this was cloned from (using |CopyReporterAtBeginImplStage()|).
375
376   CompositorFrameReporter* partial_update_decider() const {
377     return partial_update_decider_.get();
378   }
379   using FrameReportTypes =
380       std::bitset<static_cast<size_t>(FrameReportType::kMaxValue) + 1>;
381
382   // This function is called to calculate breakdown stage duration's prediction
383   // based on the `previous_predictions` and update the `previous_predictions`
384   // to the new prediction calculated.
385   void CalculateCompositorLatencyPrediction(
386       CompositorLatencyInfo& previous_predictions,
387       base::TimeDelta prediction_deviation_threshold);
388
389   // Sets EventLatency stage duration predictions based on previous trace
390   // durations using exponentially weighted averages.
391   void CalculateEventLatencyPrediction(
392       CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
393       base::TimeDelta prediction_deviation_threshold);
394
395   ReporterType get_reporter_type() { return reporter_type_; }
396
397   void set_reporter_type_to_impl() { reporter_type_ = ReporterType::kImpl; }
398   void set_reporter_type_to_main() { reporter_type_ = ReporterType::kMain; }
399
400   const std::vector<std::string>& high_latency_substages_for_testing() {
401     return high_latency_substages_;
402   }
403
404   void ClearHighLatencySubstagesForTesting() {
405     high_latency_substages_.clear();
406   }
407
408   std::vector<std::unique_ptr<EventMetrics>>& events_metrics_for_testing() {
409     return events_metrics_;
410   }
411
412  protected:
413   void set_has_partial_update(bool has_partial_update) {
414     has_partial_update_ = has_partial_update;
415   }
416
417  private:
418   void TerminateReporter();
419   void EndCurrentStage(base::TimeTicks end_time);
420
421   void ReportCompositorLatencyMetrics() const;
422   void ReportStageHistogramWithBreakdown(
423       const StageData& stage,
424       FrameSequenceTrackerType frame_sequence_tracker_type =
425           FrameSequenceTrackerType::kMaxType) const;
426   void ReportCompositorLatencyBlinkBreakdowns(
427       FrameSequenceTrackerType frame_sequence_tracker_type) const;
428   void ReportCompositorLatencyVizBreakdowns(
429       FrameSequenceTrackerType frame_sequence_tracker_type) const;
430   void ReportCompositorLatencyHistogram(
431       FrameSequenceTrackerType intraction_type,
432       StageType stage_type,
433       absl::optional<VizBreakdown> viz_breakdown,
434       absl::optional<BlinkBreakdown> blink_breakdown,
435       base::TimeDelta time_delta) const;
436
437   void ReportEventLatencyMetrics() const;
438   void ReportCompositorLatencyTraceEvents(const FrameInfo& info) const;
439   void ReportEventLatencyTraceEvents() const;
440
441   void EnableReportType(FrameReportType report_type) {
442     report_types_.set(static_cast<size_t>(report_type));
443   }
444   bool TestReportType(FrameReportType report_type) const {
445     return report_types_.test(static_cast<size_t>(report_type));
446   }
447
448   // This method is only used for DCheck
449   base::TimeDelta SumOfStageHistory() const;
450
451   // Terminating reporters in partial_update_dependents_ after a limit.
452   void DiscardOldPartialUpdateReporters();
453
454   base::TimeTicks Now() const;
455
456   FrameInfo GenerateFrameInfo() const;
457
458   base::WeakPtr<CompositorFrameReporter> GetWeakPtr();
459
460   // Erase and return only the EventMetrics objects which depend on main thread
461   // updates (see comments on EventMetrics::requires_main_thread_update_).
462   EventMetrics::List TakeMainBlockedEventsMetrics();
463
464   void FindHighLatencyAttribution(
465       CompositorLatencyInfo& previous_predictions,
466       CompositorLatencyInfo& current_stage_durations);
467
468   void FindEventLatencyAttribution(
469       EventMetrics* event_metrics,
470       CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
471       CompositorFrameReporter::EventLatencyInfo& actual_event_latency);
472
473   // Whether UMA histograms should be reported or not.
474   const bool should_report_histograms_;
475
476   const viz::BeginFrameArgs args_;
477
478   StageData current_stage_;
479
480   BeginMainFrameMetrics blink_breakdown_;
481   base::TimeTicks blink_start_time_;
482   std::unique_ptr<ProcessedBlinkBreakdown> processed_blink_breakdown_;
483
484   viz::FrameTimingDetails viz_breakdown_;
485   base::TimeTicks viz_start_time_;
486   std::unique_ptr<ProcessedVizBreakdown> processed_viz_breakdown_;
487
488   // Stage data is recorded here. On destruction these stages will be reported
489   // to UMA if the termination status is |kPresentedFrame|. Reported data will
490   // be divided based on the frame submission status.
491   std::vector<StageData> stage_history_;
492
493   // List of metrics for events affecting this frame.
494   EventMetrics::List events_metrics_;
495
496   FrameReportTypes report_types_;
497
498   base::TimeTicks frame_termination_time_;
499   base::TimeTicks begin_main_frame_start_;
500   FrameTerminationStatus frame_termination_status_ =
501       FrameTerminationStatus::kUnknown;
502
503   const ActiveTrackers active_trackers_;
504   const FrameInfo::SmoothEffectDrivingThread scrolling_thread_;
505
506   // Indicates if work on Impl frame is finished.
507   bool did_finish_impl_frame_ = false;
508   // The time that work on Impl frame is finished. It's only valid if the
509   // reporter is in a stage other than begin impl frame.
510   base::TimeTicks impl_frame_finish_time_;
511
512   // The timestamp of when the frame was marked as not having produced a frame
513   // (through a call to DidNotProduceFrame()).
514   absl::optional<base::TimeTicks> did_not_produce_frame_time_;
515   absl::optional<FrameSkippedReason> frame_skip_reason_;
516   absl::optional<base::TimeTicks> main_frame_abort_time_;
517
518   raw_ptr<const base::TickClock> tick_clock_ =
519       base::DefaultTickClock::GetInstance();
520
521   bool has_partial_update_ = false;
522
523   // If the submitted frame has update from main thread
524   bool is_accompanied_by_main_thread_update_ = false;
525
526   const SmoothThread smooth_thread_;
527   const int layer_tree_host_id_;
528
529   // Indicates whether the submitted frame had any missing content (i.e. content
530   // with checkerboarding).
531   bool has_missing_content_ = false;
532
533   // Indicates whether the frame is forked (i.e. a PipelineReporter event starts
534   // at the same frame sequence as another PipelineReporter).
535   bool is_forked_ = false;
536
537   // Indicates whether the frame is backfill (i.e. dropped frames when there are
538   // no partial compositor updates).
539   bool is_backfill_ = false;
540
541   // For a reporter A, if the main-thread takes a long time to respond
542   // to a begin-main-frame, then all reporters created (and terminated) until
543   // the main-thread responds depends on this reporter to decide whether those
544   // frames contained partial updates (i.e. main-thread made some visual
545   // updates, but were not included in the frame), or complete updates.
546   // In such cases, |partial_update_dependents_| for A contains all the frames
547   // that depend on A for deciding whether they had partial updates or not, and
548   // |partial_update_decider_| is set to A for all these reporters.
549   std::queue<base::WeakPtr<CompositorFrameReporter>> partial_update_dependents_;
550   base::WeakPtr<CompositorFrameReporter> partial_update_decider_;
551   uint32_t discarded_partial_update_dependents_count_ = 0;
552
553   // From the above example, it may be necessary for A to keep all the
554   // dependents alive until A terminates, so that the dependents can set their
555   // |has_partial_update_| flags correctly. This is done by passing ownership of
556   // these reporters (using |AdoptReporter()|).
557   std::queue<std::unique_ptr<CompositorFrameReporter>>
558       owned_partial_update_dependents_;
559
560   const GlobalMetricsTrackers global_trackers_;
561
562   std::vector<std::string> high_latency_substages_;
563
564   ReporterType reporter_type_;
565
566   base::WeakPtrFactory<CompositorFrameReporter> weak_factory_{this};
567 };
568
569 }  // namespace cc
570
571 #endif  // CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_