Commit 4b3f1a99 authored by tdresser's avatar tdresser Committed by Commit bot

Input Latency traced correctly for mouse events.

Previously, in the case where no swap was produced, we didn't
terminate mouse event async slices. Now we do.

This requires making some of the events blocking, as we need to know whether or not renderering was scheduled at the time we process the event ack. If the event is non-blocking, we receive a synthetic ACK immediately, and don't know whether or not rendering will be scheduled.

BUG=722807

Review-Url: https://codereview.chromium.org/2884953002
Cr-Commit-Position: refs/heads/master@{#473334}
parent 38a14eb8
...@@ -205,9 +205,7 @@ void InputRouterImpl::SendTouchEvent( ...@@ -205,9 +205,7 @@ void InputRouterImpl::SendTouchEvent(
// TouchpadTapSuppressionController. // TouchpadTapSuppressionController.
void InputRouterImpl::SendMouseEventImmediately( void InputRouterImpl::SendMouseEventImmediately(
const MouseEventWithLatencyInfo& mouse_event) { const MouseEventWithLatencyInfo& mouse_event) {
if (mouse_event.event.GetType() == blink::WebInputEvent::kMouseMove) mouse_event_queue_.push_back(mouse_event);
mouse_move_queue_.push_back(mouse_event);
FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency); FilterAndSendWebInputEvent(mouse_event.event, mouse_event.latency);
} }
...@@ -238,7 +236,7 @@ void InputRouterImpl::RequestNotificationWhenFlushed() { ...@@ -238,7 +236,7 @@ void InputRouterImpl::RequestNotificationWhenFlushed() {
bool InputRouterImpl::HasPendingEvents() const { bool InputRouterImpl::HasPendingEvents() const {
return !touch_event_queue_->Empty() || !gesture_event_queue_.empty() || return !touch_event_queue_->Empty() || !gesture_event_queue_.empty() ||
!key_queue_.empty() || !mouse_move_queue_.empty() || !key_queue_.empty() || !mouse_event_queue_.empty() ||
wheel_event_queue_.has_pending() || select_message_pending_ || wheel_event_queue_.has_pending() || select_message_pending_ ||
move_caret_pending_ || active_renderer_fling_count_ > 0; move_caret_pending_ || active_renderer_fling_count_ > 0;
} }
...@@ -585,15 +583,12 @@ void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type, ...@@ -585,15 +583,12 @@ void InputRouterImpl::ProcessKeyboardAck(blink::WebInputEvent::Type type,
void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type, void InputRouterImpl::ProcessMouseAck(blink::WebInputEvent::Type type,
InputEventAckState ack_result, InputEventAckState ack_result,
const ui::LatencyInfo& latency) { const ui::LatencyInfo& latency) {
if (type != WebInputEvent::kMouseMove) if (mouse_event_queue_.empty()) {
return;
if (mouse_move_queue_.empty()) {
ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_ACK); ack_handler_->OnUnexpectedEventAck(InputAckHandler::UNEXPECTED_ACK);
} else { } else {
MouseEventWithLatencyInfo front_item = mouse_move_queue_.front(); MouseEventWithLatencyInfo front_item = mouse_event_queue_.front();
front_item.latency.AddNewLatencyFrom(latency); front_item.latency.AddNewLatencyFrom(latency);
mouse_move_queue_.pop_front(); mouse_event_queue_.pop_front();
ack_handler_->OnMouseEventAck(front_item, ack_result); ack_handler_->OnMouseEventAck(front_item, ack_result);
} }
} }
......
...@@ -230,8 +230,8 @@ class CONTENT_EXPORT InputRouterImpl ...@@ -230,8 +230,8 @@ class CONTENT_EXPORT InputRouterImpl
// A queue of the mouse move events sent to the renderer. Similar // A queue of the mouse move events sent to the renderer. Similar
// to |key_queue_|. // to |key_queue_|.
typedef std::deque<MouseEventWithLatencyInfo> MouseMoveQueue; typedef std::deque<MouseEventWithLatencyInfo> MouseEventQueue;
MouseMoveQueue mouse_move_queue_; MouseEventQueue mouse_event_queue_;
// A queue of keyboard events. We can't trust data from the renderer so we // A queue of keyboard events. We can't trust data from the renderer so we
// stuff key events into a queue and pop them out on ACK, feeding our copy // stuff key events into a queue and pop them out on ACK, feeding our copy
......
...@@ -1211,19 +1211,22 @@ TEST_F(InputRouterImplTest, MouseTypesIgnoringAck) { ...@@ -1211,19 +1211,22 @@ TEST_F(InputRouterImplTest, MouseTypesIgnoringAck) {
ASSERT_LT(start_type, end_type); ASSERT_LT(start_type, end_type);
for (int i = start_type; i <= end_type; ++i) { for (int i = start_type; i <= end_type; ++i) {
WebInputEvent::Type type = static_cast<WebInputEvent::Type>(i); WebInputEvent::Type type = static_cast<WebInputEvent::Type>(i);
int expected_in_flight_event_count =
!ShouldBlockEventStream(GetEventWithType(type)) ? 0 : 1;
// Note: Only MouseMove ack is forwarded to the ack handler.
SimulateMouseEvent(type, 0, 0); SimulateMouseEvent(type, 0, 0);
EXPECT_EQ(1U, GetSentMessageCountAndResetSink()); EXPECT_EQ(1U, GetSentMessageCountAndResetSink());
EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
EXPECT_EQ(expected_in_flight_event_count, client_->in_flight_event_count()); if (ShouldBlockEventStream(GetEventWithType(type))) {
if (expected_in_flight_event_count) { EXPECT_EQ(0U, ack_handler_->GetAndResetAckCount());
EXPECT_EQ(1, client_->in_flight_event_count());
SendInputEventACK(type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED); SendInputEventACK(type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
EXPECT_EQ(0U, GetSentMessageCountAndResetSink()); EXPECT_EQ(0U, GetSentMessageCountAndResetSink());
uint32_t expected_ack_count = type == WebInputEvent::kMouseMove ? 1 : 0; EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
EXPECT_EQ(expected_ack_count, ack_handler_->GetAndResetAckCount()); EXPECT_EQ(0, client_->in_flight_event_count());
} else {
// Note: events which don't block the event stream immediately receive
// synthetic ACKs.
EXPECT_EQ(1U, ack_handler_->GetAndResetAckCount());
EXPECT_EQ(0, client_->in_flight_event_count()); EXPECT_EQ(0, client_->in_flight_event_count());
} }
} }
......
// Copyright 2017 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.
#include <vector>
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "content/browser/renderer_host/input/synthetic_gesture.h"
#include "content/browser/renderer_host/input/synthetic_gesture_controller.h"
#include "content/browser/renderer_host/input/synthetic_gesture_target.h"
#include "content/browser/renderer_host/input/synthetic_tap_gesture.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/input/synthetic_gesture_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace {
const char kMouseUpDownDataURL[] =
"data:text/html;charset=utf-8,"
"<!DOCTYPE html>"
"<html>"
"<head>"
"<title>Mouse event trace events reported.</title>"
"<script src=\"../../resources/testharness.js\"></script>"
"<script src=\"../../resources/testharnessreport.js\"></script>"
"<style>"
"body {"
" height:3000px;"
"}"
"</style>"
"</head>"
"<body>"
"</body>"
"</html>";
} // namespace
namespace content {
class MouseLatencyBrowserTest : public ContentBrowserTest {
public:
MouseLatencyBrowserTest() : loop_(base::MessageLoop::TYPE_UI) {}
~MouseLatencyBrowserTest() override {}
RenderWidgetHostImpl* GetWidgetHost() {
return RenderWidgetHostImpl::From(
shell()->web_contents()->GetRenderViewHost()->GetWidget());
}
void OnSyntheticGestureCompleted(SyntheticGesture::Result result) {
EXPECT_EQ(SyntheticGesture::GESTURE_FINISHED, result);
runner_->Quit();
}
void OnTraceDataCollected(
std::unique_ptr<const base::DictionaryValue> metadata,
base::RefCountedString* trace_data_string) {
std::unique_ptr<base::Value> trace_data =
base::JSONReader::Read(trace_data_string->data());
ASSERT_TRUE(trace_data);
trace_data_ = *trace_data;
runner_->Quit();
}
protected:
void LoadURL() {
const GURL data_url(kMouseUpDownDataURL);
NavigateToURL(shell(), data_url);
RenderWidgetHostImpl* host = GetWidgetHost();
host->GetView()->SetSize(gfx::Size(400, 400));
}
// Generate mouse events for a synthetic click at |point|.
void DoSyncClick(const gfx::PointF& position) {
SyntheticTapGestureParams params;
params.gesture_source_type = SyntheticGestureParams::MOUSE_INPUT;
params.position = position;
params.duration_ms = 100;
std::unique_ptr<SyntheticTapGesture> gesture(
new SyntheticTapGesture(params));
GetWidgetHost()->QueueSyntheticGesture(
std::move(gesture),
base::Bind(&MouseLatencyBrowserTest::OnSyntheticGestureCompleted,
base::Unretained(this)));
// Runs until we get the OnSyntheticGestureCompleted callback
runner_ = base::MakeUnique<base::RunLoop>();
runner_->Run();
}
void StartTracing() {
base::trace_event::TraceConfig trace_config(
"{"
"\"enable_argument_filter\":false,"
"\"enable_systrace\":false,"
"\"included_categories\":["
"\"latencyInfo\""
"],"
"\"record_mode\":\"record-until-full\""
"}");
base::RunLoop run_loop;
ASSERT_TRUE(TracingController::GetInstance()->StartTracing(
trace_config, run_loop.QuitClosure()));
}
const base::Value& StopTracing() {
bool success = TracingController::GetInstance()->StopTracing(
TracingController::CreateStringSink(
base::Bind(&MouseLatencyBrowserTest::OnTraceDataCollected,
base::Unretained(this))));
EXPECT_TRUE(success);
// Runs until we get the OnTraceDataCollected callback, which populates
// trace_data_;
runner_ = base::MakeUnique<base::RunLoop>();
runner_->Run();
return trace_data_;
}
private:
base::MessageLoop loop_;
std::unique_ptr<base::RunLoop> runner_;
base::Value trace_data_;
DISALLOW_COPY_AND_ASSIGN(MouseLatencyBrowserTest);
};
// Ensures that LatencyInfo async slices are reported correctly for MouseUp and
// MouseDown events in the case where no swap is generated.
// Disabled on Android because we don't support synthetic mouse input on
// Android (crbug.com/723618).
#if defined(OS_ANDROID)
#define MAYBE_MouseDownAndUpRecordedWithoutSwap \
DISABLED_MouseDownAndUpRecordedWithoutSwap
#else
#define MAYBE_MouseDownAndUpRecordedWithoutSwap \
MouseDownAndUpRecordedWithoutSwap
#endif
IN_PROC_BROWSER_TEST_F(MouseLatencyBrowserTest,
MAYBE_MouseDownAndUpRecordedWithoutSwap) {
LoadURL();
StartTracing();
DoSyncClick(gfx::PointF(100, 100));
const base::Value trace_data = StopTracing();
const base::DictionaryValue* trace_data_dict;
trace_data.GetAsDictionary(&trace_data_dict);
ASSERT_TRUE(trace_data.GetAsDictionary(&trace_data_dict));
const base::ListValue* traceEvents;
ASSERT_TRUE(trace_data_dict->GetList("traceEvents", &traceEvents));
std::vector<std::string> trace_event_names;
for (size_t i = 0; i < traceEvents->GetSize(); ++i) {
const base::DictionaryValue* traceEvent;
ASSERT_TRUE(traceEvents->GetDictionary(i, &traceEvent));
std::string name;
ASSERT_TRUE(traceEvent->GetString("name", &name));
if (name != "InputLatency::MouseUp" && name != "InputLatency::MouseDown")
continue;
trace_event_names.push_back(name);
}
// We see two events per async slice, a begin and an end.
EXPECT_THAT(
trace_event_names,
testing::ElementsAre("InputLatency::MouseDown", "InputLatency::MouseDown",
"InputLatency::MouseUp", "InputLatency::MouseUp"));
}
} // namespace content
...@@ -671,6 +671,7 @@ test("content_browsertests") { ...@@ -671,6 +671,7 @@ test("content_browsertests") {
"../browser/renderer_host/input/composited_scrolling_browsertest.cc", "../browser/renderer_host/input/composited_scrolling_browsertest.cc",
"../browser/renderer_host/input/interaction_mq_dynamic_browsertest.cc", "../browser/renderer_host/input/interaction_mq_dynamic_browsertest.cc",
"../browser/renderer_host/input/main_thread_event_queue_browsertest.cc", "../browser/renderer_host/input/main_thread_event_queue_browsertest.cc",
"../browser/renderer_host/input/mouse_latency_browsertest.cc",
"../browser/renderer_host/input/non_blocking_event_browsertest.cc", "../browser/renderer_host/input/non_blocking_event_browsertest.cc",
"../browser/renderer_host/input/scroll_latency_browsertest.cc", "../browser/renderer_host/input/scroll_latency_browsertest.cc",
"../browser/renderer_host/input/touch_action_browsertest.cc", "../browser/renderer_host/input/touch_action_browsertest.cc",
......
...@@ -181,10 +181,6 @@ bool WebInputEventTraits::ShouldBlockEventStream( ...@@ -181,10 +181,6 @@ bool WebInputEventTraits::ShouldBlockEventStream(
const WebInputEvent& event, const WebInputEvent& event,
bool raf_aligned_touch_enabled) { bool raf_aligned_touch_enabled) {
switch (event.GetType()) { switch (event.GetType()) {
case WebInputEvent::kMouseDown:
case WebInputEvent::kMouseUp:
case WebInputEvent::kMouseEnter:
case WebInputEvent::kMouseLeave:
case WebInputEvent::kContextMenu: case WebInputEvent::kContextMenu:
case WebInputEvent::kGestureScrollBegin: case WebInputEvent::kGestureScrollBegin:
case WebInputEvent::kGestureScrollEnd: case WebInputEvent::kGestureScrollEnd:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment