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.
5 #ifndef CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_
6 #define CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_
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"
30 struct FrameTimingDetails;
34 class DroppedFrameCounter;
35 class EventLatencyTracker;
36 class FrameSequenceTrackerCollection;
37 class LatencyUkmReporter;
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;
46 // This is used for tracing and reporting the duration of pipeline stages within
49 // For each stage in the frame pipeline, calling StartStage will start tracing
50 // that stage (and end any currently running stages).
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 {
62 enum class FrameTerminationStatus {
63 // The tracked compositor frame was presented.
66 // The tracked compositor frame was submitted to the display compositor but
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,
75 // Frame that was being tracked did not end up being submitting (e.g. frame
76 // had no damage or LTHI was ended).
79 // Default termination status. Should not be reachable.
83 // These values are used for indexing the UMA histograms.
84 enum class FrameReportType {
86 kMissedDeadlineFrame = 1,
88 kCompositorOnlyFrame = 3,
89 kMaxValue = kCompositorOnlyFrame
92 // These values are used for indexing the UMA histograms.
93 enum class StageType {
94 kBeginImplFrameToSendBeginMainFrame = 0,
95 kSendBeginMainFrameToCommit = 1,
97 kEndCommitToActivation = 3,
99 kEndActivateToSubmitCompositorFrame = 5,
100 kSubmitCompositorFrameToPresentationCompositorFrame = 6,
105 enum class VizBreakdown {
106 kSubmitToReceiveCompositorFrame = 0,
107 kReceivedCompositorFrameToStartDraw = 1,
108 kStartDrawToSwapStart = 2,
109 kSwapStartToSwapEnd = 3,
110 kSwapEndToPresentationCompositorFrame = 4,
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,
121 enum class BlinkBreakdown {
122 kHandleInputEvents = 0,
128 kCompositingInputs = 6,
130 kCompositeCommit = 8,
132 kBeginMainSentToStarted = 10,
136 // To distinguish between impl and main reporter
137 enum class ReporterType { kImpl = 0, kMain = 1 };
139 struct CC_EXPORT StageData {
140 StageType stage_type;
141 base::TimeTicks start_time;
142 base::TimeTicks end_time;
144 StageData(StageType stage_type,
145 base::TimeTicks start_time,
146 base::TimeTicks end_time);
147 StageData(const StageData&);
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&);
163 using SmoothThread = FrameInfo::SmoothThread;
165 // Holds a processed list of Blink breakdowns with an `Iterator` class to
166 // easily iterator over them.
167 class CC_EXPORT ProcessedBlinkBreakdown {
171 explicit Iterator(const ProcessedBlinkBreakdown* owner);
174 bool IsValid() const;
176 BlinkBreakdown GetBreakdown() const;
177 base::TimeDelta GetLatency() const;
180 raw_ptr<const ProcessedBlinkBreakdown> owner_;
185 ProcessedBlinkBreakdown(base::TimeTicks blink_start_time,
186 base::TimeTicks begin_main_frame_start,
187 const BeginMainFrameMetrics& blink_breakdown);
188 ~ProcessedBlinkBreakdown();
190 ProcessedBlinkBreakdown(const ProcessedBlinkBreakdown&) = delete;
191 ProcessedBlinkBreakdown& operator=(const ProcessedBlinkBreakdown&) = delete;
193 // Returns a new iterator for the Blink breakdowns.
194 Iterator CreateIterator() const;
197 base::TimeDelta list_[static_cast<int>(BlinkBreakdown::kBreakdownCount)];
200 // Holds a processed list of Viz breakdowns with an `Iterator` class to easily
201 // iterate over them.
202 class CC_EXPORT ProcessedVizBreakdown {
206 Iterator(const ProcessedVizBreakdown* owner,
207 bool skip_swap_start_to_swap_end);
210 bool IsValid() const;
212 VizBreakdown GetBreakdown() const;
213 base::TimeTicks GetStartTime() const;
214 base::TimeTicks GetEndTime() const;
215 base::TimeDelta GetDuration() const;
218 raw_ptr<const ProcessedVizBreakdown> owner_;
219 const bool skip_swap_start_to_swap_end_;
224 ProcessedVizBreakdown(base::TimeTicks viz_start_time,
225 const viz::FrameTimingDetails& viz_breakdown);
226 ~ProcessedVizBreakdown();
228 ProcessedVizBreakdown(const ProcessedVizBreakdown&) = delete;
229 ProcessedVizBreakdown& operator=(const ProcessedVizBreakdown&) = delete;
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;
237 base::TimeTicks swap_start() const { return swap_start_; }
240 absl::optional<std::pair<base::TimeTicks, base::TimeTicks>>
241 list_[static_cast<int>(VizBreakdown::kBreakdownCount)];
243 bool buffer_ready_available_ = false;
244 base::TimeTicks swap_start_;
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();
253 std::vector<base::TimeDelta> top_level_stages;
254 std::vector<base::TimeDelta> blink_breakdown_stages;
255 std::vector<base::TimeDelta> viz_breakdown_stages;
257 base::TimeDelta total_latency;
258 base::TimeDelta total_blink_latency;
259 base::TimeDelta total_viz_latency;
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();
271 CompositorFrameReporter(const CompositorFrameReporter& reporter) = delete;
272 CompositorFrameReporter& operator=(const CompositorFrameReporter& reporter) =
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);
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);
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();
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);
304 void AddEventsMetrics(EventMetrics::List events_metrics);
306 // Erase and return all EventMetrics objects from our list.
307 EventMetrics::List TakeEventsMetrics();
309 size_t stage_history_size_for_testing() const {
310 return stage_history_.size();
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_;
322 bool did_not_produce_frame() const {
323 return did_not_produce_frame_time_.has_value();
325 base::TimeTicks did_not_produce_frame_time() const {
326 return *did_not_produce_frame_time_;
329 bool did_abort_main_frame() const {
330 return main_frame_abort_time_.has_value();
332 base::TimeTicks main_frame_abort_time() const {
333 return *main_frame_abort_time_;
336 FrameSkippedReason frame_skip_reason() const { return *frame_skip_reason_; }
338 void set_tick_clock(const base::TickClock* tick_clock) {
340 tick_clock_ = tick_clock;
343 void set_has_missing_content(bool has_missing_content) {
344 has_missing_content_ = has_missing_content;
347 void SetPartialUpdateDecider(CompositorFrameReporter* decider);
349 size_t partial_update_dependents_size_for_testing() const {
350 return partial_update_dependents_.size();
353 size_t owned_partial_update_dependents_size_for_testing() const {
354 return owned_partial_update_dependents_.size();
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;
363 void set_is_forked(bool is_forked) { is_forked_ = is_forked; }
364 void set_is_backfill(bool is_backfill) { is_backfill_ = is_backfill; }
366 const viz::BeginFrameId& frame_id() const { return args_.frame_id; }
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);
373 // If this is a cloned reporter, then this returns a weak-ptr to the original
374 // reporter this was cloned from (using |CopyReporterAtBeginImplStage()|).
376 CompositorFrameReporter* partial_update_decider() const {
377 return partial_update_decider_.get();
379 using FrameReportTypes =
380 std::bitset<static_cast<size_t>(FrameReportType::kMaxValue) + 1>;
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);
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);
395 ReporterType get_reporter_type() { return reporter_type_; }
397 void set_reporter_type_to_impl() { reporter_type_ = ReporterType::kImpl; }
398 void set_reporter_type_to_main() { reporter_type_ = ReporterType::kMain; }
400 const std::vector<std::string>& high_latency_substages_for_testing() {
401 return high_latency_substages_;
404 void ClearHighLatencySubstagesForTesting() {
405 high_latency_substages_.clear();
408 std::vector<std::unique_ptr<EventMetrics>>& events_metrics_for_testing() {
409 return events_metrics_;
413 void set_has_partial_update(bool has_partial_update) {
414 has_partial_update_ = has_partial_update;
418 void TerminateReporter();
419 void EndCurrentStage(base::TimeTicks end_time);
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;
437 void ReportEventLatencyMetrics() const;
438 void ReportCompositorLatencyTraceEvents(const FrameInfo& info) const;
439 void ReportEventLatencyTraceEvents() const;
441 void EnableReportType(FrameReportType report_type) {
442 report_types_.set(static_cast<size_t>(report_type));
444 bool TestReportType(FrameReportType report_type) const {
445 return report_types_.test(static_cast<size_t>(report_type));
448 // This method is only used for DCheck
449 base::TimeDelta SumOfStageHistory() const;
451 // Terminating reporters in partial_update_dependents_ after a limit.
452 void DiscardOldPartialUpdateReporters();
454 base::TimeTicks Now() const;
456 FrameInfo GenerateFrameInfo() const;
458 base::WeakPtr<CompositorFrameReporter> GetWeakPtr();
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();
464 void FindHighLatencyAttribution(
465 CompositorLatencyInfo& previous_predictions,
466 CompositorLatencyInfo& current_stage_durations);
468 void FindEventLatencyAttribution(
469 EventMetrics* event_metrics,
470 CompositorFrameReporter::EventLatencyInfo& predicted_event_latency,
471 CompositorFrameReporter::EventLatencyInfo& actual_event_latency);
473 // Whether UMA histograms should be reported or not.
474 const bool should_report_histograms_;
476 const viz::BeginFrameArgs args_;
478 StageData current_stage_;
480 BeginMainFrameMetrics blink_breakdown_;
481 base::TimeTicks blink_start_time_;
482 std::unique_ptr<ProcessedBlinkBreakdown> processed_blink_breakdown_;
484 viz::FrameTimingDetails viz_breakdown_;
485 base::TimeTicks viz_start_time_;
486 std::unique_ptr<ProcessedVizBreakdown> processed_viz_breakdown_;
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_;
493 // List of metrics for events affecting this frame.
494 EventMetrics::List events_metrics_;
496 FrameReportTypes report_types_;
498 base::TimeTicks frame_termination_time_;
499 base::TimeTicks begin_main_frame_start_;
500 FrameTerminationStatus frame_termination_status_ =
501 FrameTerminationStatus::kUnknown;
503 const ActiveTrackers active_trackers_;
504 const FrameInfo::SmoothEffectDrivingThread scrolling_thread_;
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_;
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_;
518 raw_ptr<const base::TickClock> tick_clock_ =
519 base::DefaultTickClock::GetInstance();
521 bool has_partial_update_ = false;
523 // If the submitted frame has update from main thread
524 bool is_accompanied_by_main_thread_update_ = false;
526 const SmoothThread smooth_thread_;
527 const int layer_tree_host_id_;
529 // Indicates whether the submitted frame had any missing content (i.e. content
530 // with checkerboarding).
531 bool has_missing_content_ = false;
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;
537 // Indicates whether the frame is backfill (i.e. dropped frames when there are
538 // no partial compositor updates).
539 bool is_backfill_ = false;
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;
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_;
560 const GlobalMetricsTrackers global_trackers_;
562 std::vector<std::string> high_latency_substages_;
564 ReporterType reporter_type_;
566 base::WeakPtrFactory<CompositorFrameReporter> weak_factory_{this};
571 #endif // CC_METRICS_COMPOSITOR_FRAME_REPORTER_H_