Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(60)

Side by Side Diff: content/browser/renderer_host/input/input_router_impl_perftest.cc

Issue 170913002: Add InputRouter perftests for touches and scroll gestures (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updates Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | content/content_tests.gypi » ('j') | content/content_tests.gypi » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
tdresser 2014/02/18 19:46:00 2014
jdduke (slow) 2014/02/18 20:16:10 Done.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/basictypes.h"
6 #include "base/command_line.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "content/browser/renderer_host/input/input_ack_handler.h"
9 #include "content/browser/renderer_host/input/input_router_client.h"
10 #include "content/browser/renderer_host/input/input_router_impl.h"
11 #include "content/common/input/web_input_event_traits.h"
12 #include "content/common/input_messages.h"
13 #include "content/common/view_messages.h"
14 #include "content/public/common/content_switches.h"
15 #include "ipc/ipc_sender.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "testing/perf/perf_test.h"
18 #include "ui/gfx/geometry/vector2d_f.h"
19
20 using base::TimeDelta;
21 using blink::WebGestureEvent;
22 using blink::WebInputEvent;
23 using blink::WebTouchEvent;
24 using blink::WebTouchPoint;
25
26 namespace content {
27
28 namespace {
29
30 class NullInputAckHandler : public InputAckHandler {
31 public:
32 NullInputAckHandler() : ack_count_(0) {}
33 virtual ~NullInputAckHandler() {}
34
35 // InputAckHandler
36 virtual void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
37 InputEventAckState ack_result) OVERRIDE {
38 ++ack_count_;
39 }
40 virtual void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
41 InputEventAckState ack_result) OVERRIDE {
42 ++ack_count_;
43 }
44 virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
45 InputEventAckState ack_result) OVERRIDE {
46 ++ack_count_;
47 }
48 virtual void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
49 InputEventAckState ack_result) OVERRIDE {
50 ++ack_count_;
51 }
52 virtual void OnUnexpectedEventAck(UnexpectedEventAckType type) OVERRIDE {
53 ++ack_count_;
54 }
55
56 size_t GetAndResetAckCount() {
57 size_t ack_count = ack_count_;
58 ack_count_ = 0;
59 return ack_count;
60 }
61
62 size_t ack_count() const { return ack_count_; }
63
64 private:
65 size_t ack_count_;
66 };
67
68 class NullInputRouterClient : public InputRouterClient {
69 public:
70 NullInputRouterClient() {}
71 virtual ~NullInputRouterClient() {}
72
73 // InputRouterClient
74 virtual InputEventAckState FilterInputEvent(
75 const blink::WebInputEvent& input_event,
76 const ui::LatencyInfo& latency_info) OVERRIDE {
77 return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
78 }
79 virtual void IncrementInFlightEventCount() OVERRIDE {}
80 virtual void DecrementInFlightEventCount() OVERRIDE {}
81 virtual void OnHasTouchEventHandlers(bool has_handlers) OVERRIDE {}
82 virtual OverscrollController* GetOverscrollController() const OVERRIDE {
83 return NULL;
84 }
85 virtual void DidFlush() OVERRIDE {}
86 virtual void SetNeedsFlush() OVERRIDE {}
87 };
88
89 class NullIPCSender : public IPC::Sender {
90 public:
91 NullIPCSender() : sent_count_(0) {}
92 virtual ~NullIPCSender() {}
93
94 virtual bool Send(IPC::Message* message) {
95 delete message;
96 ++sent_count_;
97 return true;
98 }
99
100 size_t GetAndResetSentEventCount() {
101 size_t message_count = sent_count_;
102 sent_count_ = 0;
103 return message_count;
104 }
105
106 bool HasMessages() const { return sent_count_ > 0; }
107
108 private:
109 size_t sent_count_;
110 };
111
112 typedef std::vector<WebGestureEvent> Gestures;
113 Gestures BuildScrollSequence(size_t steps,
tdresser 2014/02/18 19:46:00 Could this use and/or be a part of synthetic_web_i
jdduke (slow) 2014/02/18 20:16:10 Yeah, I have a TODO below to that effect, but I'll
114 gfx::Vector2dF origin,
115 gfx::Vector2dF distance) {
116 Gestures gestures;
117 const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
118
119 WebGestureEvent gesture;
120 gesture.type = WebInputEvent::GestureScrollBegin;
121 gesture.x = origin.x();
122 gesture.y = origin.y();
123 gestures.push_back(gesture);
124
125 gesture.type = WebInputEvent::GestureScrollUpdate;
126 gesture.data.scrollUpdate.deltaX = delta.x();
127 gesture.data.scrollUpdate.deltaY = delta.y();
128 for (size_t i = 0; i < steps; ++i) {
129 gesture.x += delta.x();
130 gesture.y += delta.y();
131 gestures.push_back(gesture);
132 }
133
134 gesture.type = WebInputEvent::GestureScrollEnd;
135 gestures.push_back(gesture);
136 return gestures;
137 }
138
139 typedef std::vector<WebTouchEvent> Touches;
140 Touches BuildTouchSequence(size_t steps,
141 gfx::Vector2dF origin,
142 gfx::Vector2dF distance) {
143 Touches touches;
144 const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
145
146 WebTouchEvent touch;
147 touch.touchesLength = 1;
148 touch.type = WebInputEvent::TouchStart;
149 touch.touches[0].id = 0;
150 touch.touches[0].state = WebTouchPoint::StatePressed;
151 touch.touches[0].position.x = origin.x();
152 touch.touches[0].position.y = origin.y();
153 touch.touches[0].screenPosition.x = origin.x();
154 touch.touches[0].screenPosition.y = origin.y();
155 touches.push_back(touch);
156
157 touch.type = WebInputEvent::TouchMove;
158 touch.touches[0].state = WebTouchPoint::StateMoved;
159 for (size_t i = 0; i < steps; ++i) {
160 touch.touches[0].position.x += delta.x();
161 touch.touches[0].position.y += delta.y();
162 touch.touches[0].screenPosition.x += delta.x();
163 touch.touches[0].screenPosition.y += delta.y();
164 touches.push_back(touch);
165 }
166
167 touch.type = WebInputEvent::TouchEnd;
168 touch.touches[0].state = WebTouchPoint::StateReleased;
169 touches.push_back(touch);
170 return touches;
171 }
172
173 class InputEventTimer {
174 public:
175 InputEventTimer(const char* test_name, int64 event_count)
176 : test_name_(test_name),
177 event_count_(event_count),
178 start_(base::TimeTicks::Now()) {}
179
180 ~InputEventTimer() {
181 perf_test::PrintResult(
182 "avg_time_per_event",
183 "",
184 test_name_,
185 static_cast<size_t>(((base::TimeTicks::Now() - start_) / event_count_)
186 .InMicroseconds()),
187 "us",
188 true);
189 }
190
191 private:
192 const char* test_name_;
193 int64 event_count_;
194 base::TimeTicks start_;
195 DISALLOW_COPY_AND_ASSIGN(InputEventTimer);
196 };
197
198 } // namespace
199
200 class InputRouterImplPerfTest : public testing::Test {
201 public:
202 InputRouterImplPerfTest()
203 : last_sent_event_type_(WebInputEvent::Undefined),
204 last_input_id_(0) {}
205
206 virtual ~InputRouterImplPerfTest() {}
207
208 protected:
209 // testing::Test
210 virtual void SetUp() OVERRIDE {
211 if (!CommandLine::ForCurrentProcess()->HasSwitch(
212 switches::kDisableGestureDebounce)) {
213 CommandLine::ForCurrentProcess()->AppendSwitch(
214 switches::kDisableGestureDebounce);
215 }
216
217 sender_.reset(new NullIPCSender());
218 client_.reset(new NullInputRouterClient());
219 ack_handler_.reset(new NullInputAckHandler());
220 input_router_.reset(new InputRouterImpl(
221 sender_.get(), client_.get(), ack_handler_.get(), MSG_ROUTING_NONE));
222 }
223
224 virtual void TearDown() OVERRIDE {
225 base::MessageLoop::current()->RunUntilIdle();
226
227 input_router_.reset();
228 ack_handler_.reset();
229 client_.reset();
230 sender_.reset();
231 }
232
233 void SendEvent(const WebGestureEvent& gesture,
234 const ui::LatencyInfo& latency) {
235 input_router_->SendGestureEvent(
236 GestureEventWithLatencyInfo(gesture, latency));
237 }
238
239 void SendEvent(const WebTouchEvent& touch, const ui::LatencyInfo& latency) {
240 input_router_->SendTouchEvent(TouchEventWithLatencyInfo(touch, latency));
241 }
242
243 void SendInputEventACK(blink::WebInputEvent::Type type,
244 InputEventAckState ack_result) {
245 InputHostMsg_HandleInputEvent_ACK response(
246 0, type, ack_result, ui::LatencyInfo());
247 input_router_->OnMessageReceived(response);
248 }
249
250 InputRouterImpl* input_router() const { return input_router_.get(); }
251
252 void OnHasTouchEventHandlers(bool has_handlers) {
253 input_router_->OnMessageReceived(
254 ViewHostMsg_HasTouchEventHandlers(0, has_handlers));
255 }
256
257 size_t GetAndResetSentEventCount() {
258 return sender_->GetAndResetSentEventCount();
259 }
260
261 size_t GetAndResetAckCount() { return ack_handler_->GetAndResetAckCount(); }
262
263 size_t AckCount() const { return ack_handler_->ack_count(); }
264
265 int64 NextLatencyID() { return ++last_input_id_; }
266
267 ui::LatencyInfo CreateLatencyInfo() {
268 ui::LatencyInfo latency;
269 latency.AddLatencyNumber(
270 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 1, 0);
271 latency.AddLatencyNumber(
272 ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT,
273 1,
274 NextLatencyID());
275 return latency;
276 }
277
278 // TODO(jdduke): Use synthetic gesture pipeline.
279 template <typename EventType>
280 void RunTest(const char* test_name,
281 const std::vector<EventType>& events,
282 bool ack_delay,
283 size_t iterations) {
284 OnHasTouchEventHandlers(true);
285
286 const size_t event_count = events.size();
287 const size_t total_event_count = event_count * iterations;
288 ASSERT_LT(ack_delay, event_count);
289
290 InputEventTimer timer(test_name, total_event_count);
291 while (iterations--) {
292 size_t i = 0, ack_i = 0;
293 if (ack_delay)
294 SendEvent(events[i++], CreateLatencyInfo());
295
296 for (; i < event_count; ++i, ++ack_i) {
297 SendEvent(events[i], CreateLatencyInfo());
298 SendInputEventACK(events[ack_i].type, INPUT_EVENT_ACK_STATE_CONSUMED);
299 }
300
301 if (ack_delay)
302 SendInputEventACK(events.back().type, INPUT_EVENT_ACK_STATE_CONSUMED);
303
304 EXPECT_EQ(event_count, GetAndResetSentEventCount());
305 EXPECT_EQ(event_count, GetAndResetAckCount());
306 }
307 }
308
309 void RunTest(const char* test_name,
tdresser 2014/02/18 19:46:00 I'd prefer it if the "RunTest" methods had unique
jdduke (slow) 2014/02/18 20:16:10 Done.
310 size_t steps,
311 gfx::Vector2dF origin,
312 gfx::Vector2dF distance,
313 size_t iterations) {
314 OnHasTouchEventHandlers(true);
315
316 Gestures gestures = BuildScrollSequence(steps, origin, distance);
317 Touches touches = BuildTouchSequence(steps, origin, distance);
318 ASSERT_EQ(touches.size(), gestures.size());
319
320 const size_t event_count = gestures.size();
321 const size_t total_event_count = event_count * iterations * 2;
322
323 InputEventTimer timer(test_name, total_event_count);
324 while (iterations--) {
325 for (size_t i = 0; i < event_count; ++i) {
326 SendEvent(touches[i], CreateLatencyInfo());
327 // Touches may not be forwarded after the scroll sequence has begun, so
328 // only ack if necessary.
329 if (!AckCount()) {
330 SendInputEventACK(touches[i].type,
331 INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
332 }
333
334 SendEvent(gestures[i], CreateLatencyInfo());
335 SendInputEventACK(gestures[i].type, INPUT_EVENT_ACK_STATE_CONSUMED);
336 EXPECT_EQ(2U, GetAndResetAckCount());
337 }
338 }
339 }
340
341 private:
342 WebInputEvent::Type last_sent_event_type_;
343 int64 last_input_id_;
344 scoped_ptr<NullIPCSender> sender_;
345 scoped_ptr<NullInputRouterClient> client_;
346 scoped_ptr<NullInputAckHandler> ack_handler_;
347 scoped_ptr<InputRouterImpl> input_router_;
348 base::MessageLoopForUI message_loop_;
349 };
350
351 const size_t kDefaultSteps(100);
352 const size_t kDefaultIterations(100);
353 const gfx::Vector2dF kDefaultOrigin(100, 100);
354 const gfx::Vector2dF kDefaultDistance(500, 500);
355
356 TEST_F(InputRouterImplPerfTest, TouchSwipe) {
357 RunTest("TouchSwipe ",
358 BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
359 false,
360 kDefaultIterations);
361 }
362
363 TEST_F(InputRouterImplPerfTest, TouchSwipeDelayedAck) {
364 RunTest("TouchSwipeDelayedAck ",
365 BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
366 true,
367 kDefaultIterations);
368 }
369
370 TEST_F(InputRouterImplPerfTest, GestureScroll) {
371 RunTest("GestureScroll ",
372 BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
373 false,
374 kDefaultIterations);
375 }
376
377 TEST_F(InputRouterImplPerfTest, GestureScrollDelayedAck) {
378 RunTest("GestureScrollDelayedAck ",
379 BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
380 true,
381 kDefaultIterations);
382 }
383
384 TEST_F(InputRouterImplPerfTest, TouchSwipeToGestureScroll) {
385 RunTest("TouchSwipeToGestureScroll ",
386 kDefaultSteps,
387 kDefaultOrigin,
388 kDefaultDistance,
389 kDefaultIterations);
390 }
391
392 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/content_tests.gypi » ('j') | content/content_tests.gypi » ('J')

Powered by Google App Engine
This is Rietveld 408576698