Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / renderer_host / input / input_router_impl_perftest.cc
blob9d0924f2efa6f4e203a32cd733220cae20b551bb
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 NativeWebKeyboardEvent& event,
35 InputEventAckState ack_result) override {
36 ++ack_count_;
38 void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
39 InputEventAckState ack_result) override {
40 ++ack_count_;
42 void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
43 InputEventAckState ack_result) override {
44 ++ack_count_;
46 void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
47 InputEventAckState ack_result) override {
48 ++ack_count_;
50 void OnUnexpectedEventAck(UnexpectedEventAckType type) override {
51 ++ack_count_;
54 size_t GetAndResetAckCount() {
55 size_t ack_count = ack_count_;
56 ack_count_ = 0;
57 return ack_count;
60 size_t ack_count() const { return ack_count_; }
62 private:
63 size_t ack_count_;
66 class NullInputRouterClient : public InputRouterClient {
67 public:
68 NullInputRouterClient() {}
69 ~NullInputRouterClient() override {}
71 // InputRouterClient
72 InputEventAckState FilterInputEvent(
73 const blink::WebInputEvent& input_event,
74 const ui::LatencyInfo& latency_info) override {
75 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
77 void IncrementInFlightEventCount() override {}
78 void DecrementInFlightEventCount() override {}
79 void OnHasTouchEventHandlers(bool has_handlers) override {}
80 void DidFlush() override {}
81 void DidOverscroll(const DidOverscrollParams& params) override {}
82 void DidStopFlinging() override {}
85 class NullIPCSender : public IPC::Sender {
86 public:
87 NullIPCSender() : sent_count_(0) {}
88 ~NullIPCSender() override {}
90 bool Send(IPC::Message* message) override {
91 delete message;
92 ++sent_count_;
93 return true;
96 size_t GetAndResetSentEventCount() {
97 size_t message_count = sent_count_;
98 sent_count_ = 0;
99 return message_count;
102 bool HasMessages() const { return sent_count_ > 0; }
104 private:
105 size_t sent_count_;
108 // TODO(jdduke): Use synthetic gesture pipeline, crbug.com/344598.
109 typedef std::vector<WebGestureEvent> Gestures;
110 Gestures BuildScrollSequence(size_t steps,
111 const gfx::Vector2dF& origin,
112 const gfx::Vector2dF& distance) {
113 Gestures gestures;
114 const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
116 WebGestureEvent gesture;
117 gesture.type = WebInputEvent::GestureScrollBegin;
118 gesture.x = origin.x();
119 gesture.y = origin.y();
120 gestures.push_back(gesture);
122 gesture.type = WebInputEvent::GestureScrollUpdate;
123 gesture.data.scrollUpdate.deltaX = delta.x();
124 gesture.data.scrollUpdate.deltaY = delta.y();
125 for (size_t i = 0; i < steps; ++i) {
126 gesture.x += delta.x();
127 gesture.y += delta.y();
128 gestures.push_back(gesture);
131 gesture.type = WebInputEvent::GestureScrollEnd;
132 gestures.push_back(gesture);
133 return gestures;
136 typedef std::vector<WebTouchEvent> Touches;
137 Touches BuildTouchSequence(size_t steps,
138 const gfx::Vector2dF& origin,
139 const gfx::Vector2dF& distance) {
140 Touches touches;
141 const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
143 WebTouchEvent touch;
144 touch.touchesLength = 1;
145 touch.type = WebInputEvent::TouchStart;
146 touch.touches[0].id = 0;
147 touch.touches[0].state = WebTouchPoint::StatePressed;
148 touch.touches[0].position.x = origin.x();
149 touch.touches[0].position.y = origin.y();
150 touch.touches[0].screenPosition.x = origin.x();
151 touch.touches[0].screenPosition.y = origin.y();
152 touches.push_back(touch);
154 touch.type = WebInputEvent::TouchMove;
155 touch.touches[0].state = WebTouchPoint::StateMoved;
156 for (size_t i = 0; i < steps; ++i) {
157 touch.touches[0].position.x += delta.x();
158 touch.touches[0].position.y += delta.y();
159 touch.touches[0].screenPosition.x += delta.x();
160 touch.touches[0].screenPosition.y += delta.y();
161 touches.push_back(touch);
164 touch.type = WebInputEvent::TouchEnd;
165 touch.touches[0].state = WebTouchPoint::StateReleased;
166 touches.push_back(touch);
167 return touches;
170 class InputEventTimer {
171 public:
172 InputEventTimer(const char* test_name, int64 event_count)
173 : test_name_(test_name),
174 event_count_(event_count),
175 start_(base::TimeTicks::Now()) {}
177 ~InputEventTimer() {
178 perf_test::PrintResult(
179 "avg_time_per_event",
181 test_name_,
182 static_cast<size_t>(((base::TimeTicks::Now() - start_) / event_count_)
183 .InMicroseconds()),
184 "us",
185 true);
188 private:
189 const char* test_name_;
190 int64 event_count_;
191 base::TimeTicks start_;
192 DISALLOW_COPY_AND_ASSIGN(InputEventTimer);
195 } // namespace
197 class InputRouterImplPerfTest : public testing::Test {
198 public:
199 InputRouterImplPerfTest() : last_input_id_(0) {}
200 ~InputRouterImplPerfTest() override {}
202 protected:
203 // testing::Test
204 void SetUp() override {
205 sender_.reset(new NullIPCSender());
206 client_.reset(new NullInputRouterClient());
207 ack_handler_.reset(new NullInputAckHandler());
208 input_router_.reset(new InputRouterImpl(sender_.get(),
209 client_.get(),
210 ack_handler_.get(),
211 MSG_ROUTING_NONE,
212 InputRouterImpl::Config()));
215 void TearDown() override {
216 base::MessageLoop::current()->RunUntilIdle();
218 input_router_.reset();
219 ack_handler_.reset();
220 client_.reset();
221 sender_.reset();
224 void SendEvent(const WebGestureEvent& gesture,
225 const ui::LatencyInfo& latency) {
226 input_router_->SendGestureEvent(
227 GestureEventWithLatencyInfo(gesture, latency));
230 void SendEvent(const WebTouchEvent& touch, const ui::LatencyInfo& latency) {
231 input_router_->SendTouchEvent(TouchEventWithLatencyInfo(touch, latency));
234 void SendEventAckIfNecessary(const blink::WebInputEvent& event,
235 InputEventAckState ack_result) {
236 if (!WebInputEventTraits::WillReceiveAckFromRenderer(event))
237 return;
238 InputEventAck ack(event.type, ack_result);
239 InputHostMsg_HandleInputEvent_ACK response(0, ack);
240 input_router_->OnMessageReceived(response);
243 void OnHasTouchEventHandlers(bool has_handlers) {
244 input_router_->OnMessageReceived(
245 ViewHostMsg_HasTouchEventHandlers(0, has_handlers));
248 size_t GetAndResetSentEventCount() {
249 return sender_->GetAndResetSentEventCount();
252 size_t GetAndResetAckCount() { return ack_handler_->GetAndResetAckCount(); }
254 size_t AckCount() const { return ack_handler_->ack_count(); }
256 int64 NextLatencyID() { return ++last_input_id_; }
258 ui::LatencyInfo CreateLatencyInfo() {
259 ui::LatencyInfo latency;
260 latency.AddLatencyNumber(
261 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 1, 0);
262 latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 1,
263 NextLatencyID());
264 return latency;
267 // TODO(jdduke): Use synthetic gesture pipeline, crbug.com/344598.
268 template <typename EventType>
269 void SimulateEventSequence(const char* test_name,
270 const std::vector<EventType>& events,
271 bool ack_delay,
272 size_t iterations) {
273 OnHasTouchEventHandlers(true);
275 const size_t event_count = events.size();
276 const size_t total_event_count = event_count * iterations;
278 InputEventTimer timer(test_name, total_event_count);
279 while (iterations--) {
280 size_t i = 0, ack_i = 0;
281 if (ack_delay)
282 SendEvent(events[i++], CreateLatencyInfo());
284 for (; i < event_count; ++i, ++ack_i) {
285 SendEvent(events[i], CreateLatencyInfo());
286 SendEventAckIfNecessary(events[ack_i], INPUT_EVENT_ACK_STATE_CONSUMED);
289 if (ack_delay)
290 SendEventAckIfNecessary(events.back(), INPUT_EVENT_ACK_STATE_CONSUMED);
292 EXPECT_EQ(event_count, GetAndResetSentEventCount());
293 EXPECT_EQ(event_count, GetAndResetAckCount());
297 void SimulateTouchAndScrollEventSequence(const char* test_name,
298 size_t steps,
299 const gfx::Vector2dF& origin,
300 const gfx::Vector2dF& distance,
301 size_t iterations) {
302 OnHasTouchEventHandlers(true);
304 Gestures gestures = BuildScrollSequence(steps, origin, distance);
305 Touches touches = BuildTouchSequence(steps, origin, distance);
306 ASSERT_EQ(touches.size(), gestures.size());
308 const size_t event_count = gestures.size();
309 const size_t total_event_count = event_count * iterations * 2;
311 InputEventTimer timer(test_name, total_event_count);
312 while (iterations--) {
313 for (size_t i = 0; i < event_count; ++i) {
314 SendEvent(touches[i], CreateLatencyInfo());
315 // Touches may not be forwarded after the scroll sequence has begun, so
316 // only ack if necessary.
317 if (!AckCount()) {
318 SendEventAckIfNecessary(touches[i],
319 INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
322 SendEvent(gestures[i], CreateLatencyInfo());
323 SendEventAckIfNecessary(gestures[i], INPUT_EVENT_ACK_STATE_CONSUMED);
324 EXPECT_EQ(2U, GetAndResetAckCount());
329 private:
330 int64 last_input_id_;
331 scoped_ptr<NullIPCSender> sender_;
332 scoped_ptr<NullInputRouterClient> client_;
333 scoped_ptr<NullInputAckHandler> ack_handler_;
334 scoped_ptr<InputRouterImpl> input_router_;
335 base::MessageLoopForUI message_loop_;
338 const size_t kDefaultSteps(100);
339 const size_t kDefaultIterations(100);
340 const gfx::Vector2dF kDefaultOrigin(100, 100);
341 const gfx::Vector2dF kDefaultDistance(500, 500);
343 TEST_F(InputRouterImplPerfTest, TouchSwipe) {
344 SimulateEventSequence(
345 "TouchSwipe ",
346 BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
347 false,
348 kDefaultIterations);
351 TEST_F(InputRouterImplPerfTest, TouchSwipeDelayedAck) {
352 SimulateEventSequence(
353 "TouchSwipeDelayedAck ",
354 BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
355 true,
356 kDefaultIterations);
359 TEST_F(InputRouterImplPerfTest, GestureScroll) {
360 SimulateEventSequence(
361 "GestureScroll ",
362 BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
363 false,
364 kDefaultIterations);
367 TEST_F(InputRouterImplPerfTest, GestureScrollDelayedAck) {
368 SimulateEventSequence(
369 "GestureScrollDelayedAck ",
370 BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
371 true,
372 kDefaultIterations);
375 TEST_F(InputRouterImplPerfTest, TouchSwipeToGestureScroll) {
376 SimulateTouchAndScrollEventSequence("TouchSwipeToGestureScroll ",
377 kDefaultSteps,
378 kDefaultOrigin,
379 kDefaultDistance,
380 kDefaultIterations);
383 } // namespace content