[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / compositor_frame_reporting_controller.cc
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 #include "cc/metrics/compositor_frame_reporting_controller.h"
6
7 #include <utility>
8
9 #include "base/trace_event/trace_event.h"
10 #include "base/trace_event/trace_id_helper.h"
11 #include "cc/metrics/compositor_frame_reporter.h"
12 #include "cc/metrics/dropped_frame_counter.h"
13 #include "cc/metrics/frame_sequence_tracker_collection.h"
14 #include "cc/metrics/latency_ukm_reporter.h"
15 #include "components/viz/common/frame_timing_details.h"
16 #include "components/viz/common/quads/compositor_frame_metadata.h"
17 #include "services/tracing/public/cpp/perfetto/macros.h"
18
19 namespace cc {
20 namespace {
21 using SmoothThread = CompositorFrameReporter::SmoothThread;
22 using StageType = CompositorFrameReporter::StageType;
23 using FrameTerminationStatus = CompositorFrameReporter::FrameTerminationStatus;
24
25 constexpr char kTraceCategory[] = "cc,benchmark";
26 constexpr int kNumOfCompositorStages =
27     static_cast<int>(StageType::kStageTypeCount) - 1;
28 constexpr int kNumDispatchStages =
29     static_cast<int>(EventMetrics::DispatchStage::kMaxValue);
30 constexpr base::TimeDelta kDefaultLatencyPredictionDeviationThreshold =
31     viz::BeginFrameArgs::DefaultInterval() / 2;
32 }  // namespace
33
34 CompositorFrameReportingController::CompositorFrameReportingController(
35     bool should_report_histograms,
36     bool should_report_ukm,
37     int layer_tree_host_id)
38     : should_report_histograms_(should_report_histograms),
39       layer_tree_host_id_(layer_tree_host_id),
40       latency_ukm_reporter_(std::make_unique<LatencyUkmReporter>()),
41       previous_latency_predictions_main_(base::Microseconds(-1)),
42       previous_latency_predictions_impl_(base::Microseconds(-1)),
43       event_latency_predictions_(
44           CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages,
45                                                     kNumOfCompositorStages)) {
46   if (should_report_ukm) {
47     // UKM metrics should be reported if and only if `latency_ukm_reporter` is
48     // set on `global_trackers_`.
49     global_trackers_.latency_ukm_reporter = latency_ukm_reporter_.get();
50   }
51 }
52
53 CompositorFrameReportingController::~CompositorFrameReportingController() {
54   base::TimeTicks now = Now();
55   for (int i = 0; i < PipelineStage::kNumPipelineStages; ++i) {
56     if (reporters_[i]) {
57       reporters_[i]->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
58                                     now);
59     }
60   }
61   for (auto& pair : submitted_compositor_frames_) {
62     pair.reporter->TerminateFrame(FrameTerminationStatus::kDidNotPresentFrame,
63                                   Now());
64   }
65 }
66
67 CompositorFrameReportingController::SubmittedCompositorFrame::
68     SubmittedCompositorFrame() = default;
69 CompositorFrameReportingController::SubmittedCompositorFrame::
70     SubmittedCompositorFrame(uint32_t frame_token,
71                              std::unique_ptr<CompositorFrameReporter> reporter)
72     : frame_token(frame_token), reporter(std::move(reporter)) {}
73 CompositorFrameReportingController::SubmittedCompositorFrame::
74     ~SubmittedCompositorFrame() = default;
75
76 CompositorFrameReportingController::SubmittedCompositorFrame::
77     SubmittedCompositorFrame(SubmittedCompositorFrame&& other) = default;
78
79 base::TimeTicks CompositorFrameReportingController::Now() const {
80   return tick_clock_->NowTicks();
81 }
82
83 bool CompositorFrameReportingController::HasReporterAt(
84     PipelineStage stage) const {
85   return !!reporters_[stage].get();
86 }
87
88 void CompositorFrameReportingController::ProcessSkippedFramesIfNecessary(
89     const viz::BeginFrameArgs& args) {
90   const auto& previous_frame = last_started_compositor_frame_.args;
91   if (previous_frame.IsValid() &&
92       previous_frame.frame_id.source_id == args.frame_id.source_id) {
93     CreateReportersForDroppedFrames(previous_frame, args);
94   }
95
96   last_started_compositor_frame_.args = args;
97   last_started_compositor_frame_.scrolling_thread = scrolling_thread_;
98   last_started_compositor_frame_.active_trackers = active_trackers_;
99   last_started_compositor_frame_.smooth_thread = GetSmoothThread();
100 }
101
102 void CompositorFrameReportingController::WillBeginImplFrame(
103     const viz::BeginFrameArgs& args) {
104   ProcessSkippedFramesIfNecessary(args);
105   ReportMultipleSwaps(args.frame_time, last_interval_);
106   last_interval_ = args.interval;
107
108   base::TimeTicks begin_time = Now();
109   if (reporters_[PipelineStage::kBeginImplFrame]) {
110     auto& reporter = reporters_[PipelineStage::kBeginImplFrame];
111     DCHECK(reporter->did_finish_impl_frame());
112     // TODO(1144353): This is a speculative fix. This code should only be
113     // reached after the previous frame have been explicitly marked as 'did not
114     // produce frame', i.e. this code should have a DCHECK instead of a
115     // conditional:
116     //   DCHECK(reporter->did_not_produce_frame()).
117     if (reporter->did_not_produce_frame()) {
118       reporter->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
119                                reporter->did_not_produce_frame_time());
120     } else {
121       reporter->TerminateFrame(FrameTerminationStatus::kReplacedByNewReporter,
122                                Now());
123     }
124   }
125   auto reporter = std::make_unique<CompositorFrameReporter>(
126       active_trackers_, args, should_report_histograms_, GetSmoothThread(),
127       scrolling_thread_, layer_tree_host_id_, global_trackers_);
128   reporter->set_tick_clock(tick_clock_);
129   reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
130                        begin_time);
131   reporters_[PipelineStage::kBeginImplFrame] = std::move(reporter);
132 }
133
134 void CompositorFrameReportingController::WillBeginMainFrame(
135     const viz::BeginFrameArgs& args) {
136   if (reporters_[PipelineStage::kBeginImplFrame]) {
137     // We need to use .get() below because operator<< in std::unique_ptr is a
138     // C++20 feature.
139     DCHECK_NE(reporters_[PipelineStage::kBeginMainFrame].get(),
140               reporters_[PipelineStage::kBeginImplFrame].get());
141     DCHECK_EQ(reporters_[PipelineStage::kBeginImplFrame]->frame_id(),
142               args.frame_id);
143     reporters_[PipelineStage::kBeginImplFrame]->StartStage(
144         StageType::kSendBeginMainFrameToCommit, Now());
145     AdvanceReporterStage(PipelineStage::kBeginImplFrame,
146                          PipelineStage::kBeginMainFrame);
147   } else {
148     // In this case we have already submitted the ImplFrame, but we received
149     // beginMain frame before next BeginImplFrame (Not reached the ImplFrame
150     // deadline yet). So will start a new reporter at BeginMainFrame, and use
151     // the state(s) from the ImplFrame where necessary.
152     auto scrolling_thread = scrolling_thread_;
153     auto active_trackers = active_trackers_;
154     auto smooth_thread = GetSmoothThread();
155     if (args.frame_id == last_started_compositor_frame_.args.frame_id) {
156       // TODO(1277547): Instead of replacing all current information with the
157       // older information from when the impl-frame started, merge the two sets
158       // of information that makes sense.
159       scrolling_thread = last_started_compositor_frame_.scrolling_thread;
160       active_trackers = last_started_compositor_frame_.active_trackers;
161       smooth_thread = last_started_compositor_frame_.smooth_thread;
162     }
163     auto reporter = std::make_unique<CompositorFrameReporter>(
164         active_trackers, args, should_report_histograms_, smooth_thread,
165         scrolling_thread, layer_tree_host_id_, global_trackers_);
166     reporter->set_tick_clock(tick_clock_);
167     reporter->StartStage(StageType::kSendBeginMainFrameToCommit, Now());
168     reporters_[PipelineStage::kBeginMainFrame] = std::move(reporter);
169   }
170 }
171
172 void CompositorFrameReportingController::BeginMainFrameAborted(
173     const viz::BeginFrameId& id,
174     CommitEarlyOutReason reason) {
175   auto& reporter = reporters_[PipelineStage::kBeginMainFrame];
176   DCHECK(reporter);
177   DCHECK_EQ(reporter->frame_id(), id);
178   reporter->OnAbortBeginMainFrame(Now());
179
180   if (reason == CommitEarlyOutReason::FINISHED_NO_UPDATES)
181     DidNotProduceFrame(id, FrameSkippedReason::kNoDamage);
182 }
183
184 void CompositorFrameReportingController::WillCommit() {
185   DCHECK(reporters_[PipelineStage::kReadyToCommit]);
186   reporters_[PipelineStage::kReadyToCommit]->StartStage(StageType::kCommit,
187                                                         Now());
188 }
189
190 void CompositorFrameReportingController::DidCommit() {
191   DCHECK(reporters_[PipelineStage::kReadyToCommit]);
192   reporters_[PipelineStage::kReadyToCommit]->StartStage(
193       StageType::kEndCommitToActivation, Now());
194   AdvanceReporterStage(PipelineStage::kReadyToCommit, PipelineStage::kCommit);
195 }
196
197 void CompositorFrameReportingController::WillInvalidateOnImplSide() {
198   // Allows for activation without committing.
199   // TODO(alsan): Report latency of impl side invalidations.
200   next_activate_has_invalidation_ = true;
201 }
202
203 void CompositorFrameReportingController::WillActivate() {
204   DCHECK(reporters_[PipelineStage::kCommit] || next_activate_has_invalidation_);
205   if (!reporters_[PipelineStage::kCommit])
206     return;
207   reporters_[PipelineStage::kCommit]->StartStage(StageType::kActivation, Now());
208 }
209
210 void CompositorFrameReportingController::DidActivate() {
211   DCHECK(reporters_[PipelineStage::kCommit] || next_activate_has_invalidation_);
212   next_activate_has_invalidation_ = false;
213   if (!reporters_[PipelineStage::kCommit])
214     return;
215   reporters_[PipelineStage::kCommit]->StartStage(
216       StageType::kEndActivateToSubmitCompositorFrame, Now());
217   AdvanceReporterStage(PipelineStage::kCommit, PipelineStage::kActivate);
218 }
219
220 void CompositorFrameReportingController::DidSubmitCompositorFrame(
221     uint32_t frame_token,
222     base::TimeTicks submit_time,
223     const viz::BeginFrameId& current_frame_id,
224     const viz::BeginFrameId& last_activated_frame_id,
225     EventMetricsSet events_metrics,
226     bool has_missing_content) {
227   bool is_activated_frame_new =
228       (last_activated_frame_id != last_submitted_frame_id_);
229
230   // It is possible to submit a CompositorFrame containing outputs from two
231   // different begin-frames: an begin-main-frame that was blocked on the
232   // main-thread, and another one for the compositor thread.
233   std::unique_ptr<CompositorFrameReporter> main_reporter;
234   std::unique_ptr<CompositorFrameReporter> impl_reporter;
235
236   // If |is_activated_frame_new| is true, |main_reporter| is guaranteed to
237   // be set, and |impl_reporter| may or may not be set; otherwise,
238   // |impl_reporter| is guaranteed to be set, and |main_reporter| will not be
239   // set.
240   if (is_activated_frame_new) {
241     DCHECK_EQ(reporters_[PipelineStage::kActivate]->frame_id(),
242               last_activated_frame_id);
243     // The reporter in activate state can be submitted
244     main_reporter = std::move(reporters_[PipelineStage::kActivate]);
245     last_submitted_frame_id_ = last_activated_frame_id;
246   } else {
247     DCHECK(!reporters_[PipelineStage::kActivate]);
248   }
249
250   // |main_reporter| can be for a previous BeginFrameArgs (i.e. not for
251   // |current_frame_id|), in which case it is necessary to also report metrics
252   // for the reporter representing |current_frame_id|. Following are the
253   // possibilities:
254   //  1) the main-thread did not request any updates (i.e. a 'begin main frame'
255   //     was not issued). The reporter for |current_frame_id| should still be in
256   //     the 'impl frame' stage.
257   //  2) the 'begin main frame' was issued, but the main-thread did not have any
258   //     updates (i.e. the 'begin main frame' was aborted). The reporter for
259   //     |current_frame_id| should be in the 'main frame' stage, and it will
260   //     have been aborted.
261   //  3) main-thread is still processing 'begin main frame'. The reporter for
262   //     |current_frame_id| should be in either the 'main frame' or 'commit'
263   //     stage.
264   if (CanSubmitImplFrame(current_frame_id)) {
265     auto& reporter = reporters_[PipelineStage::kBeginImplFrame];
266     reporter->StartStage(StageType::kEndActivateToSubmitCompositorFrame,
267                          reporter->impl_frame_finish_time());
268     AdvanceReporterStage(PipelineStage::kBeginImplFrame,
269                          PipelineStage::kActivate);
270     impl_reporter = std::move(reporters_[PipelineStage::kActivate]);
271     CompositorFrameReporter* partial_update_decider =
272         GetOutstandingUpdatesFromMain(current_frame_id);
273     if (partial_update_decider)
274       impl_reporter->SetPartialUpdateDecider(partial_update_decider);
275   } else if (CanSubmitMainFrame(current_frame_id)) {
276     auto& reporter = reporters_[PipelineStage::kBeginMainFrame];
277     reporter->StartStage(StageType::kEndActivateToSubmitCompositorFrame,
278                          reporter->impl_frame_finish_time());
279     AdvanceReporterStage(PipelineStage::kBeginMainFrame,
280                          PipelineStage::kActivate);
281     impl_reporter = std::move(reporters_[PipelineStage::kActivate]);
282   } else {
283     auto reporter = RestoreReporterAtBeginImpl(current_frame_id);
284     // The method will return nullptr if Impl reporter has been submitted
285     // prior to BeginMainFrame.
286     if (reporter) {
287       reporter->StartStage(StageType::kEndActivateToSubmitCompositorFrame,
288                            reporter->impl_frame_finish_time());
289       impl_reporter = std::move(reporter);
290     }
291   }
292
293 #if DCHECK_IS_ON()
294   if (!events_metrics.main_event_metrics.empty()) {
295     DCHECK(main_reporter);
296   }
297
298   if (impl_reporter) {
299     DCHECK_EQ(impl_reporter->frame_id(), current_frame_id);
300     if (main_reporter) {
301       DCHECK_NE(main_reporter->frame_id(), current_frame_id);
302     }
303   }
304 #endif
305
306   // When |impl_reporter| does not exist, but there are still impl-side metrics,
307   // merge the main and impl metrics and pass the combined vector into
308   // |main_reporter|.
309   if (!impl_reporter && !events_metrics.impl_event_metrics.empty()) {
310     DCHECK(main_reporter);
311     // If there are impl events, there must be a reporter with
312     // |current_frame_id|.
313     DCHECK_EQ(main_reporter->frame_id(), current_frame_id);
314     events_metrics.main_event_metrics.reserve(
315         events_metrics.main_event_metrics.size() +
316         events_metrics.impl_event_metrics.size());
317     events_metrics.main_event_metrics.insert(
318         events_metrics.main_event_metrics.end(),
319         std::make_move_iterator(events_metrics.impl_event_metrics.begin()),
320         std::make_move_iterator(events_metrics.impl_event_metrics.end()));
321   }
322
323   if (main_reporter) {
324     main_reporter->StartStage(
325         StageType::kSubmitCompositorFrameToPresentationCompositorFrame,
326         submit_time);
327     main_reporter->AddEventsMetrics(
328         std::move(events_metrics.main_event_metrics));
329     main_reporter->set_has_missing_content(has_missing_content);
330     main_reporter->set_reporter_type_to_main();
331     submitted_compositor_frames_.emplace_back(frame_token,
332                                               std::move(main_reporter));
333   }
334
335   if (impl_reporter) {
336     impl_reporter->EnableCompositorOnlyReporting();
337     impl_reporter->StartStage(
338         StageType::kSubmitCompositorFrameToPresentationCompositorFrame,
339         submit_time);
340     impl_reporter->AddEventsMetrics(
341         std::move(events_metrics.impl_event_metrics));
342     impl_reporter->set_has_missing_content(has_missing_content);
343     impl_reporter->set_is_accompanied_by_main_thread_update(
344         is_activated_frame_new);
345     impl_reporter->set_reporter_type_to_impl();
346     submitted_compositor_frames_.emplace_back(frame_token,
347                                               std::move(impl_reporter));
348   }
349 }
350
351 void CompositorFrameReportingController::DidNotProduceFrame(
352     const viz::BeginFrameId& id,
353     FrameSkippedReason skip_reason) {
354   for (auto& stage_reporter : reporters_) {
355     if (stage_reporter && stage_reporter->frame_id() == id) {
356       // The reporter will be flagged and terminated when replaced by another
357       // reporter. The reporter is not terminated immediately here because it
358       // can still end up producing a frame afterwards. For example, if the
359       // compositor does not have any updates, and the main-thread takes too
360       // long, then DidNotProduceFrame() is called for the reporter in the
361       // BeginMain stage, but the main-thread can make updates, which can be
362       // submitted with the next frame.
363       stage_reporter->OnDidNotProduceFrame(skip_reason);
364       if (skip_reason == FrameSkippedReason::kWaitingOnMain)
365         SetPartialUpdateDeciderWhenWaitingOnMain(stage_reporter);
366
367       break;
368     }
369   }
370 }
371
372 void CompositorFrameReportingController::
373     SetPartialUpdateDeciderWhenWaitingOnMain(
374         std::unique_ptr<CompositorFrameReporter>& stage_reporter) {
375   // If the compositor has no updates, and the main-thread has not responded
376   // to the begin-main-frame yet, then depending on main thread having
377   // update or not this would be a NoFrameProduced or a DroppedFrame. To
378   // handle this case , keep the reporter for the main-thread, but recreate
379   // a reporter for the current frame and link it to the reporter it depends
380   // on.
381   auto reporter = RestoreReporterAtBeginImpl(stage_reporter->frame_id());
382   if (reporter) {
383     reporter->OnDidNotProduceFrame(FrameSkippedReason::kWaitingOnMain);
384     reporter->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
385                              Now());
386     stage_reporter->AdoptReporter(std::move(reporter));
387   } else {
388     // The stage_reporter in this case was waiting for main, so needs to
389     // be adopted by the reporter which is waiting on Main thread's work
390     CompositorFrameReporter* partial_update_decider =
391         GetOutstandingUpdatesFromMain(stage_reporter->frame_id());
392     if (partial_update_decider) {
393       stage_reporter->SetPartialUpdateDecider(partial_update_decider);
394       stage_reporter->OnDidNotProduceFrame(FrameSkippedReason::kWaitingOnMain);
395       stage_reporter->TerminateFrame(
396           FrameTerminationStatus::kDidNotProduceFrame, Now());
397       partial_update_decider->AdoptReporter(std::move(stage_reporter));
398     }
399   }
400 }
401
402 void CompositorFrameReportingController::TrackSwapTiming(
403     const viz::FrameTimingDetails& details) {
404   if (details.swap_timings.swap_start != base::TimeTicks()) {
405     if (latest_swap_times_.empty() ||
406         latest_swap_times_.back() < details.swap_timings.swap_start)
407       latest_swap_times_.push(details.swap_timings.swap_start);
408   }
409
410   // Making sure the queue would not keep growing in size.
411   DCHECK_LE(latest_swap_times_.size(), 10u);
412 }
413
414 void CompositorFrameReportingController::ReportMultipleSwaps(
415     base::TimeTicks begin_frame_time,
416     base::TimeDelta interval) {
417   while (!latest_swap_times_.empty() &&
418          latest_swap_times_.front() <= begin_frame_time - interval) {
419     latest_swap_times_.pop();
420   }
421
422   if (latest_swap_times_.empty())
423     return;
424
425   if (latest_swap_times_.size() > 1) {
426     base::TimeDelta swap_delta =
427         latest_swap_times_.back() - latest_swap_times_.front();
428
429     if (swap_delta < interval) {
430       UMA_HISTOGRAM_PERCENTAGE("GPU.MultipleSwapsDelta",
431                                swap_delta * 100.0 / interval);
432
433       const auto trace_track =
434           perfetto::Track(base::trace_event::GetNextGlobalTraceId());
435       TRACE_EVENT_BEGIN(kTraceCategory, "MultipleSwaps", trace_track,
436                         latest_swap_times_.front());
437       TRACE_EVENT_END(kTraceCategory, trace_track, latest_swap_times_.back());
438     }
439   }
440 }
441
442 void CompositorFrameReportingController::OnFinishImplFrame(
443     const viz::BeginFrameId& id) {
444   for (auto& reporter : reporters_) {
445     if (reporter && reporter->frame_id() == id) {
446       reporter->OnFinishImplFrame(Now());
447       return;
448     }
449   }
450 }
451
452 void CompositorFrameReportingController::DidPresentCompositorFrame(
453     uint32_t frame_token,
454     const viz::FrameTimingDetails& details) {
455   bool feedback_failed = details.presentation_feedback.failed();
456
457   if (!feedback_failed)
458     TrackSwapTiming(details);
459
460   for (auto submitted_frame = submitted_compositor_frames_.begin();
461        submitted_frame != submitted_compositor_frames_.end() &&
462        !viz::FrameTokenGT(submitted_frame->frame_token, frame_token);) {
463     bool is_earlier_frame = submitted_frame->frame_token != frame_token;
464
465     // If the presentation feedback is a failure, earlier frames should still be
466     // left in the queue as they still might end up being presented
467     // successfully. Skip to the next frame.
468     if (feedback_failed && is_earlier_frame) {
469       submitted_frame++;
470       continue;
471     }
472
473     auto termination_status = feedback_failed
474                                   ? FrameTerminationStatus::kDidNotPresentFrame
475                                   : FrameTerminationStatus::kPresentedFrame;
476
477     // If this is an earlier frame, presentation feedback has been successful
478     // which means this earlier frame should be considered dropped.
479     if (is_earlier_frame)
480       termination_status = FrameTerminationStatus::kDidNotPresentFrame;
481
482     auto& reporter = submitted_frame->reporter;
483     reporter->SetVizBreakdown(details);
484     reporter->TerminateFrame(termination_status,
485                              details.presentation_feedback.timestamp);
486
487     base::TimeDelta latency_prediction_deviation_threshold =
488         details.presentation_feedback.interval.is_zero()
489             ? kDefaultLatencyPredictionDeviationThreshold
490             : (details.presentation_feedback.interval) / 2;
491     switch (reporter->get_reporter_type()) {
492       case CompositorFrameReporter::ReporterType::kImpl:
493         reporter->CalculateCompositorLatencyPrediction(
494             previous_latency_predictions_impl_,
495             latency_prediction_deviation_threshold);
496         break;
497       case CompositorFrameReporter::ReporterType::kMain:
498         reporter->CalculateCompositorLatencyPrediction(
499             previous_latency_predictions_main_,
500             latency_prediction_deviation_threshold);
501         break;
502     }
503
504     if (termination_status == FrameTerminationStatus::kPresentedFrame) {
505       // If there are outstanding metrics from dropped frames older than this
506       // frame, this frame would be the first frame presented after those
507       // dropped frames. So, this frame is the one presenting updates from those
508       // frames to the user and should report metrics for them. Note that since
509       // reporters for submitted but dropped frames are terminated before any
510       // following frame being presented, all events metrics that should
511       // potentially be included in this presented frame are already in
512       // `events_metrics_from_dropped_frames_`.
513       for (auto it = events_metrics_from_dropped_frames_.begin();
514            it != events_metrics_from_dropped_frames_.end() &&
515            !(reporter->frame_id() < it->first);
516            it = events_metrics_from_dropped_frames_.erase(it)) {
517         reporter->AddEventsMetrics(std::move(it->second));
518       }
519
520       // TODO(crbug.com/1334827): Consider using a separate container to
521       // differentiate event predictions with and without a main dispatch stage.
522       reporter->CalculateEventLatencyPrediction(
523           event_latency_predictions_, latency_prediction_deviation_threshold);
524
525       // For presented frames, if `reporter` was cloned from another reporter,
526       // and the original reporter is still alive, then check whether the cloned
527       // reporter has a 'partial update decider'. It is still possible for the
528       // original reporter to terminate with 'no damage', and if that happens,
529       // then the cloned reporter's 'partial update' flag will need to be reset.
530       // To allow this to happen, keep the cloned reporter alive, and hand over
531       // its ownership to the original reporter, so that the cloned reporter
532       // stays alive until the original reporter is terminated, and the cloned
533       // reporter's 'partial update' flag can be unset if necessary. This is not
534       // necessary for frames with failed presentation as we can say for sure
535       // that they are dropped and nothing will change their fate.
536       if (CompositorFrameReporter* orig_reporter =
537               reporter->partial_update_decider()) {
538         orig_reporter->AdoptReporter(std::move(reporter));
539       }
540     } else {
541       // If the frame didn't end up being presented, keep its metrics around to
542       // be reported with the first following presented frame.
543       auto reporter_events_metrics = reporter->TakeEventsMetrics();
544       if (!reporter_events_metrics.empty()) {
545         auto& frame_events_metrics =
546             events_metrics_from_dropped_frames_[reporter->frame_id()];
547         frame_events_metrics.insert(
548             frame_events_metrics.end(),
549             std::make_move_iterator(reporter_events_metrics.begin()),
550             std::make_move_iterator(reporter_events_metrics.end()));
551       }
552     }
553
554     if (feedback_failed) {
555       // When feedback is for a failed presentation, `submitted_frame` is not
556       // necessarily in the front of the queue. We will reach here only once per
557       // did-present; so, we will have 1 operation of O(n) complexity (n is the
558       // number of previous frames).
559       submitted_frame = submitted_compositor_frames_.erase(submitted_frame);
560     } else {
561       // When feedback is for a successful presentation, `submitted_frame` is in
562       // the front of the queue; so, we will have n operations of O(1)
563       // complexity for a did-present (n is the number of previous frames).
564       // `pop_front()` function is used here to shrink the queue when necessary
565       // to avoid unnecessary memory usage over time.
566       DCHECK_EQ(submitted_frame->frame_token,
567                 submitted_compositor_frames_.front().frame_token);
568       submitted_compositor_frames_.pop_front();
569       submitted_frame = submitted_compositor_frames_.begin();
570     }
571   }
572 }
573
574 void CompositorFrameReportingController::OnStoppedRequestingBeginFrames() {
575   // If the client stopped requesting begin-frames, that means the begin-frames
576   // currently being handled are no longer expected to produce any
577   // compositor-frames. So terminate the reporters.
578   auto now = Now();
579   for (int i = 0; i < PipelineStage::kNumPipelineStages; ++i) {
580     if (reporters_[i]) {
581       reporters_[i]->OnDidNotProduceFrame(FrameSkippedReason::kNoDamage);
582       reporters_[i]->TerminateFrame(FrameTerminationStatus::kDidNotProduceFrame,
583                                     now);
584     }
585   }
586   last_started_compositor_frame_ = {};
587 }
588
589 void CompositorFrameReportingController::NotifyReadyToCommit(
590     std::unique_ptr<BeginMainFrameMetrics> details) {
591   DCHECK(reporters_[PipelineStage::kBeginMainFrame]);
592   reporters_[PipelineStage::kBeginMainFrame]->SetBlinkBreakdown(
593       std::move(details), begin_main_frame_start_time_);
594   AdvanceReporterStage(PipelineStage::kBeginMainFrame,
595                        PipelineStage::kReadyToCommit);
596 }
597
598 void CompositorFrameReportingController::AddActiveTracker(
599     FrameSequenceTrackerType type) {
600   active_trackers_.set(static_cast<size_t>(type));
601 }
602
603 void CompositorFrameReportingController::RemoveActiveTracker(
604     FrameSequenceTrackerType type) {
605   active_trackers_.reset(static_cast<size_t>(type));
606   if (global_trackers_.dropped_frame_counter)
607     global_trackers_.dropped_frame_counter->ReportFrames();
608 }
609
610 void CompositorFrameReportingController::SetScrollingThread(
611     FrameInfo::SmoothEffectDrivingThread thread) {
612   scrolling_thread_ = thread;
613 }
614
615 void CompositorFrameReportingController::SetThreadAffectsSmoothness(
616     FrameInfo::SmoothEffectDrivingThread thread_type,
617     bool affects_smoothness) {
618   auto current_smooth_thread = GetSmoothThread();
619
620   if (thread_type == FrameInfo::SmoothEffectDrivingThread::kCompositor) {
621     is_compositor_thread_driving_smoothness_ = affects_smoothness;
622   } else {
623     DCHECK_EQ(thread_type, FrameInfo::SmoothEffectDrivingThread::kMain);
624     is_main_thread_driving_smoothness_ = affects_smoothness;
625   }
626
627   // keep the history for the last 3 seconds.
628   if (!smooth_thread_history_.empty()) {
629     auto expired_smooth_thread =
630         smooth_thread_history_.lower_bound(Now() - base::Seconds(3))--;
631     smooth_thread_history_.erase(smooth_thread_history_.begin(),
632                                  expired_smooth_thread);
633   }
634
635   // Only trackes the history if there is a change in smooth_thread_
636   if (current_smooth_thread != GetSmoothThread()) {
637     smooth_thread_history_.insert(std::make_pair(Now(), current_smooth_thread));
638   }
639 }
640
641 void CompositorFrameReportingController::AdvanceReporterStage(
642     PipelineStage start,
643     PipelineStage target) {
644   auto& reporter = reporters_[target];
645   if (reporter) {
646     auto termination_status = FrameTerminationStatus::kReplacedByNewReporter;
647     base::TimeTicks termination_time;
648     if (reporter->did_not_produce_frame()) {
649       termination_time = reporter->did_not_produce_frame_time();
650       termination_status = FrameTerminationStatus::kDidNotProduceFrame;
651     } else if (target == PipelineStage::kBeginMainFrame &&
652                reporter->did_abort_main_frame()) {
653       termination_time = reporter->main_frame_abort_time();
654     } else {
655       termination_time = Now();
656     }
657     reporter->TerminateFrame(termination_status, termination_time);
658   }
659   reporters_[target] = std::move(reporters_[start]);
660 }
661
662 bool CompositorFrameReportingController::CanSubmitImplFrame(
663     const viz::BeginFrameId& id) const {
664 #if DCHECK_IS_ON()
665   auto& reporter = reporters_[PipelineStage::kBeginImplFrame];
666   if (reporter) {
667     DCHECK_EQ(reporter->frame_id(), id);
668     DCHECK(reporter->did_finish_impl_frame());
669   }
670 #endif
671   return reporters_[PipelineStage::kBeginImplFrame].get() != nullptr;
672 }
673
674 bool CompositorFrameReportingController::CanSubmitMainFrame(
675     const viz::BeginFrameId& id) const {
676   if (!reporters_[PipelineStage::kBeginMainFrame])
677     return false;
678   auto& reporter = reporters_[PipelineStage::kBeginMainFrame];
679   return (reporter->frame_id() == id && reporter->did_finish_impl_frame() &&
680           reporter->did_abort_main_frame());
681 }
682
683 std::unique_ptr<CompositorFrameReporter>
684 CompositorFrameReportingController::RestoreReporterAtBeginImpl(
685     const viz::BeginFrameId& id) {
686   auto& main_reporter = reporters_[PipelineStage::kBeginMainFrame];
687   auto& ready_to_commit_reporter = reporters_[PipelineStage::kReadyToCommit];
688   auto& commit_reporter = reporters_[PipelineStage::kCommit];
689   if (main_reporter && main_reporter->frame_id() == id) {
690     DCHECK(!ready_to_commit_reporter ||
691            ready_to_commit_reporter->frame_id() != id);
692     DCHECK(!commit_reporter || commit_reporter->frame_id() != id);
693     return main_reporter->CopyReporterAtBeginImplStage();
694   }
695   if (ready_to_commit_reporter && ready_to_commit_reporter->frame_id() == id) {
696     DCHECK(!commit_reporter || commit_reporter->frame_id() != id);
697     return ready_to_commit_reporter->CopyReporterAtBeginImplStage();
698   }
699   if (commit_reporter && commit_reporter->frame_id() == id)
700     return commit_reporter->CopyReporterAtBeginImplStage();
701   return nullptr;
702 }
703
704 void CompositorFrameReportingController::SetUkmManager(UkmManager* manager) {
705   latency_ukm_reporter_->set_ukm_manager(manager);
706 }
707
708 CompositorFrameReporter::SmoothThread
709 CompositorFrameReportingController::GetSmoothThread() const {
710   if (is_main_thread_driving_smoothness_) {
711     return is_compositor_thread_driving_smoothness_ ? SmoothThread::kSmoothBoth
712                                                     : SmoothThread::kSmoothMain;
713   }
714
715   return is_compositor_thread_driving_smoothness_
716              ? SmoothThread::kSmoothCompositor
717              : SmoothThread::kSmoothNone;
718 }
719
720 CompositorFrameReporter::SmoothThread
721 CompositorFrameReportingController::GetSmoothThreadAtTime(
722     base::TimeTicks timestamp) const {
723   if (smooth_thread_history_.lower_bound(timestamp) ==
724       smooth_thread_history_.end())
725     return GetSmoothThread();
726   return smooth_thread_history_.lower_bound(timestamp)->second;
727 }
728
729 CompositorFrameReporter*
730 CompositorFrameReportingController::GetOutstandingUpdatesFromMain(
731     const viz::BeginFrameId& id) const {
732   // Any unterminated reporter in the 'main frame', or 'commit' stages, then
733   // that indicates some pending updates from the main thread.
734   {
735     const auto& reporter = reporters_[PipelineStage::kBeginMainFrame];
736     if (reporter && reporter->frame_id() < id &&
737         !reporter->did_abort_main_frame()) {
738       return reporter.get();
739     }
740   }
741   {
742     const auto& reporter = reporters_[PipelineStage::kReadyToCommit];
743     if (reporter && reporter->frame_id() < id &&
744         !reporter->did_abort_main_frame()) {
745       return reporter.get();
746     }
747   }
748   {
749     const auto& reporter = reporters_[PipelineStage::kCommit];
750     if (reporter && reporter->frame_id() < id) {
751       DCHECK(!reporter->did_abort_main_frame());
752       return reporter.get();
753     }
754   }
755   return nullptr;
756 }
757
758 void CompositorFrameReportingController::CreateReportersForDroppedFrames(
759     const viz::BeginFrameArgs& old_args,
760     const viz::BeginFrameArgs& new_args) const {
761   DCHECK_EQ(new_args.frame_id.source_id, old_args.frame_id.source_id);
762   DCHECK_GE(
763       new_args.frame_id.sequence_number - new_args.frames_throttled_since_last,
764       old_args.frame_id.sequence_number);
765   const uint32_t interval = new_args.frame_id.sequence_number -
766                             old_args.frame_id.sequence_number -
767                             new_args.frames_throttled_since_last;
768
769   // Up to 100 frames will be reported (100 closest frames to new_args).
770   const uint32_t kMaxFrameCount = 100;
771
772   // If there are more than 100 frames skipped, ignore them
773   if (interval > kMaxFrameCount)
774     return;
775
776   auto timestamp = old_args.frame_time + old_args.interval;
777   for (uint32_t i = 1; i < interval; ++i, timestamp += old_args.interval) {
778     auto args = viz::BeginFrameArgs::Create(
779         BEGINFRAME_FROM_HERE, old_args.frame_id.source_id,
780         old_args.frame_id.sequence_number + i, timestamp,
781         timestamp + old_args.interval, old_args.interval,
782         viz::BeginFrameArgs::NORMAL);
783     devtools_instrumentation::DidBeginFrame(
784         layer_tree_host_id_, args.frame_time, args.frame_id.sequence_number);
785     // ThreadType::kUnknown is used here for scrolling thread, because the
786     // frames reported here could have a scroll interaction active at their
787     // start time, but they were skipped and history of scrolling thread might
788     // change in the diff of start time and report time.
789     auto reporter = std::make_unique<CompositorFrameReporter>(
790         active_trackers_, args, should_report_histograms_,
791         GetSmoothThreadAtTime(timestamp),
792         FrameInfo::SmoothEffectDrivingThread::kUnknown, layer_tree_host_id_,
793         global_trackers_);
794     reporter->set_tick_clock(tick_clock_);
795     reporter->StartStage(StageType::kBeginImplFrameToSendBeginMainFrame,
796                          timestamp);
797     reporter->TerminateFrame(FrameTerminationStatus::kDidNotPresentFrame,
798                              args.deadline);
799     reporter->set_is_backfill(true);
800   }
801 }
802
803 void CompositorFrameReportingController::AddSortedFrame(
804     const viz::BeginFrameArgs& args,
805     const FrameInfo& frame_info) {
806   if (global_trackers_.frame_sequence_trackers) {
807     global_trackers_.frame_sequence_trackers->AddSortedFrame(args, frame_info);
808   }
809 }
810
811 void CompositorFrameReportingController::SetDroppedFrameCounter(
812     DroppedFrameCounter* counter) {
813   global_trackers_.dropped_frame_counter = counter;
814   if (counter) {
815     counter->SetSortedFrameCallback(
816         base::BindRepeating(&CompositorFrameReportingController::AddSortedFrame,
817                             base::Unretained(this)));
818   }
819 }
820
821 }  // namespace cc