1 // Copyright 2020 The Chromium Authors. All rights reserved.
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_FRAME_SEQUENCE_METRICS_H_
6 #define CC_METRICS_FRAME_SEQUENCE_METRICS_H_
7 
8 #include <memory>
9 
10 #include "base/callback.h"
11 #include "base/optional.h"
12 #include "base/trace_event/traced_value.h"
13 #include "cc/cc_export.h"
14 
15 namespace cc {
16 class ThroughputUkmReporter;
17 class JankMetrics;
18 
19 enum class FrameSequenceTrackerType {
20   // Used as an enum for metrics. DO NOT reorder or delete values. Rather,
21   // add them at the end and increment kMaxType.
22   kCompositorAnimation = 0,
23   kMainThreadAnimation = 1,
24   kPinchZoom = 2,
25   kRAF = 3,
26   kTouchScroll = 4,
27   kVideo = 6,
28   kWheelScroll = 7,
29   kScrollbarScroll = 8,
30   kCustom = 9,  // Note that the metrics for kCustom are not reported on UMA,
31                 // and instead are dispatched back to the LayerTreeHostClient.
32   kCanvasAnimation = 10,
33   kJSAnimation = 11,
34   kMaxType
35 };
36 
37 class CC_EXPORT FrameSequenceMetrics {
38  public:
39   FrameSequenceMetrics(FrameSequenceTrackerType type,
40                        ThroughputUkmReporter* ukm_reporter);
41   ~FrameSequenceMetrics();
42 
43   FrameSequenceMetrics(const FrameSequenceMetrics&) = delete;
44   FrameSequenceMetrics& operator=(const FrameSequenceMetrics&) = delete;
45 
46   enum class ThreadType { kMain, kCompositor, kUnknown };
47 
48   struct ThroughputData {
49     static std::unique_ptr<base::trace_event::TracedValue> ToTracedValue(
50         const ThroughputData& impl,
51         const ThroughputData& main,
52         ThreadType effective_thred);
53 
54     static bool CanReportHistogram(FrameSequenceMetrics* metrics,
55                                    ThreadType thread_type,
56                                    const ThroughputData& data);
57 
58     // Returns the dropped throughput in percent
59     static int ReportDroppedFramePercentHistogram(FrameSequenceMetrics* metrics,
60                                                   ThreadType thread_type,
61                                                   int metric_index,
62                                                   const ThroughputData& data);
63 
64     // Returns the missed deadline throughput in percent
65     static int ReportMissedDeadlineFramePercentHistogram(
66         FrameSequenceMetrics* metrics,
67         ThreadType thread_type,
68         int metric_index,
69         const ThroughputData& data);
70 
MergeThroughputData71     void Merge(const ThroughputData& data) {
72       frames_expected += data.frames_expected;
73       frames_produced += data.frames_produced;
74       frames_ontime += data.frames_ontime;
75 #if DCHECK_IS_ON()
76       frames_processed += data.frames_processed;
77       frames_received += data.frames_received;
78 #endif
79     }
80 
DroppedFramePercentThroughputData81     int DroppedFramePercent() const {
82       if (frames_expected == 0)
83         return 0;
84       return std::ceil(100 * (frames_expected - frames_produced) /
85                        static_cast<double>(frames_expected));
86     }
87 
MissedDeadlineFramePercentThroughputData88     int MissedDeadlineFramePercent() const {
89       if (frames_produced == 0)
90         return 0;
91       return std::ceil(100 * (frames_produced - frames_ontime) /
92                        static_cast<double>(frames_produced));
93     }
94 
95     // Tracks the number of frames that were expected to be shown during this
96     // frame-sequence.
97     uint32_t frames_expected = 0;
98 
99     // Tracks the number of frames that were actually presented to the user
100     // during this frame-sequence.
101     uint32_t frames_produced = 0;
102 
103     // Tracks the number of frames that were actually presented to the user
104     // that didn't miss the vsync deadline during this frame-sequence.
105     uint32_t frames_ontime = 0;
106 
107 #if DCHECK_IS_ON()
108     // Tracks the number of frames that is either submitted or reported as no
109     // damage.
110     uint32_t frames_processed = 0;
111 
112     // Tracks the number of begin-frames that are received.
113     uint32_t frames_received = 0;
114 #endif
115   };
116 
117   void SetScrollingThread(ThreadType thread);
118 
119   struct CustomReportData {
120     uint32_t frames_expected = 0;
121     uint32_t frames_produced = 0;
122     uint32_t jank_count = 0;
123   };
124   using CustomReporter = base::OnceCallback<void(const CustomReportData& data)>;
125   // Sets reporter callback for kCustom typed sequence.
126   void SetCustomReporter(CustomReporter custom_reporter);
127 
128   // Returns the 'effective thread' for the metrics (i.e. the thread most
129   // relevant for this metric).
130   ThreadType GetEffectiveThread() const;
131 
132   void Merge(std::unique_ptr<FrameSequenceMetrics> metrics);
133   bool HasEnoughDataForReporting() const;
134   bool HasDataLeftForReporting() const;
135   // Report related metrics: throughput, checkboarding...
136   void ReportMetrics();
137 
impl_throughput()138   ThroughputData& impl_throughput() { return impl_throughput_; }
main_throughput()139   ThroughputData& main_throughput() { return main_throughput_; }
add_checkerboarded_frames(int64_t frames)140   void add_checkerboarded_frames(int64_t frames) {
141     frames_checkerboarded_ += frames;
142   }
frames_checkerboarded()143   uint32_t frames_checkerboarded() const { return frames_checkerboarded_; }
144 
type()145   FrameSequenceTrackerType type() const { return type_; }
ukm_reporter()146   ThroughputUkmReporter* ukm_reporter() const {
147     return throughput_ukm_reporter_;
148   }
149 
150   // Must be called before destructor.
151   void ReportLeftoverData();
152 
153   void AdoptTrace(FrameSequenceMetrics* adopt_from);
154   void AdvanceTrace(base::TimeTicks timestamp);
155 
156   void ComputeJank(FrameSequenceMetrics::ThreadType thread_type,
157                    uint32_t frame_token,
158                    base::TimeTicks presentation_time,
159                    base::TimeDelta frame_interval);
160 
161   void NotifySubmitForJankReporter(FrameSequenceMetrics::ThreadType thread_type,
162                                    uint32_t frame_token,
163                                    uint32_t sequence_number);
164 
165   void NotifyNoUpdateForJankReporter(
166       FrameSequenceMetrics::ThreadType thread_type,
167       uint32_t sequence_number,
168       base::TimeDelta frame_interval);
169 
170  private:
171   const FrameSequenceTrackerType type_;
172 
173   // Tracks some data to generate useful trace events.
174   struct TraceData {
175     explicit TraceData(FrameSequenceMetrics* metrics);
176     ~TraceData();
177     FrameSequenceMetrics* metrics;
178     base::TimeTicks last_timestamp = base::TimeTicks::Now();
179     int frame_count = 0;
180     bool enabled = false;
181     void* trace_id = nullptr;
182 
183     void Advance(base::TimeTicks new_timestamp);
184     void Terminate();
185   } trace_data_{this};
186 
187   // Pointer to the reporter owned by the FrameSequenceTrackerCollection.
188   ThroughputUkmReporter* const throughput_ukm_reporter_;
189 
190   ThroughputData impl_throughput_;
191   ThroughputData main_throughput_;
192 
193   ThreadType scrolling_thread_ = ThreadType::kUnknown;
194 
195   // Tracks the number of produced frames that had some amount of
196   // checkerboarding, and how many frames showed such checkerboarded frames.
197   uint32_t frames_checkerboarded_ = 0;
198 
199   // Callback invoked to report metrics for kCustom typed sequence.
200   CustomReporter custom_reporter_;
201 
202   std::unique_ptr<JankMetrics> jank_reporter_;
203 };
204 
205 }  // namespace cc
206 
207 #endif  // CC_METRICS_FRAME_SEQUENCE_METRICS_H_
208