Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / renderer_host / input / input_router_impl_perftest.cc
blob48def2af907f0dfac7876644ee52513f3ed5655c
1 // Copyright 2014 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.
5 #include "base/basictypes.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "content/browser/renderer_host/input/input_ack_handler.h"
8 #include "content/browser/renderer_host/input/input_router_client.h"
9 #include "content/browser/renderer_host/input/input_router_impl.h"
10 #include "content/common/input/web_input_event_traits.h"
11 #include "content/common/input_messages.h"
12 #include "content/common/view_messages.h"
13 #include "ipc/ipc_sender.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "testing/perf/perf_test.h"
16 #include "ui/gfx/geometry/vector2d_f.h"
18 using base::TimeDelta;
19 using blink::WebGestureEvent;
20 using blink::WebInputEvent;
21 using blink::WebTouchEvent;
22 using blink::WebTouchPoint;
24 namespace content {
26 namespace {
28 class NullInputAckHandler : public InputAckHandler {
29 public:
30 NullInputAckHandler() : ack_count_(0) {}
31 ~NullInputAckHandler() override {}
33 // InputAckHandler
34 void OnKeyboardEventAck(const NativeWebKeyboardEventWithLatencyInfo& event,
35 InputEventAckState ack_result) override {
36 ++ack_count_;
38 void OnMouseEventAck(const MouseEventWithLatencyInfo& event,
39 InputEventAckState ack_result) override {
40 ++ack_count_;
42 void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
43 InputEventAckState ack_result) override {
44 ++ack_count_;
46 void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
47 InputEventAckState ack_result) override {
48 ++ack_count_;
50 void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
51 InputEventAckState ack_result) override {
52 ++ack_count_;
54 void OnUnexpectedEventAck(UnexpectedEventAckType type) override {
55 ++ack_count_;
58 size_t GetAndResetAckCount() {
59 size_t ack_count = ack_count_;
60 ack_count_ = 0;
61 return ack_count;
64 size_t ack_count() const { return ack_count_; }
66 private:
67 size_t ack_count_;
70 class NullInputRouterClient : public InputRouterClient {
71 public:
72 NullInputRouterClient() {}
73 ~NullInputRouterClient() override {}
75 // InputRouterClient
76 InputEventAckState FilterInputEvent(
77 const blink::WebInputEvent& input_event,
78 const ui::LatencyInfo& latency_info) override {
79 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
81 void IncrementInFlightEventCount() override {}
82 void DecrementInFlightEventCount() override {}
83 void OnHasTouchEventHandlers(bool has_handlers) override {}
84 void DidFlush() override {}
85 void DidOverscroll(const DidOverscrollParams& params) override {}
86 void DidStopFlinging() override {}
89 class NullIPCSender : public IPC::Sender {
90 public:
91 NullIPCSender() : sent_count_(0) {}
92 ~NullIPCSender() override {}
94 bool Send(IPC::Message* message) override {
95 delete message;
96 ++sent_count_;
97 return true;
100 size_t GetAndResetSentEventCount() {
101 size_t message_count = sent_count_;
102 sent_count_ = 0;
103 return message_count;
106 bool HasMessages() const { return sent_count_ > 0; }
108 private:
109 size_t sent_count_;
112 // TODO(jdduke): Use synthetic gesture pipeline, crbug.com/344598.
113 typedef std::vector<WebGestureEvent> Gestures;
114 Gestures BuildScrollSequence(size_t steps,
115 const gfx::Vector2dF& origin,
116 const gfx::Vector2dF& distance) {
117 Gestures gestures;
118 const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
120 WebGestureEvent gesture;
121 gesture.type = WebInputEvent::GestureScrollBegin;
122 gesture.x = origin.x();
123 gesture.y = origin.y();
124 gestures.push_back(gesture);
126 gesture.type = WebInputEvent::GestureScrollUpdate;
127 gesture.data.scrollUpdate.deltaX = delta.x();
128 gesture.data.scrollUpdate.deltaY = delta.y();
129 for (size_t i = 0; i < steps; ++i) {
130 gesture.x += delta.x();
131 gesture.y += delta.y();
132 gestures.push_back(gesture);
135 gesture.type = WebInputEvent::GestureScrollEnd;
136 gestures.push_back(gesture);
137 return gestures;
140 typedef std::vector<WebTouchEvent> Touches;
141 Touches BuildTouchSequence(size_t steps,
142 const gfx::Vector2dF& origin,
143 const gfx::Vector2dF& distance) {
144 Touches touches;
145 const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
147 WebTouchEvent touch;
148 touch.touchesLength = 1;
149 touch.type = WebInputEvent::TouchStart;
150 touch.touches[0].id = 0;
151 touch.touches[0].state = WebTouchPoint::StatePressed;
152 touch.touches[0].position.x = origin.x();
153 touch.touches[0].position.y = origin.y();
154 touch.touches[0].screenPosition.x = origin.x();
155 touch.touches[0].screenPosition.y = origin.y();
156 touches.push_back(touch);
158 touch.type = WebInputEvent::TouchMove;
159 touch.touches[0].state = WebTouchPoint::StateMoved;
160 for (size_t i = 0; i < steps; ++i) {
161 touch.touches[0].position.x += delta.x();
162 touch.touches[0].position.y += delta.y();
163 touch.touches[0].screenPosition.x += delta.x();
164 touch.touches[0].screenPosition.y += delta.y();
165 touches.push_back(touch);
168 touch.type = WebInputEvent::TouchEnd;
169 touch.touches[0].state = WebTouchPoint::StateReleased;
170 touches.push_back(touch);
171 return touches;
174 class InputEventTimer {
175 public:
176 InputEventTimer(const char* test_name, int64 event_count)
177 : test_name_(test_name),
178 event_count_(event_count),
179 start_(base::TimeTicks::Now()) {}
181 ~InputEventTimer() {
182 perf_test::PrintResult(
183 "avg_time_per_event",
185 test_name_,
186 static_cast<size_t>(((base::TimeTicks::Now() - start_) / event_count_)
187 .InMicroseconds()),
188 "us",
189 true);
192 private:
193 const char* test_name_;
194 int64 event_count_;
195 base::TimeTicks start_;
196 DISALLOW_COPY_AND_ASSIGN(InputEventTimer);
199 } // namespace
201 class InputRouterImplPerfTest : public testing::Test {
202 public:
203 InputRouterImplPerfTest() : last_input_id_(0) {}
204 ~InputRouterImplPerfTest() override {}
206 protected:
207 // testing::Test
208 void SetUp() override {
209 sender_.reset(new NullIPCSender());
210 client_.reset(new NullInputRouterClient());
211 ack_handler_.reset(new NullInputAckHandler());
212 input_router_.reset(new InputRouterImpl(sender_.get(),
213 client_.get(),
214 ack_handler_.get(),
215 MSG_ROUTING_NONE,
216 InputRouterImpl::Config()));
219 void TearDown() override {
220 base::MessageLoop::current()->RunUntilIdle();
222 input_router_.reset();
223 ack_handler_.reset();
224 client_.reset();
225 sender_.reset();
228 void SendEvent(const WebGestureEvent& gesture,
229 const ui::LatencyInfo& latency) {
230 input_router_->SendGestureEvent(
231 GestureEventWithLatencyInfo(gesture, latency));
234 void SendEvent(const WebTouchEvent& touch, const ui::LatencyInfo& latency) {
235 input_router_->SendTouchEvent(TouchEventWithLatencyInfo(touch, latency));
238 void SendEventAckIfNecessary(const blink::WebInputEvent& event,
239 InputEventAckState ack_result) {
240 if (!WebInputEventTraits::WillReceiveAckFromRenderer(event))
241 return;
242 InputEventAck ack(event.type, ack_result);
243 InputHostMsg_HandleInputEvent_ACK response(0, ack);
244 input_router_->OnMessageReceived(response);
247 void OnHasTouchEventHandlers(bool has_handlers) {
248 input_router_->OnMessageReceived(
249 ViewHostMsg_HasTouchEventHandlers(0, has_handlers));
252 size_t GetAndResetSentEventCount() {
253 return sender_->GetAndResetSentEventCount();
256 size_t GetAndResetAckCount() { return ack_handler_->GetAndResetAckCount(); }
258 size_t AckCount() const { return ack_handler_->ack_count(); }
260 int64 NextLatencyID() { return ++last_input_id_; }
262 ui::LatencyInfo CreateLatencyInfo() {
263 ui::LatencyInfo latency;
264 latency.AddLatencyNumber(
265 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 1, 0);
266 latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 1,
267 NextLatencyID());
268 return latency;
271 // TODO(jdduke): Use synthetic gesture pipeline, crbug.com/344598.
272 template <typename EventType>
273 void SimulateEventSequence(const char* test_name,
274 const std::vector<EventType>& events,
275 bool ack_delay,
276 size_t iterations) {
277 OnHasTouchEventHandlers(true);
279 const size_t event_count = events.size();
280 const size_t total_event_count = event_count * iterations;
282 InputEventTimer timer(test_name, total_event_count);
283 while (iterations--) {
284 size_t i = 0, ack_i = 0;
285 if (ack_delay)
286 SendEvent(events[i++], CreateLatencyInfo());
288 for (; i < event_count; ++i, ++ack_i) {
289 SendEvent(events[i], CreateLatencyInfo());
290 SendEventAckIfNecessary(events[ack_i], INPUT_EVENT_ACK_STATE_CONSUMED);
293 if (ack_delay)
294 SendEventAckIfNecessary(events.back(), INPUT_EVENT_ACK_STATE_CONSUMED);
296 EXPECT_EQ(event_count, GetAndResetSentEventCount());
297 EXPECT_EQ(event_count, GetAndResetAckCount());
301 void SimulateTouchAndScrollEventSequence(const char* test_name,
302 size_t steps,
303 const gfx::Vector2dF& origin,
304 const gfx::Vector2dF& distance,
305 size_t iterations) {
306 OnHasTouchEventHandlers(true);
308 Gestures gestures = BuildScrollSequence(steps, origin, distance);
309 Touches touches = BuildTouchSequence(steps, origin, distance);
310 ASSERT_EQ(touches.size(), gestures.size());
312 const size_t event_count = gestures.size();
313 const size_t total_event_count = event_count * iterations * 2;
315 InputEventTimer timer(test_name, total_event_count);
316 while (iterations--) {
317 for (size_t i = 0; i < event_count; ++i) {
318 SendEvent(touches[i], CreateLatencyInfo());
319 // Touches may not be forwarded after the scroll sequence has begun, so
320 // only ack if necessary.
321 if (!AckCount()) {
322 SendEventAckIfNecessary(touches[i],
323 INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
326 SendEvent(gestures[i], CreateLatencyInfo());
327 SendEventAckIfNecessary(gestures[i], INPUT_EVENT_ACK_STATE_CONSUMED);
328 EXPECT_EQ(2U, GetAndResetAckCount());
333 private:
334 int64 last_input_id_;
335 scoped_ptr<NullIPCSender> sender_;
336 scoped_ptr<NullInputRouterClient> client_;
337 scoped_ptr<NullInputAckHandler> ack_handler_;
338 scoped_ptr<InputRouterImpl> input_router_;
339 base::MessageLoopForUI message_loop_;
342 const size_t kDefaultSteps(100);
343 const size_t kDefaultIterations(100);
344 const gfx::Vector2dF kDefaultOrigin(100, 100);
345 const gfx::Vector2dF kDefaultDistance(500, 500);
347 TEST_F(InputRouterImplPerfTest, TouchSwipe) {
348 SimulateEventSequence(
349 "TouchSwipe ",
350 BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
351 false,
352 kDefaultIterations);
355 TEST_F(InputRouterImplPerfTest, TouchSwipeDelayedAck) {
356 SimulateEventSequence(
357 "TouchSwipeDelayedAck ",
358 BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
359 true,
360 kDefaultIterations);
363 TEST_F(InputRouterImplPerfTest, GestureScroll) {
364 SimulateEventSequence(
365 "GestureScroll ",
366 BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
367 false,
368 kDefaultIterations);
371 TEST_F(InputRouterImplPerfTest, GestureScrollDelayedAck) {
372 SimulateEventSequence(
373 "GestureScrollDelayedAck ",
374 BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
375 true,
376 kDefaultIterations);
379 TEST_F(InputRouterImplPerfTest, TouchSwipeToGestureScroll) {
380 SimulateTouchAndScrollEventSequence("TouchSwipeToGestureScroll ",
381 kDefaultSteps,
382 kDefaultOrigin,
383 kDefaultDistance,
384 kDefaultIterations);
387 } // namespace content