Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |