[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / metrics / average_lag_tracking_manager.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/average_lag_tracking_manager.h"
6
7 #include <algorithm>
8 #include <memory>
9
10 #include "components/viz/common/frame_timing_details.h"
11 #include "components/viz/common/quads/compositor_frame_metadata.h"
12
13 namespace cc {
14 namespace {
15
16 void AddEventInfoFromEventMetricsList(
17     const EventMetrics::List& events_metrics,
18     std::vector<AverageLagTracker::EventInfo>* event_infos) {
19   for (const std::unique_ptr<EventMetrics>& event_metrics : events_metrics) {
20     EventMetrics::EventType type = event_metrics->type();
21     if (type != EventMetrics::EventType::kFirstGestureScrollUpdate &&
22         type != EventMetrics::EventType::kGestureScrollUpdate) {
23       continue;
24     }
25
26     auto* scroll_update_metrics = event_metrics->AsScrollUpdate();
27     DCHECK(scroll_update_metrics);
28     event_infos->emplace_back(
29         scroll_update_metrics->delta(),
30         scroll_update_metrics->predicted_delta(),
31         scroll_update_metrics->last_timestamp(),
32         type == EventMetrics::EventType::kFirstGestureScrollUpdate
33             ? AverageLagTracker::EventType::ScrollBegin
34             : AverageLagTracker::EventType::ScrollUpdate);
35   }
36 }
37
38 }  // namespace
39
40 AverageLagTrackingManager::AverageLagTrackingManager() = default;
41
42 AverageLagTrackingManager::~AverageLagTrackingManager() {
43   // The map must contain only frames that haven't been presented (i.e. did not
44   // get a presentation feedback yet). Thus, at a given point in time, more than
45   // a handful (actually around 2) of frames without feedback is unexpected.
46   DCHECK_LE(frame_token_to_info_.size(), 20u);
47 }
48
49 void AverageLagTrackingManager::CollectScrollEventsFromFrame(
50     uint32_t frame_token,
51     const EventMetricsSet& events_metrics) {
52   std::vector<AverageLagTracker::EventInfo> event_infos;
53
54   // A scroll event can be handled either on the main or the compositor thread
55   // (not both). So, both lists of metrics from the main and the compositor
56   // thread might contain interesting scroll events and we should collect
57   // information about scroll events from both. We are not worried about
58   // ordering of the events at this point. If the frame is presented, events
59   // for the frame will be sorted and fed into `AverageLagTracker` in order.
60   AddEventInfoFromEventMetricsList(events_metrics.main_event_metrics,
61                                    &event_infos);
62   AddEventInfoFromEventMetricsList(events_metrics.impl_event_metrics,
63                                    &event_infos);
64
65   if (event_infos.size() > 0)
66     frame_token_to_info_.emplace_back(frame_token, std::move(event_infos));
67 }
68
69 void AverageLagTrackingManager::DidPresentCompositorFrame(
70     uint32_t frame_token,
71     const viz::FrameTimingDetails& frame_details) {
72   if (frame_details.presentation_feedback.failed()) {
73     // When presentation fails, remove the current frame from (potentially, the
74     // middle of) the queue; but, leave earlier frames in the queue as they
75     // still might end up being presented successfully.
76     for (auto submitted_frame = frame_token_to_info_.begin();
77          submitted_frame != frame_token_to_info_.end(); submitted_frame++) {
78       if (viz::FrameTokenGT(submitted_frame->first, frame_token))
79         break;
80       if (submitted_frame->first == frame_token) {
81         frame_token_to_info_.erase(submitted_frame);
82         break;
83       }
84     }
85     return;
86   }
87
88   // When presentation succeeds, consider earlier frames as failed and remove
89   // them from the front of the queue. Then take the list of events for the
90   // current frame and remove it from the front of the queue, too.
91   std::vector<AverageLagTracker::EventInfo> infos;
92   while (!frame_token_to_info_.empty()) {
93     auto& submitted_frame = frame_token_to_info_.front();
94     if (viz::FrameTokenGT(submitted_frame.first, frame_token))
95       break;
96     if (submitted_frame.first == frame_token)
97       infos = std::move(submitted_frame.second);
98     frame_token_to_info_.pop_front();
99   }
100
101   // If there is no event, there is nothing to report.
102   if (infos.empty())
103     return;
104
105   DCHECK(!frame_details.swap_timings.is_null());
106
107   // AverageLagTracker expects events' info to be in ascending order.
108   std::sort(infos.begin(), infos.end(),
109             [](const AverageLagTracker::EventInfo& a,
110                const AverageLagTracker::EventInfo& b) {
111               return a.event_timestamp < b.event_timestamp;
112             });
113
114   for (AverageLagTracker::EventInfo& info : infos) {
115     info.finish_timestamp = frame_details.presentation_feedback.timestamp;
116     lag_tracker_.AddScrollEventInFrame(info);
117   }
118 }
119
120 void AverageLagTrackingManager::Clear() {
121   frame_token_to_info_.clear();
122 }
123
124 }  // namespace cc