summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-19 20:58:59 +0000
committerjdduke@chromium.org <jdduke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-19 20:58:59 +0000
commit35afe7467e97f573eed41804ccbd2d7509322a1a (patch)
treefab54040b01c80eeb215148d289feb9a1d1208b8 /content
parentffc735e33b2d004dcf5da7c96f9a5ac34236d053 (diff)
downloadchromium_src-35afe7467e97f573eed41804ccbd2d7509322a1a.zip
chromium_src-35afe7467e97f573eed41804ccbd2d7509322a1a.tar.gz
chromium_src-35afe7467e97f573eed41804ccbd2d7509322a1a.tar.bz2
Add InputRouter perftests for touches and scroll gestures
Add some basic perftests that track how long a given WebTouchEvent or WebGestureEvent takes to propagate through the InputRouter. This includes both the time to send and the time to ack a given event, averaged over a typical touch swipe or scroll gesture sequence. BUG=339877 TBR=jam@chromium.org Review URL: https://codereview.chromium.org/170913002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@252079 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/browser/renderer_host/input/input_router_impl_perftest.cc389
-rw-r--r--content/content_tests.gypi22
-rw-r--r--content/public/common/content_switches.h2
3 files changed, 412 insertions, 1 deletions
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 0000000..717ba4f
--- /dev/null
+++ b/content/browser/renderer_host/input/input_router_impl_perftest.cc
@@ -0,0 +1,389 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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) OVERRIDE {
+ 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_;
+};
+
+// TODO(jdduke): Use synthetic gesture pipeline, crbug.com/344598.
+typedef std::vector<WebGestureEvent> Gestures;
+Gestures BuildScrollSequence(size_t steps,
+ 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_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 SendEventAck(blink::WebInputEvent::Type type,
+ InputEventAckState ack_result) {
+ InputHostMsg_HandleInputEvent_ACK response(
+ 0, type, ack_result, ui::LatencyInfo());
+ input_router_->OnMessageReceived(response);
+ }
+
+ 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, crbug.com/344598.
+ template <typename EventType>
+ void SimulateEventSequence(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;
+
+ 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());
+ SendEventAck(events[ack_i].type, INPUT_EVENT_ACK_STATE_CONSUMED);
+ }
+
+ if (ack_delay)
+ SendEventAck(events.back().type, INPUT_EVENT_ACK_STATE_CONSUMED);
+
+ EXPECT_EQ(event_count, GetAndResetSentEventCount());
+ EXPECT_EQ(event_count, GetAndResetAckCount());
+ }
+ }
+
+ void SimulateTouchAndScrollEventSequence(const char* test_name,
+ 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()) {
+ SendEventAck(touches[i].type, INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+ }
+
+ SendEvent(gestures[i], CreateLatencyInfo());
+ SendEventAck(gestures[i].type, INPUT_EVENT_ACK_STATE_CONSUMED);
+ EXPECT_EQ(2U, GetAndResetAckCount());
+ }
+ }
+ }
+
+ private:
+ 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) {
+ SimulateEventSequence(
+ "TouchSwipe ",
+ BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
+ false,
+ kDefaultIterations);
+}
+
+TEST_F(InputRouterImplPerfTest, TouchSwipeDelayedAck) {
+ SimulateEventSequence(
+ "TouchSwipeDelayedAck ",
+ BuildTouchSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
+ true,
+ kDefaultIterations);
+}
+
+TEST_F(InputRouterImplPerfTest, GestureScroll) {
+ SimulateEventSequence(
+ "GestureScroll ",
+ BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
+ false,
+ kDefaultIterations);
+}
+
+TEST_F(InputRouterImplPerfTest, GestureScrollDelayedAck) {
+ SimulateEventSequence(
+ "GestureScrollDelayedAck ",
+ BuildScrollSequence(kDefaultSteps, kDefaultOrigin, kDefaultDistance),
+ true,
+ kDefaultIterations);
+}
+
+TEST_F(InputRouterImplPerfTest, TouchSwipeToGestureScroll) {
+ SimulateTouchAndScrollEventSequence("TouchSwipeToGestureScroll ",
+ kDefaultSteps,
+ kDefaultOrigin,
+ kDefaultDistance,
+ kDefaultIterations);
+}
+
+} // namespace content
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 69a839d..db64b35 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -867,6 +867,7 @@
'type': '<(gtest_target_type)',
'defines!': ['CONTENT_IMPLEMENTATION'],
'dependencies': [
+ 'content.gyp:content_browser',
'content.gyp:content_common',
'test_support_content',
'../base/base.gyp:test_support_base',
@@ -881,9 +882,17 @@
'..',
],
'sources': [
+ 'browser/renderer_host/input/input_router_impl_perftest.cc',
'common/cc_messages_perftest.cc',
'test/run_all_perftests.cc',
],
+ 'conditions': [
+ ['OS == "android" and gtest_target_type == "shared_library"', {
+ 'dependencies': [
+ '../testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
+ ],
},
{
'target_name': 'content_browser_test_support',
@@ -1424,6 +1433,19 @@
'includes': [ '../build/java_apk.gypi' ],
},
{
+ 'target_name': 'content_perftests_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'content.gyp:content_java',
+ 'content_perftests',
+ ],
+ 'variables': {
+ 'test_suite_name': 'content_perftests',
+ 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)content_perftests<(SHARED_LIB_SUFFIX)',
+ },
+ 'includes': [ '../build/apk_test.gypi' ],
+ },
+ {
'target_name': 'chromium_linker_test_apk',
'type': 'none',
'dependencies': [
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index eb173c4..913ed5a 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -64,7 +64,7 @@ CONTENT_EXPORT extern const char kDisableFlash3d[];
CONTENT_EXPORT extern const char kDisableFlashStage3d[];
CONTENT_EXPORT extern const char kDisableForceCompositingMode[];
CONTENT_EXPORT extern const char kDisableFullScreen[];
-extern const char kDisableGestureDebounce[];
+CONTENT_EXPORT extern const char kDisableGestureDebounce[];
CONTENT_EXPORT extern const char kDisableGestureTapHighlight[];
CONTENT_EXPORT extern const char kDisableGLMultisampling[];
CONTENT_EXPORT extern const char kDisableGpu[];