| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CC_METRICS_EVENT_METRICS_H_ |
| #define CC_METRICS_EVENT_METRICS_H_ |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/memory/raw_ptr.h" |
| #include "base/time/tick_clock.h" |
| #include "base/time/time.h" |
| #include "cc/cc_export.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "ui/events/types/event_type.h" |
| #include "ui/events/types/scroll_input_type.h" |
| |
| namespace cc { |
| class PinchEventMetrics; |
| class ScrollEventMetrics; |
| class ScrollUpdateEventMetrics; |
| |
| // Data about an event used by CompositorFrameReporter in generating event |
| // latency metrics. |
| class CC_EXPORT EventMetrics { |
| public: |
| using List = std::vector<std::unique_ptr<EventMetrics>>; |
| |
| // Event types we are interested in. This list should be in the same order as |
| // values of EventLatencyEventType enum from enums.xml file. |
| enum class EventType { |
| kMousePressed, |
| kMouseReleased, |
| kMouseWheel, |
| // TODO(crbug/1071645): Currently, all ET_KEY_PRESSED events are reported |
| // under EventLatency.KeyPressed histogram. This includes both key-down and |
| // key-char events. Consider reporting them separately. |
| kKeyPressed, |
| kKeyReleased, |
| kTouchPressed, |
| kTouchReleased, |
| kTouchMoved, |
| kGestureScrollBegin, |
| kGestureScrollUpdate, |
| kGestureScrollEnd, |
| kGestureDoubleTap, |
| kGestureLongPress, |
| kGestureLongTap, |
| kGestureShowPress, |
| kGestureTap, |
| kGestureTapCancel, |
| kGestureTapDown, |
| kGestureTapUnconfirmed, |
| kGestureTwoFingerTap, |
| kFirstGestureScrollUpdate, |
| kMouseDragged, |
| kGesturePinchBegin, |
| kGesturePinchEnd, |
| kGesturePinchUpdate, |
| kInertialGestureScrollUpdate, |
| kMaxValue = kInertialGestureScrollUpdate, |
| }; |
| |
| // Stages of event dispatch in different processes/threads. |
| enum class DispatchStage { |
| kGenerated, |
| kArrivedInRendererCompositor, |
| kRendererCompositorStarted, |
| kRendererCompositorFinished, |
| kRendererMainStarted, |
| kRendererMainFinished, |
| kMaxValue = kRendererMainFinished, |
| }; |
| |
| // Returns a new instance if the event is of a type we are interested in. |
| // Otherwise, returns `nullptr`. For scroll and pinch events, use the |
| // appropriate subcalss instead. |
| static std::unique_ptr<EventMetrics> Create(ui::EventType type, |
| base::TimeTicks timestamp); |
| |
| // Similar to `Create()` with an extra `base::TickClock` to use in tests. |
| static std::unique_ptr<EventMetrics> CreateForTesting( |
| ui::EventType type, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| // Used to create an instance for an event generated based on an existing |
| // event. If the new event is of an interesting type, we expect that the |
| // existing event is also of an interesting type in which case `existing` is |
| // not `nullptr` and timestamps (up to and including `last_dispatch_stage`) |
| // and tick clock from `existing` will be used for the new metrics object. If |
| // the new event is not an interesting one, return value would be `nullptr`. |
| // For scroll and pinch events, use the appropriate subclass instead. |
| static std::unique_ptr<EventMetrics> CreateFromExisting( |
| ui::EventType type, |
| DispatchStage last_dispatch_stage, |
| const EventMetrics* existing); |
| |
| virtual ~EventMetrics(); |
| |
| EventMetrics& operator=(const EventMetrics&) = delete; |
| |
| EventType type() const { return type_; } |
| |
| // Returns a string representing event type. |
| const char* GetTypeName() const; |
| |
| void SetDispatchStageTimestamp(DispatchStage stage); |
| base::TimeTicks GetDispatchStageTimestamp(DispatchStage stage) const; |
| |
| // Resets the metrics object to dispatch stage `stage` by setting timestamps |
| // of dispatch stages after `stage` to null timestamp, |
| void ResetToDispatchStage(DispatchStage stage); |
| |
| bool HasSmoothInputEvent() const; |
| |
| virtual ScrollEventMetrics* AsScroll(); |
| const ScrollEventMetrics* AsScroll() const; |
| |
| virtual ScrollUpdateEventMetrics* AsScrollUpdate(); |
| const ScrollUpdateEventMetrics* AsScrollUpdate() const; |
| |
| virtual PinchEventMetrics* AsPinch(); |
| const PinchEventMetrics* AsPinch() const; |
| |
| virtual std::unique_ptr<EventMetrics> Clone() const; |
| |
| bool should_record_tracing() const { return should_record_tracing_; } |
| void tracing_recorded() { |
| DCHECK(should_record_tracing_); |
| should_record_tracing_ = false; |
| } |
| |
| bool requires_main_thread_update() const { |
| return requires_main_thread_update_; |
| } |
| void set_requires_main_thread_update() { |
| DCHECK(!requires_main_thread_update_); |
| requires_main_thread_update_ = true; |
| } |
| |
| protected: |
| EventMetrics(EventType type, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| // Creates a clone of `other` that might be used in creating `EventMetrics` |
| // objects for some injected events. Since this object itself does not |
| // directly correspond to an event, it won't be used in recording trace |
| // events. |
| EventMetrics(const EventMetrics& other); |
| |
| // Copy timestamps of dispatch stages (up to and including |
| // `last_dispatch_stage`) from `other`. |
| void CopyTimestampsFrom(const EventMetrics& other, |
| DispatchStage last_dispatch_stage); |
| |
| private: |
| friend class ScrollEventMetrics; |
| friend class ScrollUpdateEventMetrics; |
| |
| static std::unique_ptr<EventMetrics> CreateInternal( |
| ui::EventType type, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| EventType type_; |
| |
| const raw_ptr<const base::TickClock> tick_clock_; |
| |
| // Timestamps of different stages of event dispatch. Timestamps are set as the |
| // event moves forward in the pipeline. In the end, some stages might not have |
| // a timestamp which means the event did not pass those stages. |
| base::TimeTicks |
| dispatch_stage_timestamps_[static_cast<int>(DispatchStage::kMaxValue) + |
| 1]; |
| |
| // Determines whether a tracing event should be recorded for this object or |
| // not. This is `true` by default and set to `false` after a tracing event is |
| // recorded to avoid multiple recordings. Also, it is `false` for cloned |
| // objects as they are not meant to be recorded in tracings. |
| bool should_record_tracing_ = true; |
| |
| // This is set on an EventMetrics object that comes from the impl thread, if |
| // the visual update from the event requires the main thread. Currently used |
| // for GestureScrollUpdate with scroll unification, when the scroller isn't |
| // composited or has main-thread scrolling reasons on the ScrollNode. |
| bool requires_main_thread_update_ = false; |
| }; |
| |
| class CC_EXPORT ScrollEventMetrics : public EventMetrics { |
| public: |
| // Type of scroll events. This list should be in the same order as values of |
| // `EventLatencyScrollInputType` enum from enums.xml file. |
| enum class ScrollType { |
| kAutoscroll, |
| kScrollbar, |
| kTouchscreen, |
| kWheel, |
| kMaxValue = kWheel, |
| }; |
| |
| // Returns a new instance if the event is of a type we are interested in. |
| // Otherwise, returns `nullptr`. Should only be used for scroll events other |
| // than scroll-update. |
| static std::unique_ptr<ScrollEventMetrics> Create( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| base::TimeTicks timestamp); |
| |
| // Similar to `Create()` with an extra `base::TickClock` to use in tests. |
| // Should only be used for scroll events other than scroll-update. |
| static std::unique_ptr<ScrollEventMetrics> CreateForTesting( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| // Used to create an instance for an event generated based on an existing |
| // event. If the new event is of an interesting type, we expect that the |
| // existing event is also of an interesting type in which case `existing` is |
| // not `nullptr` and timestamps (up to and including `last_dispatch_stage`) |
| // and tick clock from `existing` will be used for the new metrics object. If |
| // the new event is not an interesting one, return value would be `nullptr`. |
| // Should only be used for scroll events other than scroll-update. |
| static std::unique_ptr<ScrollEventMetrics> CreateFromExisting( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| DispatchStage last_dispatch_stage, |
| const EventMetrics* existing); |
| |
| ~ScrollEventMetrics() override; |
| |
| ScrollType scroll_type() const { return scroll_type_; } |
| |
| // Returns a string representing input type for a scroll event. |
| const char* GetScrollTypeName() const; |
| |
| ScrollEventMetrics* AsScroll() override; |
| |
| std::unique_ptr<EventMetrics> Clone() const override; |
| |
| protected: |
| ScrollEventMetrics(EventType type, |
| ScrollType scroll_type, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| ScrollEventMetrics(const ScrollEventMetrics&); |
| |
| private: |
| static std::unique_ptr<ScrollEventMetrics> CreateInternal( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| // Type of the input device for the event. |
| ScrollType scroll_type_; |
| }; |
| |
| class CC_EXPORT ScrollUpdateEventMetrics : public ScrollEventMetrics { |
| public: |
| // Determines whether a scroll-update event is the first one in a gesture |
| // scroll sequence or not. |
| enum class ScrollUpdateType { |
| kStarted, |
| kContinued, |
| kMaxValue = kContinued, |
| }; |
| |
| // Returns a new instance if the event is of a type we are interested in. |
| // Otherwise, returns `nullptr`. Should only be used for scroll-update events. |
| static std::unique_ptr<ScrollUpdateEventMetrics> Create( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| ScrollUpdateType scroll_update_type, |
| float delta, |
| base::TimeTicks timestamp); |
| |
| // Similar to `Create()` with an extra `base::TickClock` to use in tests. |
| // Should only be used for scroll-update events. |
| static std::unique_ptr<ScrollUpdateEventMetrics> CreateForTesting( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| ScrollUpdateType scroll_update_type, |
| float delta, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| // Used to create an instance for an event generated based on an existing |
| // event. If the new event is of an interesting type, we expect that the |
| // existing event is also of an interesting type in which case `existing` is |
| // not `nullptr` and timestamps (up to and including `last_dispatch_stage`) |
| // and tick clock from `existing` will be used for the new metrics object. If |
| // the new event is not an interesting one, return value would be `nullptr`. |
| // Should only be used for scroll-update events. |
| static std::unique_ptr<ScrollUpdateEventMetrics> CreateFromExisting( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| ScrollUpdateType scroll_update_type, |
| float delta, |
| DispatchStage last_dispatch_stage, |
| const EventMetrics* existing); |
| |
| ~ScrollUpdateEventMetrics() override; |
| |
| void CoalesceWith(const ScrollUpdateEventMetrics& newer_scroll_update); |
| |
| ScrollUpdateEventMetrics* AsScrollUpdate() override; |
| |
| float delta() const { return delta_; } |
| |
| float predicted_delta() const { return predicted_delta_; } |
| void set_predicted_delta(float predicted_delta) { |
| predicted_delta_ = predicted_delta; |
| } |
| |
| base::TimeTicks last_timestamp() const { return last_timestamp_; } |
| |
| std::unique_ptr<EventMetrics> Clone() const override; |
| |
| protected: |
| ScrollUpdateEventMetrics(EventType type, |
| ScrollType scroll_type, |
| ScrollUpdateType scroll_update_type, |
| float delta, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| ScrollUpdateEventMetrics(const ScrollUpdateEventMetrics&); |
| |
| private: |
| static std::unique_ptr<ScrollUpdateEventMetrics> CreateInternal( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| ScrollUpdateType scroll_update_type, |
| float delta, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| float delta_; |
| float predicted_delta_; |
| |
| // Timestamp of the last event coalesced into this one. |
| base::TimeTicks last_timestamp_; |
| }; |
| |
| class CC_EXPORT PinchEventMetrics : public EventMetrics { |
| public: |
| // Type of pinch events. This list should be in the same order as values of |
| // `EventLatencyPinchInputType` enum from enums.xml file. |
| enum class PinchType { |
| kTouchpad, |
| kTouchscreen, |
| kMaxValue = kTouchscreen, |
| }; |
| |
| // Returns a new instance if the event is of a type we are interested in. |
| // Otherwise, returns `nullptr`. Should only be used for pinch events. |
| static std::unique_ptr<PinchEventMetrics> Create( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| base::TimeTicks timestamp); |
| |
| // Similar to `Create()` with an extra `base::TickClock` to use in tests. |
| // Should only be used for pinch events. |
| static std::unique_ptr<PinchEventMetrics> CreateForTesting( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| ~PinchEventMetrics() override; |
| |
| PinchType pinch_type() const { return pinch_type_; } |
| |
| // Returns a string representing input type for a pinch event. Should only be |
| // called for pinch events. |
| const char* GetPinchTypeName() const; |
| |
| PinchEventMetrics* AsPinch() override; |
| |
| std::unique_ptr<EventMetrics> Clone() const override; |
| |
| protected: |
| PinchEventMetrics(EventType type, |
| PinchType pinch_type, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| PinchEventMetrics(const PinchEventMetrics&); |
| |
| private: |
| static std::unique_ptr<PinchEventMetrics> CreateInternal( |
| ui::EventType type, |
| ui::ScrollInputType input_type, |
| base::TimeTicks timestamp, |
| const base::TickClock* tick_clock); |
| |
| PinchType pinch_type_; |
| }; |
| |
| // Struct storing event metrics from both main and impl threads. |
| struct CC_EXPORT EventMetricsSet { |
| EventMetricsSet(); |
| ~EventMetricsSet(); |
| EventMetricsSet(EventMetrics::List main_thread_event_metrics, |
| EventMetrics::List impl_thread_event_metrics); |
| EventMetricsSet(EventMetricsSet&&); |
| EventMetricsSet& operator=(EventMetricsSet&&); |
| |
| EventMetricsSet(const EventMetricsSet&) = delete; |
| EventMetricsSet& operator=(const EventMetricsSet&) = delete; |
| |
| EventMetrics::List main_event_metrics; |
| EventMetrics::List impl_event_metrics; |
| }; |
| |
| } // namespace cc |
| |
| #endif // CC_METRICS_EVENT_METRICS_H_ |