[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / frame_sequence_tracker_collection.cc
1 // Copyright 2020 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/frame_sequence_tracker_collection.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "base/containers/contains.h"
11 #include "base/containers/cxx20_erase.h"
12 #include "base/memory/ptr_util.h"
13 #include "cc/metrics/compositor_frame_reporting_controller.h"
14 #include "cc/metrics/frame_sequence_tracker.h"
15 #include "cc/metrics/throughput_ukm_reporter.h"
16
17 namespace cc {
18
19 namespace {
20
21 using ThreadType = FrameInfo::SmoothEffectDrivingThread;
22
23 bool IsScrollType(FrameSequenceTrackerType type) {
24   return type == FrameSequenceTrackerType::kTouchScroll ||
25          type == FrameSequenceTrackerType::kWheelScroll ||
26          type == FrameSequenceTrackerType::kScrollbarScroll;
27 }
28
29 }  // namespace
30
31 FrameSequenceTrackerCollection::FrameSequenceTrackerCollection(
32     bool is_single_threaded,
33     CompositorFrameReportingController* compositor_frame_reporting_controller)
34     : is_single_threaded_(is_single_threaded),
35       compositor_frame_reporting_controller_(
36           compositor_frame_reporting_controller) {}
37
38 FrameSequenceTrackerCollection::~FrameSequenceTrackerCollection() {
39   CleanUp();
40   frame_trackers_.clear();
41   removal_trackers_.clear();
42   custom_frame_trackers_.clear();
43   accumulated_metrics_.clear();
44 }
45
46 FrameSequenceTracker* FrameSequenceTrackerCollection::StartSequenceInternal(
47     FrameSequenceTrackerType type,
48     FrameInfo::SmoothEffectDrivingThread scrolling_thread) {
49   DCHECK_NE(FrameSequenceTrackerType::kCustom, type);
50   if (is_single_threaded_)
51     return nullptr;
52   auto key = std::make_pair(type, scrolling_thread);
53   if (frame_trackers_.contains(key))
54     return frame_trackers_[key].get();
55
56   auto tracker = base::WrapUnique(
57       new FrameSequenceTracker(type, throughput_ukm_reporter_.get()));
58   frame_trackers_[key] = std::move(tracker);
59
60   if (compositor_frame_reporting_controller_)
61     compositor_frame_reporting_controller_->AddActiveTracker(type);
62
63   auto* metrics = frame_trackers_[key]->metrics();
64   if (accumulated_metrics_.contains(key)) {
65     metrics->AdoptTrace(accumulated_metrics_[key].get());
66   }
67   if (IsScrollType(type)) {
68     DCHECK_NE(scrolling_thread, ThreadType::kUnknown);
69     metrics->SetScrollingThread(scrolling_thread);
70     compositor_frame_reporting_controller_->SetScrollingThread(
71         scrolling_thread);
72   }
73
74   if (metrics->GetEffectiveThread() == ThreadType::kCompositor) {
75     if (compositor_frame_reporting_controller_ &&
76         compositor_thread_driving_smoothness_ == 0) {
77       compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
78           ThreadType::kCompositor, true);
79     }
80     ++compositor_thread_driving_smoothness_;
81   } else {
82     DCHECK_EQ(metrics->GetEffectiveThread(), ThreadType::kMain);
83     if (compositor_frame_reporting_controller_ &&
84         main_thread_driving_smoothness_ == 0) {
85       compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
86           ThreadType::kMain, true);
87     }
88     ++main_thread_driving_smoothness_;
89   }
90   return frame_trackers_[key].get();
91 }
92
93 FrameSequenceTracker* FrameSequenceTrackerCollection::StartSequence(
94     FrameSequenceTrackerType type) {
95   DCHECK(!IsScrollType(type));
96   return StartSequenceInternal(type, ThreadType::kUnknown);
97 }
98
99 FrameSequenceTracker* FrameSequenceTrackerCollection::StartScrollSequence(
100     FrameSequenceTrackerType type,
101     FrameInfo::SmoothEffectDrivingThread scrolling_thread) {
102   DCHECK(IsScrollType(type));
103   return StartSequenceInternal(type, scrolling_thread);
104 }
105
106 void FrameSequenceTrackerCollection::CleanUp() {
107   for (auto& tracker : frame_trackers_)
108     tracker.second->CleanUp();
109   for (auto& tracker : custom_frame_trackers_)
110     tracker.second->CleanUp();
111   for (auto& tracker : removal_trackers_)
112     tracker->CleanUp();
113   for (auto& metric : accumulated_metrics_)
114     metric.second->ReportLeftoverData();
115   throughput_ukm_reporter_ = nullptr;
116 }
117
118 void FrameSequenceTrackerCollection::StopSequence(
119     FrameSequenceTrackerType type) {
120   DCHECK_NE(FrameSequenceTrackerType::kCustom, type);
121
122   auto key = std::make_pair(type, ThreadType::kUnknown);
123   if (IsScrollType(type)) {
124     compositor_frame_reporting_controller_->SetScrollingThread(
125         ThreadType::kUnknown);
126     key = std::make_pair(type, ThreadType::kCompositor);
127     if (!frame_trackers_.contains(key))
128       key = std::make_pair(type, ThreadType::kMain);
129   }
130
131   if (!frame_trackers_.contains(key))
132     return;
133
134   auto tracker = std::move(frame_trackers_[key]);
135   if (compositor_frame_reporting_controller_) {
136     compositor_frame_reporting_controller_->RemoveActiveTracker(
137         tracker->type());
138   }
139
140   if (tracker->metrics()->GetEffectiveThread() == ThreadType::kCompositor) {
141     DCHECK_GT(compositor_thread_driving_smoothness_, 0u);
142     --compositor_thread_driving_smoothness_;
143     if (compositor_frame_reporting_controller_ &&
144         compositor_thread_driving_smoothness_ == 0) {
145       compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
146           ThreadType::kCompositor, false);
147     }
148   } else {
149     DCHECK_GT(main_thread_driving_smoothness_, 0u);
150     --main_thread_driving_smoothness_;
151     if (compositor_frame_reporting_controller_ &&
152         main_thread_driving_smoothness_ == 0) {
153       compositor_frame_reporting_controller_->SetThreadAffectsSmoothness(
154           ThreadType::kMain, false);
155     }
156   }
157
158   frame_trackers_.erase(key);
159   tracker->ScheduleTerminate();
160   removal_trackers_.push_back(std::move(tracker));
161   DestroyTrackers();
162 }
163
164 void FrameSequenceTrackerCollection::StartCustomSequence(int sequence_id) {
165   DCHECK(!base::Contains(custom_frame_trackers_, sequence_id));
166
167   // base::Unretained() is safe here because |this| owns FrameSequenceTracker
168   // and FrameSequenceMetrics.
169   custom_frame_trackers_[sequence_id] =
170       base::WrapUnique(new FrameSequenceTracker(
171           sequence_id,
172           base::BindOnce(
173               &FrameSequenceTrackerCollection::AddCustomTrackerResult,
174               base::Unretained(this), sequence_id)));
175 }
176
177 void FrameSequenceTrackerCollection::StopCustomSequence(int sequence_id) {
178   auto it = custom_frame_trackers_.find(sequence_id);
179   // This happens when an animation is aborted before starting.
180   if (it == custom_frame_trackers_.end())
181     return;
182
183   std::unique_ptr<FrameSequenceTracker> tracker = std::move(it->second);
184   custom_frame_trackers_.erase(it);
185   tracker->ScheduleTerminate();
186   removal_trackers_.push_back(std::move(tracker));
187   DestroyTrackers();
188 }
189
190 void FrameSequenceTrackerCollection::ClearAll() {
191   frame_trackers_.clear();
192   custom_frame_trackers_.clear();
193   removal_trackers_.clear();
194 }
195
196 void FrameSequenceTrackerCollection::NotifyBeginImplFrame(
197     const viz::BeginFrameArgs& args) {
198   RecreateTrackers(args);
199   for (auto& tracker : frame_trackers_)
200     tracker.second->ReportBeginImplFrame(args);
201   for (auto& tracker : custom_frame_trackers_)
202     tracker.second->ReportBeginImplFrame(args);
203 }
204
205 void FrameSequenceTrackerCollection::NotifyBeginMainFrame(
206     const viz::BeginFrameArgs& args) {
207   for (auto& tracker : frame_trackers_)
208     tracker.second->ReportBeginMainFrame(args);
209   for (auto& tracker : custom_frame_trackers_)
210     tracker.second->ReportBeginMainFrame(args);
211 }
212
213 void FrameSequenceTrackerCollection::NotifyMainFrameProcessed(
214     const viz::BeginFrameArgs& args) {
215   for (auto& tracker : frame_trackers_)
216     tracker.second->ReportMainFrameProcessed(args);
217   for (auto& tracker : custom_frame_trackers_)
218     tracker.second->ReportMainFrameProcessed(args);
219 }
220
221 void FrameSequenceTrackerCollection::NotifyImplFrameCausedNoDamage(
222     const viz::BeginFrameAck& ack) {
223   for (auto& tracker : frame_trackers_)
224     tracker.second->ReportImplFrameCausedNoDamage(ack);
225   for (auto& tracker : custom_frame_trackers_)
226     tracker.second->ReportImplFrameCausedNoDamage(ack);
227
228   // Removal trackers continue to process any frames which they started
229   // observing.
230   for (auto& tracker : removal_trackers_)
231     tracker->ReportImplFrameCausedNoDamage(ack);
232 }
233
234 void FrameSequenceTrackerCollection::NotifyMainFrameCausedNoDamage(
235     const viz::BeginFrameArgs& args,
236     bool aborted) {
237   for (auto& tracker : frame_trackers_)
238     tracker.second->ReportMainFrameCausedNoDamage(args, aborted);
239   for (auto& tracker : custom_frame_trackers_)
240     tracker.second->ReportMainFrameCausedNoDamage(args, aborted);
241 }
242
243 void FrameSequenceTrackerCollection::NotifyPauseFrameProduction() {
244   for (auto& tracker : frame_trackers_)
245     tracker.second->PauseFrameProduction();
246   for (auto& tracker : custom_frame_trackers_)
247     tracker.second->PauseFrameProduction();
248 }
249
250 void FrameSequenceTrackerCollection::NotifySubmitFrame(
251     uint32_t frame_token,
252     bool has_missing_content,
253     const viz::BeginFrameAck& ack,
254     const viz::BeginFrameArgs& origin_args) {
255   for (auto& tracker : frame_trackers_) {
256     tracker.second->ReportSubmitFrame(frame_token, has_missing_content, ack,
257                                       origin_args);
258   }
259   for (auto& tracker : custom_frame_trackers_) {
260     tracker.second->ReportSubmitFrame(frame_token, has_missing_content, ack,
261                                       origin_args);
262   }
263
264   // Removal trackers continue to process any frames which they started
265   // observing.
266   for (auto& tracker : removal_trackers_) {
267     tracker->ReportSubmitFrame(frame_token, has_missing_content, ack,
268                                origin_args);
269   }
270
271   // TODO(crbug.com/1072482): find a proper way to terminate a tracker. Please
272   // refer to details in FrameSequenceTracker::ReportSubmitFrame
273   DestroyTrackers();
274 }
275
276 void FrameSequenceTrackerCollection::NotifyFrameEnd(
277     const viz::BeginFrameArgs& args,
278     const viz::BeginFrameArgs& main_args) {
279   for (auto& tracker : frame_trackers_)
280     tracker.second->ReportFrameEnd(args, main_args);
281   for (auto& tracker : custom_frame_trackers_)
282     tracker.second->ReportFrameEnd(args, main_args);
283
284   // Removal trackers continue to process any frames which they started
285   // observing.
286   for (auto& tracker : removal_trackers_)
287     tracker->ReportFrameEnd(args, main_args);
288   DestroyTrackers();
289 }
290
291 void FrameSequenceTrackerCollection::NotifyFramePresented(
292     uint32_t frame_token,
293     const gfx::PresentationFeedback& feedback) {
294   for (auto& tracker : frame_trackers_)
295     tracker.second->ReportFramePresented(frame_token, feedback);
296   for (auto& tracker : custom_frame_trackers_)
297     tracker.second->ReportFramePresented(frame_token, feedback);
298   for (auto& tracker : removal_trackers_)
299     tracker->ReportFramePresented(frame_token, feedback);
300
301   DestroyTrackers();
302 }
303
304 void FrameSequenceTrackerCollection::DestroyTrackers() {
305   for (auto& tracker : removal_trackers_) {
306     if (tracker->termination_status() ==
307         FrameSequenceTracker::TerminationStatus::kReadyForTermination) {
308       // The tracker is ready to be terminated.
309       // For non kCustom typed trackers, take the metrics from the tracker.
310       // merge with any outstanding metrics from previous trackers of the same
311       // type. If there are enough frames to report the metrics, then report the
312       // metrics and destroy it. Otherwise, retain it to be merged with
313       // follow-up sequences.
314       // For kCustom typed trackers, |metrics| invokes AddCustomTrackerResult
315       // on its destruction, which add its data to |custom_tracker_results_|
316       // to be picked up by caller.
317       if (tracker->metrics() &&
318           tracker->type() == FrameSequenceTrackerType::kCustom)
319         continue;
320       auto metrics = tracker->TakeMetrics();
321
322       auto key = std::make_pair(metrics->type(), metrics->GetEffectiveThread());
323       if (accumulated_metrics_.contains(key)) {
324         metrics->Merge(std::move(accumulated_metrics_[key]));
325         accumulated_metrics_.erase(key);
326       }
327
328       if (metrics->HasEnoughDataForReporting())
329         metrics->ReportMetrics();
330       if (metrics->HasDataLeftForReporting())
331         accumulated_metrics_[key] = std::move(metrics);
332     }
333   }
334
335   base::EraseIf(
336       removal_trackers_,
337       [](const std::unique_ptr<FrameSequenceTracker>& tracker) {
338         return tracker->termination_status() ==
339                FrameSequenceTracker::TerminationStatus::kReadyForTermination;
340       });
341 }
342
343 void FrameSequenceTrackerCollection::RecreateTrackers(
344     const viz::BeginFrameArgs& args) {
345   std::vector<std::pair<FrameSequenceTrackerType, ThreadType>>
346       recreate_trackers;
347   for (const auto& tracker : frame_trackers_) {
348     if (tracker.second->ShouldReportMetricsNow(args))
349       recreate_trackers.push_back(tracker.first);
350   }
351
352   for (const auto& key : recreate_trackers) {
353     DCHECK(frame_trackers_[key]);
354     auto tracker_type = key.first;
355     ThreadType thread_type = key.second;
356
357     // StopSequence put the tracker in the |removal_trackers_|, which will
358     // report its throughput data when its frame is presented.
359     StopSequence(tracker_type);
360
361     // The frame sequence is still active, so create a new tracker to keep
362     // tracking this sequence.
363     if (thread_type != FrameInfo::SmoothEffectDrivingThread::kUnknown) {
364       DCHECK(IsScrollType(tracker_type));
365       StartScrollSequence(tracker_type, thread_type);
366     } else {
367       StartSequence(tracker_type);
368     }
369   }
370 }
371
372 ActiveFrameSequenceTrackers
373 FrameSequenceTrackerCollection::FrameSequenceTrackerActiveTypes() const {
374   ActiveFrameSequenceTrackers encoded_types = 0;
375   for (const auto& key : frame_trackers_) {
376     auto thread_type = key.first.first;
377     encoded_types |= static_cast<ActiveFrameSequenceTrackers>(
378         1 << static_cast<unsigned>(thread_type));
379   }
380   return encoded_types;
381 }
382
383 FrameSequenceTracker*
384 FrameSequenceTrackerCollection::GetRemovalTrackerForTesting(
385     FrameSequenceTrackerType type) {
386   for (const auto& tracker : removal_trackers_)
387     if (tracker->type() == type)
388       return tracker.get();
389   return nullptr;
390 }
391
392 void FrameSequenceTrackerCollection::SetUkmManager(UkmManager* manager) {
393   DCHECK(frame_trackers_.empty());
394   if (manager)
395     throughput_ukm_reporter_ = std::make_unique<ThroughputUkmReporter>(manager);
396   else
397     throughput_ukm_reporter_ = nullptr;
398 }
399
400 void FrameSequenceTrackerCollection::AddCustomTrackerResult(
401     int custom_sequence_id,
402     const FrameSequenceMetrics::CustomReportData& data) {
403   DCHECK(custom_tracker_results_added_callback_);
404
405   CustomTrackerResults results;
406   results[custom_sequence_id] = data;
407   custom_tracker_results_added_callback_.Run(results);
408 }
409
410 void FrameSequenceTrackerCollection::AddSortedFrame(
411     const viz::BeginFrameArgs& args,
412     const FrameInfo& frame_info) {
413   for (auto& tracker : frame_trackers_)
414     tracker.second->AddSortedFrame(args, frame_info);
415   for (auto& tracker : custom_frame_trackers_)
416     tracker.second->AddSortedFrame(args, frame_info);
417 }
418
419 }  // namespace cc