Chromium Code Reviews| Index: content/renderer/input/main_thread_event_queue.cc |
| diff --git a/content/renderer/input/main_thread_event_queue.cc b/content/renderer/input/main_thread_event_queue.cc |
| index 8c1b8675cfafb469d36ae1841c51a4d9256fe32e..ad9ca5216703d07a3de5b1a725f098cd1c810a05 100644 |
| --- a/content/renderer/input/main_thread_event_queue.cc |
| +++ b/content/renderer/input/main_thread_event_queue.cc |
| @@ -4,17 +4,40 @@ |
| #include "content/renderer/input/main_thread_event_queue.h" |
| +#include "base/metrics/histogram_macros.h" |
| #include "content/common/input/event_with_latency_info.h" |
| #include "content/common/input_messages.h" |
| namespace content { |
| +namespace { |
| + |
| +// The maximum number of post-coalesced events processed per rAF task. 10 was |
| +// chosen because it really should never be hit yet prevents an infinite loop if |
| +// the compositor keeps delivering events faster than the main thread can |
| +// process them. |
| +const size_t kMaxEventsPerRafTask = 10; |
| + |
| +bool isContinuousEvent(const std::unique_ptr<EventWithDispatchType>& event) { |
| + switch (event->event().type) { |
| + case blink::WebInputEvent::MouseMove: |
| + case blink::WebInputEvent::TouchMove: |
| + case blink::WebInputEvent::MouseWheel: |
| + return true; |
| + default: |
| + return false; |
| + } |
| +} |
|
tdresser
2016/08/25 14:38:41
Missing newline.
dtapuska
2016/08/25 15:01:35
Done.
|
| +} // namespace |
| + |
| EventWithDispatchType::EventWithDispatchType( |
| ui::ScopedWebInputEvent event, |
| const ui::LatencyInfo& latency, |
| InputEventDispatchType dispatch_type) |
| : ScopedWebInputEventWithLatencyInfo(std::move(event), latency), |
| - dispatch_type_(dispatch_type) {} |
| + dispatch_type_(dispatch_type), |
| + creation_timestamp_(base::TimeTicks::Now()), |
| + last_coalesced_timestamp_(creation_timestamp_) {} |
| EventWithDispatchType::~EventWithDispatchType() {} |
| @@ -25,16 +48,17 @@ bool EventWithDispatchType::CanCoalesceWith( |
| } |
| void EventWithDispatchType::CoalesceWith(const EventWithDispatchType& other) { |
| - // If we are blocking and are coalescing touch, make sure to keep |
| - // the touch ids that need to be acked. |
| - if (dispatch_type_ == DISPATCH_TYPE_BLOCKING) { |
| - // We should only have blocking touch events that need coalescing. |
| - eventsToAck_.push_back( |
| - ui::WebInputEventTraits::GetUniqueTouchEventId(other.event())); |
| - } |
| + coalesced_event_ids_.push_back( |
| + ui::WebInputEventTraits::GetUniqueTouchEventId(other.event())); |
| ScopedWebInputEventWithLatencyInfo::CoalesceWith(other); |
| + last_coalesced_timestamp_ = base::TimeTicks::Now(); |
| } |
| +MainThreadEventQueue::SharedState::SharedState() |
| + : sent_main_frame_request_(false) {} |
| + |
| +MainThreadEventQueue::SharedState::~SharedState() {} |
| + |
| MainThreadEventQueue::MainThreadEventQueue( |
| int routing_id, |
| MainThreadEventQueueClient* client, |
| @@ -46,6 +70,8 @@ MainThreadEventQueue::MainThreadEventQueue( |
| last_touch_start_forced_nonblocking_due_to_fling_(false), |
| enable_fling_passive_listener_flag_(base::FeatureList::IsEnabled( |
| features::kPassiveEventListenersDueToFling)), |
| + handle_raf_aligned_input_( |
| + base::FeatureList::IsEnabled(features::kRafAlignedInputEvents)), |
| main_task_runner_(main_task_runner), |
| renderer_scheduler_(renderer_scheduler) {} |
| @@ -110,16 +136,35 @@ bool MainThreadEventQueue::HandleEvent( |
| return non_blocking; |
| } |
| -void MainThreadEventQueue::PopEventOnMainThread() { |
| - { |
| - base::AutoLock lock(event_queue_lock_); |
| - if (!events_.empty()) |
| - in_flight_event_ = events_.Pop(); |
| - } |
| - |
| +void MainThreadEventQueue::DispatchInFlightEvent() { |
| if (in_flight_event_) { |
| + // Report the coalesced count only for continuous events; otherwise |
| + // the zero value would be dominated by non-continuous events. |
| + if (isContinuousEvent(in_flight_event_)) { |
| + UMA_HISTOGRAM_CUSTOM_COUNTS( |
| + "Event.MainThreadEventQueue.Continuous.QueueingTime", |
| + (base::TimeTicks::Now() - in_flight_event_->creationTimestamp()) |
| + .ToInternalValue(), |
| + 1, 10000000, 100); |
| + |
| + UMA_HISTOGRAM_CUSTOM_COUNTS( |
| + "Event.MainThreadEventQueue.Continuous.FreshnessTime", |
| + (base::TimeTicks::Now() - in_flight_event_->lastCoalescedTimestamp()) |
| + .ToInternalValue(), |
| + 1, 10000000, 100); |
| + |
| + UMA_HISTOGRAM_COUNTS_100("Event.MainThreadEventQueue.CoalescedCount", |
| + in_flight_event_->coalescedEventIds().size()); |
| + } else { |
| + UMA_HISTOGRAM_CUSTOM_COUNTS( |
| + "Event.MainThreadEventQueue.NonContinuous.QueueingTime", |
| + (base::TimeTicks::Now() - in_flight_event_->creationTimestamp()) |
| + .ToInternalValue(), |
| + 1, 10000000, 100); |
| + } |
| + |
| InputEventDispatchType dispatch_type = in_flight_event_->dispatchType(); |
| - if (!in_flight_event_->eventsToAck().empty() && |
| + if (!in_flight_event_->coalescedEventIds().empty() && |
| dispatch_type == DISPATCH_TYPE_BLOCKING) { |
| dispatch_type = DISPATCH_TYPE_BLOCKING_NOTIFY_MAIN; |
| } |
| @@ -132,11 +177,41 @@ void MainThreadEventQueue::PopEventOnMainThread() { |
| in_flight_event_.reset(); |
| } |
| +void MainThreadEventQueue::PossiblyScheduleMainFrame() { |
| + if (!handle_raf_aligned_input_) |
| + return; |
| + bool needs_main_frame = false; |
| + { |
| + base::AutoLock lock(shared_state_lock_); |
| + if (!shared_state_.sent_main_frame_request_ && |
| + !shared_state_.events_.empty() && |
| + isContinuousEvent(shared_state_.events_.front())) { |
| + needs_main_frame = !shared_state_.sent_main_frame_request_; |
| + shared_state_.sent_main_frame_request_ = false; |
| + } |
| + } |
| + if (needs_main_frame) |
| + client_->NeedsMainFrame(routing_id_); |
| +} |
| + |
| +void MainThreadEventQueue::DispatchSingleEvent() { |
| + { |
| + base::AutoLock lock(shared_state_lock_); |
| + if (shared_state_.events_.empty()) |
| + return; |
| + |
| + in_flight_event_ = shared_state_.events_.Pop(); |
| + } |
| + DispatchInFlightEvent(); |
| + PossiblyScheduleMainFrame(); |
| +} |
| + |
| void MainThreadEventQueue::EventHandled(blink::WebInputEvent::Type type, |
| InputEventAckState ack_result) { |
| - if (in_flight_event_) { |
| - // Send acks for blocking touch events. |
| - for (const auto id : in_flight_event_->eventsToAck()) { |
| + if (in_flight_event_ && |
| + in_flight_event_->dispatchType() == DISPATCH_TYPE_BLOCKING) { |
| + // We should only have blocking touch events that need coalescing. |
| + for (const auto id : in_flight_event_->coalescedEventIds()) { |
| client_->SendInputEventAck(routing_id_, type, ack_result, id); |
| if (renderer_scheduler_) { |
| renderer_scheduler_->DidHandleInputEventOnMainThread( |
| @@ -146,23 +221,68 @@ void MainThreadEventQueue::EventHandled(blink::WebInputEvent::Type type, |
| } |
| } |
| +void MainThreadEventQueue::DispatchRafAlignedInput() { |
| + if (!handle_raf_aligned_input_) |
| + return; |
| + |
| + { |
| + base::AutoLock lock(shared_state_lock_); |
| + shared_state_.sent_main_frame_request_ = false; |
| + } |
| + |
| + for (size_t i = 0; i < kMaxEventsPerRafTask; ++i) { |
| + { |
| + base::AutoLock lock(shared_state_lock_); |
| + if (shared_state_.events_.empty()) |
| + break; |
| + |
| + if (!isContinuousEvent(shared_state_.events_.front())) |
| + break; |
| + in_flight_event_ = shared_state_.events_.Pop(); |
| + } |
| + DispatchInFlightEvent(); |
| + } |
| + PossiblyScheduleMainFrame(); |
| +} |
| + |
| void MainThreadEventQueue::SendEventNotificationToMainThread() { |
| main_task_runner_->PostTask( |
| - FROM_HERE, base::Bind(&MainThreadEventQueue::PopEventOnMainThread, |
| - this)); |
| + FROM_HERE, base::Bind(&MainThreadEventQueue::DispatchSingleEvent, this)); |
| } |
| void MainThreadEventQueue::QueueEvent( |
| std::unique_ptr<EventWithDispatchType> event) { |
| - bool send_notification = false; |
| + bool is_continuous = isContinuousEvent(event); |
| + size_t send_notification_count = 0; |
| + bool needs_main_frame = false; |
| { |
| - base::AutoLock lock(event_queue_lock_); |
| - size_t size_before = events_.size(); |
| - events_.Queue(std::move(event)); |
| - send_notification = events_.size() != size_before; |
| + base::AutoLock lock(shared_state_lock_); |
| + size_t size_before = shared_state_.events_.size(); |
| + shared_state_.events_.Queue(std::move(event)); |
| + size_t size_after = shared_state_.events_.size(); |
| + if (size_before != size_after) { |
| + if (!handle_raf_aligned_input_) { |
| + send_notification_count = 1; |
| + } else if (!is_continuous) { |
| + send_notification_count = 1; |
| + // If we had just enqueued a non-rAF input event we will send a series |
| + // of normal post messages to ensure they are all handled right away. |
| + for (size_t pos = size_after - 1; pos >= 1; --pos) { |
| + if (isContinuousEvent(shared_state_.events_.at(pos - 1))) |
| + send_notification_count++; |
| + else |
| + break; |
| + } |
| + } else { |
| + needs_main_frame = !shared_state_.sent_main_frame_request_; |
| + shared_state_.sent_main_frame_request_ = true; |
| + } |
| + } |
| } |
| - if (send_notification) |
| + for (size_t i = 0; i < send_notification_count; ++i) |
| SendEventNotificationToMainThread(); |
| + if (needs_main_frame) |
| + client_->NeedsMainFrame(routing_id_); |
| } |
| } // namespace content |