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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | content/content_tests.gypi » ('j') | content/content_tests.gypi » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/browser/renderer_host/input/input_router_impl_perftest.cc
diff --git a/content/browser/renderer_host/input/input_router_impl_perftest.cc b/content/browser/renderer_host/input/input_router_impl_perftest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9e4b3c5ca473bb4679ca8b15e0e8a77f3683bedf
--- /dev/null
+++ b/content/browser/renderer_host/input/input_router_impl_perftest.cc
@@ -0,0 +1,392 @@
+// 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.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/renderer_host/input/input_ack_handler.h"
+#include "content/browser/renderer_host/input/input_router_client.h"
+#include "content/browser/renderer_host/input/input_router_impl.h"
+#include "content/common/input/web_input_event_traits.h"
+#include "content/common/input_messages.h"
+#include "content/common/view_messages.h"
+#include "content/public/common/content_switches.h"
+#include "ipc/ipc_sender.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+using base::TimeDelta;
+using blink::WebGestureEvent;
+using blink::WebInputEvent;
+using blink::WebTouchEvent;
+using blink::WebTouchPoint;
+
+namespace content {
+
+namespace {
+
+class NullInputAckHandler : public InputAckHandler {
+ public:
+ NullInputAckHandler() : ack_count_(0) {}
+ virtual ~NullInputAckHandler() {}
+
+ // InputAckHandler
+ virtual void OnKeyboardEventAck(const NativeWebKeyboardEvent& event,
+ InputEventAckState ack_result) OVERRIDE {
+ ++ack_count_;
+ }
+ virtual void OnWheelEventAck(const MouseWheelEventWithLatencyInfo& event,
+ InputEventAckState ack_result) OVERRIDE {
+ ++ack_count_;
+ }
+ virtual void OnTouchEventAck(const TouchEventWithLatencyInfo& event,
+ InputEventAckState ack_result) OVERRIDE {
+ ++ack_count_;
+ }
+ virtual void OnGestureEventAck(const GestureEventWithLatencyInfo& event,
+ InputEventAckState ack_result) OVERRIDE {
+ ++ack_count_;
+ }
+ virtual void OnUnexpectedEventAck(UnexpectedEventAckType type) OVERRIDE {
+ ++ack_count_;
+ }
+
+ size_t GetAndResetAckCount() {
+ size_t ack_count = ack_count_;
+ ack_count_ = 0;
+ return ack_count;
+ }
+
+ size_t ack_count() const { return ack_count_; }
+
+ private:
+ size_t ack_count_;
+};
+
+class NullInputRouterClient : public InputRouterClient {
+ public:
+ NullInputRouterClient() {}
+ virtual ~NullInputRouterClient() {}
+
+ // InputRouterClient
+ virtual InputEventAckState FilterInputEvent(
+ const blink::WebInputEvent& input_event,
+ const ui::LatencyInfo& latency_info) OVERRIDE {
+ return INPUT_EVENT_ACK_STATE_NOT_CONSUMED;
+ }
+ virtual void IncrementInFlightEventCount() OVERRIDE {}
+ virtual void DecrementInFlightEventCount() OVERRIDE {}
+ virtual void OnHasTouchEventHandlers(bool has_handlers) OVERRIDE {}
+ virtual OverscrollController* GetOverscrollController() const OVERRIDE {
+ return NULL;
+ }
+ virtual void DidFlush() OVERRIDE {}
+ virtual void SetNeedsFlush() OVERRIDE {}
+};
+
+class NullIPCSender : public IPC::Sender {
+ public:
+ NullIPCSender() : sent_count_(0) {}
+ virtual ~NullIPCSender() {}
+
+ virtual bool Send(IPC::Message* message) {
+ delete message;
+ ++sent_count_;
+ return true;
+ }
+
+ size_t GetAndResetSentEventCount() {
+ size_t message_count = sent_count_;
+ sent_count_ = 0;
+ return message_count;
+ }
+
+ bool HasMessages() const { return sent_count_ > 0; }
+
+ private:
+ size_t sent_count_;
+};
+
+typedef std::vector<WebGestureEvent> Gestures;
+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
+ gfx::Vector2dF origin,
+ gfx::Vector2dF distance) {
+ Gestures gestures;
+ const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
+
+ WebGestureEvent gesture;
+ gesture.type = WebInputEvent::GestureScrollBegin;
+ gesture.x = origin.x();
+ gesture.y = origin.y();
+ gestures.push_back(gesture);
+
+ gesture.type = WebInputEvent::GestureScrollUpdate;
+ gesture.data.scrollUpdate.deltaX = delta.x();
+ gesture.data.scrollUpdate.deltaY = delta.y();
+ for (size_t i = 0; i < steps; ++i) {
+ gesture.x += delta.x();
+ gesture.y += delta.y();
+ gestures.push_back(gesture);
+ }
+
+ gesture.type = WebInputEvent::GestureScrollEnd;
+ gestures.push_back(gesture);
+ return gestures;
+}
+
+typedef std::vector<WebTouchEvent> Touches;
+Touches BuildTouchSequence(size_t steps,
+ gfx::Vector2dF origin,
+ gfx::Vector2dF distance) {
+ Touches touches;
+ const gfx::Vector2dF delta = ScaleVector2d(distance, 1.f / steps);
+
+ WebTouchEvent touch;
+ touch.touchesLength = 1;
+ touch.type = WebInputEvent::TouchStart;
+ touch.touches[0].id = 0;
+ touch.touches[0].state = WebTouchPoint::StatePressed;
+ touch.touches[0].position.x = origin.x();
+ touch.touches[0].position.y = origin.y();
+ touch.touches[0].screenPosition.x = origin.x();
+ touch.touches[0].screenPosition.y = origin.y();
+ touches.push_back(touch);
+
+ touch.type = WebInputEvent::TouchMove;
+ touch.touches[0].state = WebTouchPoint::StateMoved;
+ for (size_t i = 0; i < steps; ++i) {
+ touch.touches[0].position.x += delta.x();
+ touch.touches[0].position.y += delta.y();
+ touch.touches[0].screenPosition.x += delta.x();
+ touch.touches[0].screenPosition.y += delta.y();
+ touches.push_back(touch);
+ }
+
+ touch.type = WebInputEvent::TouchEnd;
+ touch.touches[0].state = WebTouchPoint::StateReleased;
+ touches.push_back(touch);
+ return touches;
+}
+
+class InputEventTimer {
+ public:
+ InputEventTimer(const char* test_name, int64 event_count)
+ : test_name_(test_name),
+ event_count_(event_count),
+ start_(base::TimeTicks::Now()) {}
+
+ ~InputEventTimer() {
+ perf_test::PrintResult(
+ "avg_time_per_event",
+ "",
+ test_name_,
+ static_cast<size_t>(((base::TimeTicks::Now() - start_) / event_count_)
+ .InMicroseconds()),
+ "us",
+ true);
+ }
+
+ private:
+ const char* test_name_;
+ int64 event_count_;
+ base::TimeTicks start_;
+ DISALLOW_COPY_AND_ASSIGN(InputEventTimer);
+};
+
+} // namespace
+
+class InputRouterImplPerfTest : public testing::Test {
+ public:
+ InputRouterImplPerfTest()
+ : last_sent_event_type_(WebInputEvent::Undefined),
+ last_input_id_(0) {}
+
+ virtual ~InputRouterImplPerfTest() {}
+
+ protected:
+ // testing::Test
+ virtual void SetUp() OVERRIDE {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGestureDebounce)) {
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kDisableGestureDebounce);
+ }
+
+ sender_.reset(new NullIPCSender());
+ client_.reset(new NullInputRouterClient());
+ ack_handler_.reset(new NullInputAckHandler());
+ input_router_.reset(new InputRouterImpl(
+ sender_.get(), client_.get(), ack_handler_.get(), MSG_ROUTING_NONE));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ base::MessageLoop::current()->RunUntilIdle();
+
+ input_router_.reset();
+ ack_handler_.reset();
+ client_.reset();
+ sender_.reset();
+ }
+
+ void SendEvent(const WebGestureEvent& gesture,
+ const ui::LatencyInfo& latency) {
+ input_router_->SendGestureEvent(
+ GestureEventWithLatencyInfo(gesture, latency));
+ }
+
+ void SendEvent(const WebTouchEvent& touch, const ui::LatencyInfo& latency) {
+ input_router_->SendTouchEvent(TouchEventWithLatencyInfo(touch, latency));
+ }
+
+ void SendInputEventACK(blink::WebInputEvent::Type type,
+ InputEventAckState ack_result) {
+ InputHostMsg_HandleInputEvent_ACK response(
+ 0, type, ack_result, ui::LatencyInfo());
+ input_router_->OnMessageReceived(response);
+ }
+
+ InputRouterImpl* input_router() const { return input_router_.get(); }
+
+ void OnHasTouchEventHandlers(bool has_handlers) {
+ input_router_->OnMessageReceived(
+ ViewHostMsg_HasTouchEventHandlers(0, has_handlers));
+ }
+
+ size_t GetAndResetSentEventCount() {
+ return sender_->GetAndResetSentEventCount();
+ }
+
+ size_t GetAndResetAckCount() { return ack_handler_->GetAndResetAckCount(); }
+
+ size_t AckCount() const { return ack_handler_->ack_count(); }
+
+ int64 NextLatencyID() { return ++last_input_id_; }
+
+ ui::LatencyInfo CreateLatencyInfo() {
+ ui::LatencyInfo latency;
+ latency.AddLatencyNumber(
+ ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT, 1, 0);
+ latency.AddLatencyNumber(
+ ui::INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT,
+ 1,
+ NextLatencyID());
+ return latency;
+ }
+
+ // TODO(jdduke): Use synthetic gesture pipeline.
+ template <typename EventType>
+ void RunTest(const char* test_name,
+ const std::vector<EventType>& events,
+ bool ack_delay,
+ size_t iterations) {
+ OnHasTouchEventHandlers(true);
+
+ const size_t event_count = events.size();
+ const size_t total_event_count = event_count * iterations;
+ ASSERT_LT(ack_delay, event_count);
+
+ InputEventTimer timer(test_name, total_event_count);
+ while (iterations--) {
+ size_t i = 0, ack_i = 0;
+ if (ack_delay)
+ SendEvent(events[i++], CreateLatencyInfo());
+
+ for (; i < event_count; ++i, ++ack_i) {
+ SendEvent(events[i], CreateLatencyInfo());
+ SendInputEventACK(events[ack_i].type, INPUT_EVENT_ACK_STATE_CONSUMED);
+ }
+
+ if (ack_delay)
+ SendInputEventACK(events.back().type, INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ EXPECT_EQ(event_count, GetAndResetSentEventCount());
+ EXPECT_EQ(event_count, GetAndResetAckCount());
+ }
+ }
+
+ 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.
+ size_t steps,
+ gfx::Vector2dF origin,
+ gfx::Vector2dF distance,
+ size_t iterations) {
+ OnHasTouchEventHandlers(true);
+
+ Gestures gestures = BuildScrollSequence(steps, origin, distance);
+ Touches touches = BuildTouchSequence(steps, origin, distance);
+ ASSERT_EQ(touches.size(), gestures.size());
+
+ const size_t event_count = gestures.size();
+ const size_t total_event_count = event_count * iterations * 2;
+
+ InputEventTimer timer(test_name, total_event_count);
+ while (iterations--) {
+ for (size_t i = 0; i < event_count; ++i) {
+ SendEvent(touches[i], CreateLatencyInfo());
+ // Touches may not be forwarded after the scroll sequence has begun, so
+ // only ack if necessary.
+ if (!AckCount()) {
+ SendInputEventACK(touches[i].type,
+ INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ }
+
+ SendEvent(gestures[i], CreateLatencyInfo());
+ SendInputEventACK(gestures[i].type, INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(2U, GetAndResetAckCount());
+ }
+ }
+ }
+
+ private:
+ WebInputEvent::Type last_sent_event_type_;
+ int64 last_input_id_;
+ scoped_ptr<NullIPCSender> sender_;
+ scoped_ptr<NullInputRouterClient> client_;
+ scoped_ptr<NullInputAckHandler> ack_handler_;
+ scoped_ptr<InputRouterImpl> input_router_;
+ base::MessageLoopForUI message_loop_;
+};
+
+const size_t kDefaultSteps(100);
+const size_t kDefaultIterations(100);
+const gfx::Vector2dF kDefaultOrigin(100, 100);
+const gfx::Vector2dF kDefaultDistance(500, 500);
+
+TEST_F(InputRouterImplPerfTest, TouchSwipe) {
+ RunTest("TouchSwipe ",
+ BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
+ false,
+ kDefaultIterations);
+}
+
+TEST_F(InputRouterImplPerfTest, TouchSwipeDelayedAck) {
+ RunTest("TouchSwipeDelayedAck ",
+ BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
+ true,
+ kDefaultIterations);
+}
+
+TEST_F(InputRouterImplPerfTest, GestureScroll) {
+ RunTest("GestureScroll ",
+ BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
+ false,
+ kDefaultIterations);
+}
+
+TEST_F(InputRouterImplPerfTest, GestureScrollDelayedAck) {
+ RunTest("GestureScrollDelayedAck ",
+ BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
+ true,
+ kDefaultIterations);
+}
+
+TEST_F(InputRouterImplPerfTest, TouchSwipeToGestureScroll) {
+ RunTest("TouchSwipeToGestureScroll ",
+ kDefaultSteps,
+ kDefaultOrigin,
+ kDefaultDistance,
+ kDefaultIterations);
+}
+
+} // namespace content
« 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