Avi Drissman | 3f7a9d8 | 2022-09-08 20:55:42 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 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_EVENT_METRICS_H_ |
| 6 | #define CC_METRICS_EVENT_METRICS_H_ |
| 7 | |
Omar Elmekkawy | 171cf7f | 2023-01-16 16:52:51 | [diff] [blame] | 8 | #include <cstdint> |
Mohsen Izadi | ebb5f217 | 2020-05-14 18:17:53 | [diff] [blame] | 9 | #include <memory> |
Arthur Sonzogni | 5bc3326c | 2024-02-29 19:39:05 | [diff] [blame] | 10 | #include <optional> |
Jasmine Xiong | dc63b5c | 2022-08-10 06:31:42 | [diff] [blame] | 11 | #include <string> |
Mohsen Izadi | b1efd8c | 2020-05-29 17:30:28 | [diff] [blame] | 12 | #include <vector> |
Mohsen Izadi | ebb5f217 | 2020-05-14 18:17:53 | [diff] [blame] | 13 | |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 14 | #include "base/memory/raw_ptr.h" |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 15 | #include "base/time/tick_clock.h" |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 16 | #include "base/time/time.h" |
Violetta Fedotova | 842ccc3 | 2023-02-03 20:59:53 | [diff] [blame] | 17 | #include "base/types/id_type.h" |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 18 | #include "cc/cc_export.h" |
Jonathan Ross | 86b8f3b1 | 2024-03-13 19:15:15 | [diff] [blame] | 19 | #include "components/viz/common/frame_sinks/begin_frame_args.h" |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 20 | #include "ui/events/types/event_type.h" |
Dave Tapuska | fb0ad6e | 2020-05-04 19:11:08 | [diff] [blame] | 21 | #include "ui/events/types/scroll_input_type.h" |
Violetta Fedotova | 842ccc3 | 2023-02-03 20:59:53 | [diff] [blame] | 22 | #include "ui/latency/latency_info.h" |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 23 | namespace cc { |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 24 | class PinchEventMetrics; |
| 25 | class ScrollEventMetrics; |
| 26 | class ScrollUpdateEventMetrics; |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 27 | |
Mohsen Izadi | d1d3a42 | 2020-03-18 03:17:22 | [diff] [blame] | 28 | // Data about an event used by CompositorFrameReporter in generating event |
| 29 | // latency metrics. |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 30 | class CC_EXPORT EventMetrics { |
| 31 | public: |
Mohsen Izadi | b8878bf7 | 2020-11-06 19:16:42 | [diff] [blame] | 32 | using List = std::vector<std::unique_ptr<EventMetrics>>; |
Violetta Fedotova | 842ccc3 | 2023-02-03 20:59:53 | [diff] [blame] | 33 | using TraceId = base::IdType64<class ui::LatencyInfo>; |
Sadrul Habib Chowdhury | 248bce43 | 2020-07-03 02:55:34 | [diff] [blame] | 34 | // Event types we are interested in. This list should be in the same order as |
| 35 | // values of EventLatencyEventType enum from enums.xml file. |
Mohsen Izadi | b1efd8c | 2020-05-29 17:30:28 | [diff] [blame] | 36 | enum class EventType { |
| 37 | kMousePressed, |
| 38 | kMouseReleased, |
| 39 | kMouseWheel, |
Avi Drissman | ae99ae28 | 2024-07-22 20:44:28 | [diff] [blame] | 40 | // TODO(crbug.com/40126863): Currently, all EventType::kKeyPressed events |
| 41 | // are reported under EventLatency.KeyPressed histogram. This includes both |
Alison Gale | 59c007a | 2024-04-20 03:05:40 | [diff] [blame] | 42 | // key-down and key-char events. Consider reporting them separately. |
Mohsen Izadi | b1efd8c | 2020-05-29 17:30:28 | [diff] [blame] | 43 | kKeyPressed, |
| 44 | kKeyReleased, |
| 45 | kTouchPressed, |
| 46 | kTouchReleased, |
| 47 | kTouchMoved, |
| 48 | kGestureScrollBegin, |
| 49 | kGestureScrollUpdate, |
| 50 | kGestureScrollEnd, |
Mohsen Izadi | ab4b0a4 | 2020-05-29 23:33:34 | [diff] [blame] | 51 | kGestureDoubleTap, |
| 52 | kGestureLongPress, |
| 53 | kGestureLongTap, |
| 54 | kGestureShowPress, |
| 55 | kGestureTap, |
| 56 | kGestureTapCancel, |
| 57 | kGestureTapDown, |
| 58 | kGestureTapUnconfirmed, |
| 59 | kGestureTwoFingerTap, |
Mohsen Izadi | 8c3ca22 | 2020-08-28 16:05:44 | [diff] [blame] | 60 | kFirstGestureScrollUpdate, |
Mohsen Izadi | 644b782 | 2020-12-04 03:18:37 | [diff] [blame] | 61 | kMouseDragged, |
Mohsen Izadi | 46b73c3 | 2021-02-19 19:27:47 | [diff] [blame] | 62 | kGesturePinchBegin, |
| 63 | kGesturePinchEnd, |
| 64 | kGesturePinchUpdate, |
Mohsen Izadi | 3e91767 | 2021-07-15 06:01:28 | [diff] [blame] | 65 | kInertialGestureScrollUpdate, |
Navin Ramsaroop | 2949bf15 | 2023-05-31 22:01:41 | [diff] [blame] | 66 | kMouseMoved, |
| 67 | kMaxValue = kMouseMoved, |
Mohsen Izadi | b1efd8c | 2020-05-29 17:30:28 | [diff] [blame] | 68 | }; |
| 69 | |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 70 | // Stages of event dispatch in different processes/threads. |
| 71 | enum class DispatchStage { |
| 72 | kGenerated, |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 73 | // 'kScrollsBlockingTouchDispatchedToRenderer' is used by Scroll events to |
| 74 | // understand when a corresponding TouchMove event arrived in the Browser |
| 75 | // Main. If the related TouchMove wasn't blocking, this stage field is not |
| 76 | // set. |
| 77 | kScrollsBlockingTouchDispatchedToRenderer, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 78 | kArrivedInBrowserMain, |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 79 | kArrivedInRendererCompositor, |
| 80 | kRendererCompositorStarted, |
| 81 | kRendererCompositorFinished, |
Mohsen Izadi | dafa8ac3 | 2020-12-09 15:45:19 | [diff] [blame] | 82 | kRendererMainStarted, |
| 83 | kRendererMainFinished, |
| 84 | kMaxValue = kRendererMainFinished, |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 85 | }; |
| 86 | |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 87 | static std::unique_ptr<EventMetrics> Create(ui::EventType type, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 88 | base::TimeTicks timestamp, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 89 | std::optional<TraceId> trace_id); |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 90 | |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 91 | // Returns a new instance if the event is of a type we are interested in. |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 92 | // Otherwise, returns `nullptr`. For scroll and pinch events, use the |
| 93 | // appropriate subcalss instead. |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 94 | static std::unique_ptr<EventMetrics> Create( |
| 95 | ui::EventType type, |
| 96 | base::TimeTicks timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 97 | base::TimeTicks arrived_in_browser_main_timestamp, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 98 | std::optional<TraceId> trace_id); |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 99 | |
| 100 | // Similar to `Create()` with an extra `base::TickClock` to use in tests. |
| 101 | static std::unique_ptr<EventMetrics> CreateForTesting( |
| 102 | ui::EventType type, |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 103 | base::TimeTicks timestamp, |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 104 | base::TimeTicks arrived_in_browser_main_timestamp, |
Kartar Singh | c1dbdfd | 2023-08-22 14:30:34 | [diff] [blame] | 105 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 106 | std::optional<TraceId> trace_id); |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 107 | |
| 108 | // Used to create an instance for an event generated based on an existing |
| 109 | // event. If the new event is of an interesting type, we expect that the |
| 110 | // existing event is also of an interesting type in which case `existing` is |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 111 | // not `nullptr` and timestamps (up to and including `last_dispatch_stage`) |
| 112 | // and tick clock from `existing` will be used for the new metrics object. If |
| 113 | // the new event is not an interesting one, return value would be `nullptr`. |
| 114 | // For scroll and pinch events, use the appropriate subclass instead. |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 115 | static std::unique_ptr<EventMetrics> CreateFromExisting( |
| 116 | ui::EventType type, |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 117 | DispatchStage last_dispatch_stage, |
| 118 | const EventMetrics* existing); |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 119 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 120 | virtual ~EventMetrics(); |
Mohsen Izadi | d1d3a42 | 2020-03-18 03:17:22 | [diff] [blame] | 121 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 122 | EventMetrics& operator=(const EventMetrics&) = delete; |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 123 | |
Mohsen Izadi | b1efd8c | 2020-05-29 17:30:28 | [diff] [blame] | 124 | EventType type() const { return type_; } |
| 125 | |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 126 | std::optional<TraceId> trace_id() const { return trace_id_; } |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 127 | |
Mohsen Izadi | b1efd8c | 2020-05-29 17:30:28 | [diff] [blame] | 128 | // Returns a string representing event type. |
Mohsen Izadi | d1d3a42 | 2020-03-18 03:17:22 | [diff] [blame] | 129 | const char* GetTypeName() const; |
Yichen | a8c4bd9 | 2022-10-27 00:47:00 | [diff] [blame] | 130 | static const char* GetTypeName(EventType type); |
Mohsen Izadi | d1d3a42 | 2020-03-18 03:17:22 | [diff] [blame] | 131 | |
Mohsen Izadi | 820e5e4 | 2023-01-12 02:00:07 | [diff] [blame] | 132 | // Returns custom histogram bucketing for the metric. If returns `nullopt`, |
| 133 | // default bucketing will be used. |
| 134 | struct HistogramBucketing { |
| 135 | base::TimeDelta min; |
| 136 | base::TimeDelta max; |
| 137 | size_t count; |
| 138 | const char* version_suffix; |
| 139 | }; |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 140 | const std::optional<HistogramBucketing>& GetHistogramBucketing() const; |
Mohsen Izadi | 820e5e4 | 2023-01-12 02:00:07 | [diff] [blame] | 141 | |
Jasmine Xiong | dc63b5c | 2022-08-10 06:31:42 | [diff] [blame] | 142 | void SetHighLatencyStage(const std::string& stage); |
| 143 | const std::vector<std::string>& GetHighLatencyStages() const { |
| 144 | return high_latency_stages_; |
| 145 | } |
| 146 | void ClearHighLatencyStagesForTesting() { high_latency_stages_.clear(); } |
| 147 | |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 148 | void SetDispatchStageTimestamp(DispatchStage stage); |
| 149 | base::TimeTicks GetDispatchStageTimestamp(DispatchStage stage) const; |
| 150 | |
Mohsen Izadi | dafa8ac3 | 2020-12-09 15:45:19 | [diff] [blame] | 151 | // Resets the metrics object to dispatch stage `stage` by setting timestamps |
| 152 | // of dispatch stages after `stage` to null timestamp, |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 153 | void ResetToDispatchStage(DispatchStage stage); |
| 154 | |
behdad | deab7ba9 | 2021-05-10 16:25:21 | [diff] [blame] | 155 | bool HasSmoothInputEvent() const; |
| 156 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 157 | virtual ScrollEventMetrics* AsScroll(); |
| 158 | const ScrollEventMetrics* AsScroll() const; |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 159 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 160 | virtual ScrollUpdateEventMetrics* AsScrollUpdate(); |
| 161 | const ScrollUpdateEventMetrics* AsScrollUpdate() const; |
| 162 | |
| 163 | virtual PinchEventMetrics* AsPinch(); |
| 164 | const PinchEventMetrics* AsPinch() const; |
| 165 | |
| 166 | virtual std::unique_ptr<EventMetrics> Clone() const; |
| 167 | |
Mohsen Izadi | 6b7ffaafe | 2022-05-31 17:52:11 | [diff] [blame] | 168 | bool should_record_tracing() const { return should_record_tracing_; } |
| 169 | void tracing_recorded() { |
| 170 | DCHECK(should_record_tracing_); |
| 171 | should_record_tracing_ = false; |
Mohsen Izadi | d32e777a | 2022-02-15 22:23:42 | [diff] [blame] | 172 | } |
| 173 | |
Steve Kobes | 134c6e21 | 2022-06-09 20:39:41 | [diff] [blame] | 174 | bool requires_main_thread_update() const { |
| 175 | return requires_main_thread_update_; |
| 176 | } |
| 177 | void set_requires_main_thread_update() { |
| 178 | DCHECK(!requires_main_thread_update_); |
| 179 | requires_main_thread_update_ = true; |
| 180 | } |
| 181 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 182 | protected: |
| 183 | EventMetrics(EventType type, |
| 184 | base::TimeTicks timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 185 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 186 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 6b7ffaafe | 2022-05-31 17:52:11 | [diff] [blame] | 187 | |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 188 | EventMetrics(EventType type, |
| 189 | base::TimeTicks timestamp, |
| 190 | base::TimeTicks arrived_in_browser_main_timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 191 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 192 | std::optional<TraceId> trace_id); |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 193 | |
Mohsen Izadi | 6b7ffaafe | 2022-05-31 17:52:11 | [diff] [blame] | 194 | // Creates a clone of `other` that might be used in creating `EventMetrics` |
| 195 | // objects for some injected events. Since this object itself does not |
| 196 | // directly correspond to an event, it won't be used in recording trace |
| 197 | // events. |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 198 | EventMetrics(const EventMetrics& other); |
| 199 | |
| 200 | // Copy timestamps of dispatch stages (up to and including |
| 201 | // `last_dispatch_stage`) from `other`. |
| 202 | void CopyTimestampsFrom(const EventMetrics& other, |
| 203 | DispatchStage last_dispatch_stage); |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 204 | |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 205 | void SetDispatchStageTimestamp(DispatchStage stage, |
| 206 | base::TimeTicks timestamp); |
| 207 | |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 208 | private: |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 209 | friend class ScrollEventMetrics; |
| 210 | friend class ScrollUpdateEventMetrics; |
| 211 | |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 212 | static std::unique_ptr<EventMetrics> CreateInternal( |
| 213 | ui::EventType type, |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 214 | base::TimeTicks timestamp, |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 215 | base::TimeTicks arrived_in_browser_main_timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 216 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 217 | std::optional<TraceId> trace_id); |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 218 | |
Mohsen Izadi | b1efd8c | 2020-05-29 17:30:28 | [diff] [blame] | 219 | EventType type_; |
Mohsen Izadi | d1d3a42 | 2020-03-18 03:17:22 | [diff] [blame] | 220 | |
Jasmine Xiong | dc63b5c | 2022-08-10 06:31:42 | [diff] [blame] | 221 | std::vector<std::string> high_latency_stages_; |
| 222 | |
Keishi Hattori | 0e45c02 | 2021-11-27 09:25:52 | [diff] [blame] | 223 | const raw_ptr<const base::TickClock> tick_clock_; |
Mohsen Izadi | de23be8 | 2020-12-09 02:19:06 | [diff] [blame] | 224 | |
| 225 | // Timestamps of different stages of event dispatch. Timestamps are set as the |
| 226 | // event moves forward in the pipeline. In the end, some stages might not have |
| 227 | // a timestamp which means the event did not pass those stages. |
| 228 | base::TimeTicks |
| 229 | dispatch_stage_timestamps_[static_cast<int>(DispatchStage::kMaxValue) + |
| 230 | 1]; |
Mohsen Izadi | d32e777a | 2022-02-15 22:23:42 | [diff] [blame] | 231 | |
Mohsen Izadi | 6b7ffaafe | 2022-05-31 17:52:11 | [diff] [blame] | 232 | // Determines whether a tracing event should be recorded for this object or |
| 233 | // not. This is `true` by default and set to `false` after a tracing event is |
| 234 | // recorded to avoid multiple recordings. Also, it is `false` for cloned |
| 235 | // objects as they are not meant to be recorded in tracings. |
| 236 | bool should_record_tracing_ = true; |
Steve Kobes | 134c6e21 | 2022-06-09 20:39:41 | [diff] [blame] | 237 | |
| 238 | // This is set on an EventMetrics object that comes from the impl thread, if |
| 239 | // the visual update from the event requires the main thread. Currently used |
| 240 | // for GestureScrollUpdate with scroll unification, when the scroller isn't |
| 241 | // composited or has main-thread scrolling reasons on the ScrollNode. |
| 242 | bool requires_main_thread_update_ = false; |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 243 | |
| 244 | // This is a trace id of an input event. It can be null for events which don't |
| 245 | // have a corresponding input, for example a generated event based on existing |
| 246 | // event. |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 247 | std::optional<TraceId> trace_id_; |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 248 | }; |
| 249 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 250 | class CC_EXPORT ScrollEventMetrics : public EventMetrics { |
| 251 | public: |
| 252 | // Type of scroll events. This list should be in the same order as values of |
| 253 | // `EventLatencyScrollInputType` enum from enums.xml file. |
| 254 | enum class ScrollType { |
| 255 | kAutoscroll, |
| 256 | kScrollbar, |
| 257 | kTouchscreen, |
| 258 | kWheel, |
| 259 | kMaxValue = kWheel, |
| 260 | }; |
| 261 | |
| 262 | // Returns a new instance if the event is of a type we are interested in. |
| 263 | // Otherwise, returns `nullptr`. Should only be used for scroll events other |
| 264 | // than scroll-update. |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 265 | // The |blocking_touch_dispatched_to_renderer| must be not null only for |
| 266 | // scrolls which corresponding TouchMove was blocking. |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 267 | // |
| 268 | // TODO(b/224960731): Fix tests and stop supporting the case when |
| 269 | // `arrived_in_browser_main_timestamp` is null. |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 270 | static std::unique_ptr<ScrollEventMetrics> Create( |
| 271 | ui::EventType type, |
| 272 | ui::ScrollInputType input_type, |
| 273 | bool is_inertial, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 274 | base::TimeTicks timestamp, |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 275 | base::TimeTicks arrived_in_browser_main_timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 276 | base::TimeTicks blocking_touch_dispatched_to_renderer, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 277 | std::optional<TraceId> trace_id); |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 278 | |
| 279 | // Prefer to use `Create()` above. This method is used only by the Browser |
| 280 | // process which have own breakdowns. |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 281 | // Similar to `Create()` above but doesn't set kArrivedInBrowserMain and |
| 282 | // kScrollsBlockingTouchDispatchedToRenderer. |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 283 | static std::unique_ptr<ScrollEventMetrics> CreateForBrowser( |
| 284 | ui::EventType type, |
| 285 | ui::ScrollInputType input_type, |
| 286 | bool is_inertial, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 287 | base::TimeTicks timestamp, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 288 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 289 | |
| 290 | // Similar to `Create()` with an extra `base::TickClock` to use in tests. |
| 291 | // Should only be used for scroll events other than scroll-update. |
| 292 | static std::unique_ptr<ScrollEventMetrics> CreateForTesting( |
| 293 | ui::EventType type, |
| 294 | ui::ScrollInputType input_type, |
| 295 | bool is_inertial, |
| 296 | base::TimeTicks timestamp, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 297 | base::TimeTicks arrived_in_browser_main_timestamp, |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 298 | const base::TickClock* tick_clock); |
| 299 | |
| 300 | // Used to create an instance for an event generated based on an existing |
| 301 | // event. If the new event is of an interesting type, we expect that the |
| 302 | // existing event is also of an interesting type in which case `existing` is |
| 303 | // not `nullptr` and timestamps (up to and including `last_dispatch_stage`) |
| 304 | // and tick clock from `existing` will be used for the new metrics object. If |
| 305 | // the new event is not an interesting one, return value would be `nullptr`. |
| 306 | // Should only be used for scroll events other than scroll-update. |
| 307 | static std::unique_ptr<ScrollEventMetrics> CreateFromExisting( |
| 308 | ui::EventType type, |
| 309 | ui::ScrollInputType input_type, |
| 310 | bool is_inertial, |
| 311 | DispatchStage last_dispatch_stage, |
| 312 | const EventMetrics* existing); |
| 313 | |
| 314 | ~ScrollEventMetrics() override; |
| 315 | |
| 316 | ScrollType scroll_type() const { return scroll_type_; } |
| 317 | |
| 318 | // Returns a string representing input type for a scroll event. |
| 319 | const char* GetScrollTypeName() const; |
| 320 | |
| 321 | ScrollEventMetrics* AsScroll() override; |
| 322 | |
| 323 | std::unique_ptr<EventMetrics> Clone() const override; |
| 324 | |
Jonathan Ross | 86b8f3b1 | 2024-03-13 19:15:15 | [diff] [blame] | 325 | void set_begin_frame_args(const viz::BeginFrameArgs& args) { args_ = args; } |
| 326 | |
| 327 | const viz::BeginFrameArgs& begin_frame_args() const { return args_; } |
| 328 | |
Jonathan Ross | 379ca48 | 2025-06-02 14:21:15 | [diff] [blame] | 329 | void set_did_scroll(bool did_scroll) { did_scroll_ = did_scroll; } |
| 330 | bool did_scroll() const { return did_scroll_; } |
| 331 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 332 | protected: |
| 333 | ScrollEventMetrics(EventType type, |
| 334 | ScrollType scroll_type, |
| 335 | base::TimeTicks timestamp, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 336 | base::TimeTicks arrived_in_browser_main_timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 337 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 338 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 339 | ScrollEventMetrics(const ScrollEventMetrics&); |
| 340 | |
| 341 | private: |
| 342 | static std::unique_ptr<ScrollEventMetrics> CreateInternal( |
| 343 | ui::EventType type, |
| 344 | ui::ScrollInputType input_type, |
| 345 | bool is_inertial, |
| 346 | base::TimeTicks timestamp, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 347 | base::TimeTicks arrived_in_browser_main_timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 348 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 349 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 350 | |
| 351 | // Type of the input device for the event. |
| 352 | ScrollType scroll_type_; |
Jonathan Ross | 86b8f3b1 | 2024-03-13 19:15:15 | [diff] [blame] | 353 | |
| 354 | // The active viz::BeginFrameArgs when the event arrived in the Renderer. |
| 355 | // These may not match those of CompositorFrameReporter for which the event |
| 356 | // is eventually displayed. |
| 357 | viz::BeginFrameArgs args_; |
Jonathan Ross | 379ca48 | 2025-06-02 14:21:15 | [diff] [blame] | 358 | |
| 359 | // The scroll delta may not be actually applied. Event if it is consumed. This |
| 360 | // denotes that a scroll did actually occur. |
| 361 | bool did_scroll_ = false; |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 362 | }; |
| 363 | |
| 364 | class CC_EXPORT ScrollUpdateEventMetrics : public ScrollEventMetrics { |
| 365 | public: |
| 366 | // Determines whether a scroll-update event is the first one in a gesture |
| 367 | // scroll sequence or not. |
| 368 | enum class ScrollUpdateType { |
| 369 | kStarted, |
| 370 | kContinued, |
| 371 | kMaxValue = kContinued, |
| 372 | }; |
| 373 | |
| 374 | // Returns a new instance if the event is of a type we are interested in. |
| 375 | // Otherwise, returns `nullptr`. Should only be used for scroll-update events. |
Jonathan Ross | 6f1642e | 2024-05-10 14:15:18 | [diff] [blame] | 376 | // The `arrived_in_browser_main_timestamp` can be null for events that were |
| 377 | // generated synthetically within the Renderer. The |
| 378 | // `blocking_touch_dispatched_to_renderer` must be not null only for |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 379 | // scrolls which corresponding TouchMove was blocking. |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 380 | // |
Jonathan Ross | 6f1642e | 2024-05-10 14:15:18 | [diff] [blame] | 381 | // TODO(b/329346768): Build `trace_id` generation for synthetic events. |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 382 | static std::unique_ptr<ScrollUpdateEventMetrics> Create( |
| 383 | ui::EventType type, |
| 384 | ui::ScrollInputType input_type, |
| 385 | bool is_inertial, |
| 386 | ScrollUpdateType scroll_update_type, |
| 387 | float delta, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 388 | base::TimeTicks timestamp, |
Violetta Fedotova | 842ccc3 | 2023-02-03 20:59:53 | [diff] [blame] | 389 | base::TimeTicks arrived_in_browser_main_timestamp, |
Jonathan Ross | 6f1642e | 2024-05-10 14:15:18 | [diff] [blame] | 390 | base::TimeTicks blocking_touch_dispatched_to_renderer, |
| 391 | std::optional<TraceId> trace_id); |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 392 | |
| 393 | // Prefer to use `Create()` above. This method is used only by the Browser |
| 394 | // process which have own breakdowns. |
Violetta Fedotova | c6b2fb4f | 2023-04-21 10:54:39 | [diff] [blame] | 395 | // Similar to `Create()` above but doesn't set kArrivedInBrowserMain and |
| 396 | // kScrollsBlockingTouchDispatchedToRenderer. |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 397 | static std::unique_ptr<ScrollUpdateEventMetrics> CreateForBrowser( |
| 398 | ui::EventType type, |
| 399 | ui::ScrollInputType input_type, |
| 400 | bool is_inertial, |
| 401 | ScrollUpdateType scroll_update_type, |
| 402 | float delta, |
Violetta Fedotova | 842ccc3 | 2023-02-03 20:59:53 | [diff] [blame] | 403 | base::TimeTicks timestamp, |
| 404 | TraceId trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 405 | |
| 406 | // Similar to `Create()` with an extra `base::TickClock` to use in tests. |
| 407 | // Should only be used for scroll-update events. |
| 408 | static std::unique_ptr<ScrollUpdateEventMetrics> CreateForTesting( |
| 409 | ui::EventType type, |
| 410 | ui::ScrollInputType input_type, |
| 411 | bool is_inertial, |
| 412 | ScrollUpdateType scroll_update_type, |
| 413 | float delta, |
| 414 | base::TimeTicks timestamp, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 415 | base::TimeTicks arrived_in_browser_main_timestamp, |
Kartar Singh | c1dbdfd | 2023-08-22 14:30:34 | [diff] [blame] | 416 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 417 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 418 | |
| 419 | // Used to create an instance for an event generated based on an existing |
| 420 | // event. If the new event is of an interesting type, we expect that the |
| 421 | // existing event is also of an interesting type in which case `existing` is |
| 422 | // not `nullptr` and timestamps (up to and including `last_dispatch_stage`) |
| 423 | // and tick clock from `existing` will be used for the new metrics object. If |
| 424 | // the new event is not an interesting one, return value would be `nullptr`. |
| 425 | // Should only be used for scroll-update events. |
| 426 | static std::unique_ptr<ScrollUpdateEventMetrics> CreateFromExisting( |
| 427 | ui::EventType type, |
| 428 | ui::ScrollInputType input_type, |
| 429 | bool is_inertial, |
| 430 | ScrollUpdateType scroll_update_type, |
| 431 | float delta, |
| 432 | DispatchStage last_dispatch_stage, |
| 433 | const EventMetrics* existing); |
| 434 | |
| 435 | ~ScrollUpdateEventMetrics() override; |
| 436 | |
| 437 | void CoalesceWith(const ScrollUpdateEventMetrics& newer_scroll_update); |
| 438 | |
| 439 | ScrollUpdateEventMetrics* AsScrollUpdate() override; |
| 440 | |
| 441 | float delta() const { return delta_; } |
| 442 | |
| 443 | float predicted_delta() const { return predicted_delta_; } |
Omar Elmekkawy | 171cf7f | 2023-01-16 16:52:51 | [diff] [blame] | 444 | |
Kartar Singh | 554930c | 2023-05-22 11:28:22 | [diff] [blame] | 445 | int32_t coalesced_event_count() const { return coalesced_event_count_; } |
Violetta Fedotova | 842ccc3 | 2023-02-03 20:59:53 | [diff] [blame] | 446 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 447 | void set_predicted_delta(float predicted_delta) { |
| 448 | predicted_delta_ = predicted_delta; |
| 449 | } |
| 450 | |
| 451 | base::TimeTicks last_timestamp() const { return last_timestamp_; } |
| 452 | |
| 453 | std::unique_ptr<EventMetrics> Clone() const override; |
| 454 | |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 455 | void set_is_janky_scrolled_frame(std::optional<bool> is_janky) { |
Kartar Singh | 748fc33 | 2023-07-28 19:07:44 | [diff] [blame] | 456 | is_janky_scrolled_frame_ = is_janky; |
| 457 | } |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 458 | std::optional<bool> is_janky_scrolled_frame() const { |
Kartar Singh | 748fc33 | 2023-07-28 19:07:44 | [diff] [blame] | 459 | return is_janky_scrolled_frame_; |
| 460 | } |
| 461 | |
Petr Cermak | 04dd1bc | 2025-03-24 13:32:35 | [diff] [blame] | 462 | void set_is_janky_scrolled_frame_v3(std::optional<bool> is_janky) { |
| 463 | is_janky_scrolled_frame_v3_ = is_janky; |
| 464 | } |
| 465 | std::optional<bool> is_janky_scrolled_frame_v3() const { |
| 466 | return is_janky_scrolled_frame_v3_; |
| 467 | } |
| 468 | |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 469 | protected: |
| 470 | ScrollUpdateEventMetrics(EventType type, |
| 471 | ScrollType scroll_type, |
| 472 | ScrollUpdateType scroll_update_type, |
| 473 | float delta, |
| 474 | base::TimeTicks timestamp, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 475 | base::TimeTicks arrived_in_browser_main_timestamp, |
Violetta Fedotova | 842ccc3 | 2023-02-03 20:59:53 | [diff] [blame] | 476 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 477 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 478 | ScrollUpdateEventMetrics(const ScrollUpdateEventMetrics&); |
| 479 | |
| 480 | private: |
| 481 | static std::unique_ptr<ScrollUpdateEventMetrics> CreateInternal( |
| 482 | ui::EventType type, |
| 483 | ui::ScrollInputType input_type, |
| 484 | bool is_inertial, |
| 485 | ScrollUpdateType scroll_update_type, |
| 486 | float delta, |
| 487 | base::TimeTicks timestamp, |
Violetta Fedotova | e38c033 | 2022-09-02 17:48:22 | [diff] [blame] | 488 | base::TimeTicks arrived_in_browser_main_timestamp, |
Violetta Fedotova | 842ccc3 | 2023-02-03 20:59:53 | [diff] [blame] | 489 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 490 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 491 | |
| 492 | float delta_; |
| 493 | float predicted_delta_; |
| 494 | |
| 495 | // Timestamp of the last event coalesced into this one. |
| 496 | base::TimeTicks last_timestamp_; |
Omar Elmekkawy | 171cf7f | 2023-01-16 16:52:51 | [diff] [blame] | 497 | |
| 498 | // Total events that were coalesced into this into this ScrollUpdate |
| 499 | int32_t coalesced_event_count_ = 1; |
Kartar Singh | 748fc33 | 2023-07-28 19:07:44 | [diff] [blame] | 500 | |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 501 | std::optional<bool> is_janky_scrolled_frame_ = std::nullopt; |
Petr Cermak | 04dd1bc | 2025-03-24 13:32:35 | [diff] [blame] | 502 | std::optional<bool> is_janky_scrolled_frame_v3_ = std::nullopt; |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 503 | }; |
| 504 | |
| 505 | class CC_EXPORT PinchEventMetrics : public EventMetrics { |
| 506 | public: |
| 507 | // Type of pinch events. This list should be in the same order as values of |
| 508 | // `EventLatencyPinchInputType` enum from enums.xml file. |
| 509 | enum class PinchType { |
| 510 | kTouchpad, |
| 511 | kTouchscreen, |
| 512 | kMaxValue = kTouchscreen, |
| 513 | }; |
| 514 | |
| 515 | // Returns a new instance if the event is of a type we are interested in. |
| 516 | // Otherwise, returns `nullptr`. Should only be used for pinch events. |
| 517 | static std::unique_ptr<PinchEventMetrics> Create( |
| 518 | ui::EventType type, |
| 519 | ui::ScrollInputType input_type, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 520 | base::TimeTicks timestamp, |
| 521 | TraceId trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 522 | |
| 523 | // Similar to `Create()` with an extra `base::TickClock` to use in tests. |
| 524 | // Should only be used for pinch events. |
| 525 | static std::unique_ptr<PinchEventMetrics> CreateForTesting( |
| 526 | ui::EventType type, |
| 527 | ui::ScrollInputType input_type, |
| 528 | base::TimeTicks timestamp, |
| 529 | const base::TickClock* tick_clock); |
| 530 | |
| 531 | ~PinchEventMetrics() override; |
| 532 | |
| 533 | PinchType pinch_type() const { return pinch_type_; } |
| 534 | |
| 535 | // Returns a string representing input type for a pinch event. Should only be |
| 536 | // called for pinch events. |
| 537 | const char* GetPinchTypeName() const; |
| 538 | |
| 539 | PinchEventMetrics* AsPinch() override; |
| 540 | |
| 541 | std::unique_ptr<EventMetrics> Clone() const override; |
| 542 | |
| 543 | protected: |
| 544 | PinchEventMetrics(EventType type, |
| 545 | PinchType pinch_type, |
| 546 | base::TimeTicks timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 547 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 548 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 549 | PinchEventMetrics(const PinchEventMetrics&); |
| 550 | |
| 551 | private: |
| 552 | static std::unique_ptr<PinchEventMetrics> CreateInternal( |
| 553 | ui::EventType type, |
| 554 | ui::ScrollInputType input_type, |
| 555 | base::TimeTicks timestamp, |
Kartar Singh | b5098a639 | 2023-07-24 15:24:49 | [diff] [blame] | 556 | const base::TickClock* tick_clock, |
Arthur Sonzogni | ca067f26 | 2023-11-10 14:18:10 | [diff] [blame] | 557 | std::optional<TraceId> trace_id); |
Mohsen Izadi | 5efb1343 | 2021-12-13 18:24:33 | [diff] [blame] | 558 | |
| 559 | PinchType pinch_type_; |
| 560 | }; |
| 561 | |
Mingjing Zhang | 6beed0b5 | 2020-04-02 02:00:28 | [diff] [blame] | 562 | // Struct storing event metrics from both main and impl threads. |
| 563 | struct CC_EXPORT EventMetricsSet { |
| 564 | EventMetricsSet(); |
| 565 | ~EventMetricsSet(); |
Mohsen Izadi | b8878bf7 | 2020-11-06 19:16:42 | [diff] [blame] | 566 | EventMetricsSet(EventMetrics::List main_thread_event_metrics, |
Stacy Gaikovaia | 7c07f1f | 2025-05-28 21:47:03 | [diff] [blame] | 567 | EventMetrics::List impl_thread_event_metrics, |
| 568 | EventMetrics::List raster_thread_event_metrics); |
Mingjing Zhang | 6beed0b5 | 2020-04-02 02:00:28 | [diff] [blame] | 569 | EventMetricsSet(EventMetricsSet&&); |
| 570 | EventMetricsSet& operator=(EventMetricsSet&&); |
| 571 | |
| 572 | EventMetricsSet(const EventMetricsSet&) = delete; |
| 573 | EventMetricsSet& operator=(const EventMetricsSet&) = delete; |
| 574 | |
Mohsen Izadi | b8878bf7 | 2020-11-06 19:16:42 | [diff] [blame] | 575 | EventMetrics::List main_event_metrics; |
| 576 | EventMetrics::List impl_event_metrics; |
Stacy Gaikovaia | 7c07f1f | 2025-05-28 21:47:03 | [diff] [blame] | 577 | EventMetrics::List raster_event_metrics; |
Mingjing Zhang | 6beed0b5 | 2020-04-02 02:00:28 | [diff] [blame] | 578 | }; |
| 579 | |
Mohsen Izadi | a52ab64 | 2020-03-03 05:21:27 | [diff] [blame] | 580 | } // namespace cc |
| 581 | |
| 582 | #endif // CC_METRICS_EVENT_METRICS_H_ |