diff options
-rw-r--r-- | ipc/BUILD.gn | 2 | ||||
-rw-r--r-- | ipc/ipc.gyp | 2 | ||||
-rw-r--r-- | ipc/ipc_channel.h | 2 | ||||
-rw-r--r-- | ipc/ipc_channel_factory.h | 2 | ||||
-rw-r--r-- | ipc/ipc_perftest_support.cc | 342 | ||||
-rw-r--r-- | ipc/ipc_perftest_support.h | 59 | ||||
-rw-r--r-- | ipc/ipc_perftests.cc | 313 | ||||
-rw-r--r-- | ipc/ipc_test_base.cc | 22 | ||||
-rw-r--r-- | ipc/ipc_test_base.h | 4 | ||||
-rw-r--r-- | ipc/mojo/BUILD.gn | 19 | ||||
-rw-r--r-- | ipc/mojo/ipc_channel_mojo.cc | 12 | ||||
-rw-r--r-- | ipc/mojo/ipc_channel_mojo.h | 5 | ||||
-rw-r--r-- | ipc/mojo/ipc_channel_mojo_unittest.cc | 49 | ||||
-rw-r--r-- | ipc/mojo/ipc_mojo.gyp | 25 | ||||
-rw-r--r-- | ipc/mojo/ipc_mojo_perftest.cc | 87 |
15 files changed, 575 insertions, 370 deletions
diff --git a/ipc/BUILD.gn b/ipc/BUILD.gn index 4d547431..e7e08b5 100644 --- a/ipc/BUILD.gn +++ b/ipc/BUILD.gn @@ -162,6 +162,8 @@ static_library("test_support") { sources = [ "ipc_multiprocess_test.cc", "ipc_multiprocess_test.h", + "ipc_perftest_support.cc", + "ipc_perftest_support.h", "ipc_test_sink.cc", "ipc_test_sink.h", "ipc_test_base.cc", diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp index 6d90ab6..28c112b 100644 --- a/ipc/ipc.gyp +++ b/ipc/ipc.gyp @@ -130,6 +130,8 @@ 'sources': [ 'ipc_multiprocess_test.cc', 'ipc_multiprocess_test.h', + 'ipc_perftest_support.cc', + 'ipc_perftest_support.h', 'ipc_test_base.cc', 'ipc_test_base.h', 'ipc_test_channel_listener.cc', diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h index fbd4ae0..d27af58 100644 --- a/ipc/ipc_channel.h +++ b/ipc/ipc_channel.h @@ -118,7 +118,7 @@ class IPC_EXPORT Channel : public Sender { // TODO(morrita): Replace CreateByModeForProxy() with one of above Create*(). // static scoped_ptr<Channel> Create( - const IPC::ChannelHandle &channel_handle, Mode mode,Listener* listener); + const IPC::ChannelHandle &channel_handle, Mode mode, Listener* listener); static scoped_ptr<Channel> CreateClient( const IPC::ChannelHandle &channel_handle, Listener* listener); diff --git a/ipc/ipc_channel_factory.h b/ipc/ipc_channel_factory.h index 30bfd8c..84bcf97 100644 --- a/ipc/ipc_channel_factory.h +++ b/ipc/ipc_channel_factory.h @@ -16,7 +16,7 @@ namespace IPC { // Encapsulates how a Channel is created. A ChannelFactory can be // passed to the constructor of ChannelProxy or SyncChannel to tell them // how to create underlying channel. -class ChannelFactory { +class IPC_EXPORT ChannelFactory { public: // Creates a factory for "native" channel built through // IPC::Channel::Create(). diff --git a/ipc/ipc_perftest_support.cc b/ipc/ipc_perftest_support.cc new file mode 100644 index 0000000..b826420 --- /dev/null +++ b/ipc/ipc_perftest_support.cc @@ -0,0 +1,342 @@ +// Copyright (c) 2012 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 "ipc/ipc_perftest_support.h" + +#include <algorithm> +#include <string> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/pickle.h" +#include "base/strings/stringprintf.h" +#include "base/test/perf_time_logger.h" +#include "base/test/test_io_thread.h" +#include "base/threading/thread.h" +#include "base/time/time.h" +#include "build/build_config.h" +#include "ipc/ipc_channel.h" +#include "ipc/ipc_channel_proxy.h" +#include "ipc/ipc_descriptors.h" +#include "ipc/ipc_message_utils.h" +#include "ipc/ipc_sender.h" + +namespace IPC { +namespace test { + +// This class simply collects stats about abstract "events" (each of which has a +// start time and an end time). +class EventTimeTracker { + public: + explicit EventTimeTracker(const char* name) + : name_(name), + count_(0) { + } + + void AddEvent(const base::TimeTicks& start, const base::TimeTicks& end) { + DCHECK(end >= start); + count_++; + base::TimeDelta duration = end - start; + total_duration_ += duration; + max_duration_ = std::max(max_duration_, duration); + } + + void ShowResults() const { + VLOG(1) << name_ << " count: " << count_; + VLOG(1) << name_ << " total duration: " + << total_duration_.InMillisecondsF() << " ms"; + VLOG(1) << name_ << " average duration: " + << (total_duration_.InMillisecondsF() / static_cast<double>(count_)) + << " ms"; + VLOG(1) << name_ << " maximum duration: " + << max_duration_.InMillisecondsF() << " ms"; + } + + void Reset() { + count_ = 0; + total_duration_ = base::TimeDelta(); + max_duration_ = base::TimeDelta(); + } + + private: + const std::string name_; + + uint64 count_; + base::TimeDelta total_duration_; + base::TimeDelta max_duration_; + + DISALLOW_COPY_AND_ASSIGN(EventTimeTracker); +}; + +// This channel listener just replies to all messages with the exact same +// message. It assumes each message has one string parameter. When the string +// "quit" is sent, it will exit. +class ChannelReflectorListener : public Listener { + public: + ChannelReflectorListener() + : channel_(NULL), + latency_tracker_("Client messages") { + VLOG(1) << "Client listener up"; + } + + virtual ~ChannelReflectorListener() { + VLOG(1) << "Client listener down"; + latency_tracker_.ShowResults(); + } + + void Init(Channel* channel) { + DCHECK(!channel_); + channel_ = channel; + } + + virtual bool OnMessageReceived(const Message& message) OVERRIDE { + CHECK(channel_); + + PickleIterator iter(message); + int64 time_internal; + EXPECT_TRUE(iter.ReadInt64(&time_internal)); + int msgid; + EXPECT_TRUE(iter.ReadInt(&msgid)); + std::string payload; + EXPECT_TRUE(iter.ReadString(&payload)); + + // Include message deserialization in latency. + base::TimeTicks now = base::TimeTicks::Now(); + + if (payload == "hello") { + latency_tracker_.Reset(); + } else if (payload == "quit") { + latency_tracker_.ShowResults(); + base::MessageLoop::current()->QuitWhenIdle(); + return true; + } else { + // Don't track hello and quit messages. + latency_tracker_.AddEvent( + base::TimeTicks::FromInternalValue(time_internal), now); + } + + Message* msg = new Message(0, 2, Message::PRIORITY_NORMAL); + msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + msg->WriteInt(msgid); + msg->WriteString(payload); + channel_->Send(msg); + return true; + } + + private: + Channel* channel_; + EventTimeTracker latency_tracker_; +}; + +class PerformanceChannelListener : public Listener { + public: + explicit PerformanceChannelListener(const std::string& label) + : label_(label), + sender_(NULL), + msg_count_(0), + msg_size_(0), + count_down_(0), + latency_tracker_("Server messages") { + VLOG(1) << "Server listener up"; + } + + virtual ~PerformanceChannelListener() { + VLOG(1) << "Server listener down"; + } + + void Init(Sender* sender) { + DCHECK(!sender_); + sender_ = sender; + } + + // Call this before running the message loop. + void SetTestParams(int msg_count, size_t msg_size) { + DCHECK_EQ(0, count_down_); + msg_count_ = msg_count; + msg_size_ = msg_size; + count_down_ = msg_count_; + payload_ = std::string(msg_size_, 'a'); + } + + virtual bool OnMessageReceived(const Message& message) OVERRIDE { + CHECK(sender_); + + PickleIterator iter(message); + int64 time_internal; + EXPECT_TRUE(iter.ReadInt64(&time_internal)); + int msgid; + EXPECT_TRUE(iter.ReadInt(&msgid)); + std::string reflected_payload; + EXPECT_TRUE(iter.ReadString(&reflected_payload)); + + // Include message deserialization in latency. + base::TimeTicks now = base::TimeTicks::Now(); + + if (reflected_payload == "hello") { + // Start timing on hello. + latency_tracker_.Reset(); + DCHECK(!perf_logger_.get()); + std::string test_name = + base::StringPrintf("IPC_%s_Perf_%dx_%u", + label_.c_str(), + msg_count_, + static_cast<unsigned>(msg_size_)); + perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str())); + } else { + DCHECK_EQ(payload_.size(), reflected_payload.size()); + + latency_tracker_.AddEvent( + base::TimeTicks::FromInternalValue(time_internal), now); + + CHECK(count_down_ > 0); + count_down_--; + if (count_down_ == 0) { + perf_logger_.reset(); // Stop the perf timer now. + latency_tracker_.ShowResults(); + base::MessageLoop::current()->QuitWhenIdle(); + return true; + } + } + + Message* msg = new Message(0, 2, Message::PRIORITY_NORMAL); + msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + msg->WriteInt(count_down_); + msg->WriteString(payload_); + sender_->Send(msg); + return true; + } + + private: + std::string label_; + Sender* sender_; + int msg_count_; + size_t msg_size_; + + int count_down_; + std::string payload_; + EventTimeTracker latency_tracker_; + scoped_ptr<base::PerfTimeLogger> perf_logger_; +}; + +std::vector<PingPongTestParams> +IPCChannelPerfTestBase::GetDefaultTestParams() { + // Test several sizes. We use 12^N for message size, and limit the message + // count to keep the test duration reasonable. + std::vector<PingPongTestParams> list; + list.push_back(PingPongTestParams(12, 50000)); + list.push_back(PingPongTestParams(144, 50000)); + list.push_back(PingPongTestParams(1728, 50000)); + list.push_back(PingPongTestParams(20736, 12000)); + list.push_back(PingPongTestParams(248832, 100)); + return list; +} + +void IPCChannelPerfTestBase::RunTestChannelPingPong( + const std::vector<PingPongTestParams>& params) { + Init("PerformanceClient"); + + // Set up IPC channel and start client. + PerformanceChannelListener listener("Channel"); + CreateChannel(&listener); + listener.Init(channel()); + ASSERT_TRUE(ConnectChannel()); + ASSERT_TRUE(StartClient()); + + for (size_t i = 0; i < params.size(); i++) { + listener.SetTestParams(params[i].message_count(), + params[i].message_size()); + + // This initial message will kick-start the ping-pong of messages. + Message* message = + new Message(0, 2, Message::PRIORITY_NORMAL); + message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + message->WriteInt(-1); + message->WriteString("hello"); + sender()->Send(message); + + // Run message loop. + base::MessageLoop::current()->Run(); + } + + // Send quit message. + Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); + message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + message->WriteInt(-1); + message->WriteString("quit"); + sender()->Send(message); + + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannel(); +} + +void IPCChannelPerfTestBase::RunTestChannelProxyPingPong( + const std::vector<PingPongTestParams>& params) { + InitWithCustomMessageLoop("PerformanceClient", + make_scoped_ptr(new base::MessageLoop())); + + base::TestIOThread io_thread(base::TestIOThread::kAutoStart); + + // Set up IPC channel and start client. + PerformanceChannelListener listener("ChannelProxy"); + CreateChannelProxy(&listener, io_thread.task_runner()); + listener.Init(channel_proxy()); + ASSERT_TRUE(StartClient()); + + for (size_t i = 0; i < params.size(); i++) { + listener.SetTestParams(params[i].message_count(), + params[i].message_size()); + + // This initial message will kick-start the ping-pong of messages. + Message* message = + new Message(0, 2, Message::PRIORITY_NORMAL); + message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + message->WriteInt(-1); + message->WriteString("hello"); + sender()->Send(message); + + // Run message loop. + base::MessageLoop::current()->Run(); + } + + // Send quit message. + Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); + message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); + message->WriteInt(-1); + message->WriteString("quit"); + sender()->Send(message); + + EXPECT_TRUE(WaitForClientShutdown()); + DestroyChannelProxy(); +} + + +PingPongTestClient::PingPongTestClient() + : listener_(new ChannelReflectorListener()) { +} + +PingPongTestClient::~PingPongTestClient() { +} + +scoped_ptr<Channel> PingPongTestClient::CreateChannel( + Listener* listener) { + return Channel::CreateClient( + IPCTestBase::GetChannelName("PerformanceClient"), listener); +} + +int PingPongTestClient::RunMain() { + scoped_ptr<Channel> channel = CreateChannel(listener_.get()); + listener_->Init(channel.get()); + CHECK(channel->Connect()); + + base::MessageLoop::current()->Run(); + return 0; +} + +scoped_refptr<base::TaskRunner> PingPongTestClient::task_runner() { + return main_message_loop_.message_loop_proxy(); +} + +} // namespace test +} // namespace IPC diff --git a/ipc/ipc_perftest_support.h b/ipc/ipc_perftest_support.h new file mode 100644 index 0000000..611a209 --- /dev/null +++ b/ipc/ipc_perftest_support.h @@ -0,0 +1,59 @@ +// Copyright (c) 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. + +#ifndef IPC_IPC_PERFTEST_SUPPORT_H_ +#define IPC_IPC_PERFTEST_SUPPORT_H_ + +#include <vector> + +#include "ipc/ipc_test_base.h" + +namespace IPC { +namespace test { + +class ChannelReflectorListener; + +class PingPongTestParams { + public: + PingPongTestParams(size_t size, int count) + : message_size_(size), message_count_(count) { + } + + size_t message_size() const { return message_size_; } + int message_count() const { return message_count_; } + + private: + size_t message_size_; + int message_count_; +}; + +class IPCChannelPerfTestBase : public IPCTestBase { + public: + static std::vector<PingPongTestParams> GetDefaultTestParams(); + + void RunTestChannelPingPong( + const std::vector<PingPongTestParams>& params_list); + void RunTestChannelProxyPingPong( + const std::vector<PingPongTestParams>& params_list); +}; + +class PingPongTestClient { + public: + PingPongTestClient(); + virtual ~PingPongTestClient(); + + virtual scoped_ptr<Channel> CreateChannel(Listener* listener); + int RunMain(); + scoped_refptr<base::TaskRunner> task_runner(); + + private: + base::MessageLoopForIO main_message_loop_; + scoped_ptr<ChannelReflectorListener> listener_; + scoped_ptr<Channel> channel_; +}; + +} +} + +#endif // IPC_IPC_PERFTEST_SUPPORT_H_ diff --git a/ipc/ipc_perftests.cc b/ipc/ipc_perftests.cc index 08a8d70..cb40626 100644 --- a/ipc/ipc_perftests.cc +++ b/ipc/ipc_perftests.cc @@ -2,26 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "build/build_config.h" - -#include <algorithm> -#include <string> - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/pickle.h" -#include "base/strings/stringprintf.h" -#include "base/test/perf_time_logger.h" -#include "base/test/test_io_thread.h" -#include "base/threading/thread.h" -#include "base/time/time.h" -#include "ipc/ipc_channel.h" -#include "ipc/ipc_channel_proxy.h" -#include "ipc/ipc_descriptors.h" -#include "ipc/ipc_message_utils.h" -#include "ipc/ipc_sender.h" -#include "ipc/ipc_test_base.h" +#include "ipc/ipc_perftest_support.h" namespace { @@ -29,298 +10,20 @@ namespace { // // TODO(brettw): Make this test run by default. -class IPCChannelPerfTest : public IPCTestBase { -}; - -// This class simply collects stats about abstract "events" (each of which has a -// start time and an end time). -class EventTimeTracker { - public: - explicit EventTimeTracker(const char* name) - : name_(name), - count_(0) { - } - - void AddEvent(const base::TimeTicks& start, const base::TimeTicks& end) { - DCHECK(end >= start); - count_++; - base::TimeDelta duration = end - start; - total_duration_ += duration; - max_duration_ = std::max(max_duration_, duration); - } - - void ShowResults() const { - VLOG(1) << name_ << " count: " << count_; - VLOG(1) << name_ << " total duration: " - << total_duration_.InMillisecondsF() << " ms"; - VLOG(1) << name_ << " average duration: " - << (total_duration_.InMillisecondsF() / static_cast<double>(count_)) - << " ms"; - VLOG(1) << name_ << " maximum duration: " - << max_duration_.InMillisecondsF() << " ms"; - } - - void Reset() { - count_ = 0; - total_duration_ = base::TimeDelta(); - max_duration_ = base::TimeDelta(); - } - - private: - const std::string name_; - - uint64 count_; - base::TimeDelta total_duration_; - base::TimeDelta max_duration_; - - DISALLOW_COPY_AND_ASSIGN(EventTimeTracker); -}; - -// This channel listener just replies to all messages with the exact same -// message. It assumes each message has one string parameter. When the string -// "quit" is sent, it will exit. -class ChannelReflectorListener : public IPC::Listener { - public: - ChannelReflectorListener() - : channel_(NULL), - latency_tracker_("Client messages") { - VLOG(1) << "Client listener up"; - } - - virtual ~ChannelReflectorListener() { - VLOG(1) << "Client listener down"; - latency_tracker_.ShowResults(); - } - - void Init(IPC::Channel* channel) { - DCHECK(!channel_); - channel_ = channel; - } - - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { - CHECK(channel_); - - PickleIterator iter(message); - int64 time_internal; - EXPECT_TRUE(iter.ReadInt64(&time_internal)); - int msgid; - EXPECT_TRUE(iter.ReadInt(&msgid)); - std::string payload; - EXPECT_TRUE(iter.ReadString(&payload)); - - // Include message deserialization in latency. - base::TimeTicks now = base::TimeTicks::Now(); - - if (payload == "hello") { - latency_tracker_.Reset(); - } else if (payload == "quit") { - latency_tracker_.ShowResults(); - base::MessageLoop::current()->QuitWhenIdle(); - return true; - } else { - // Don't track hello and quit messages. - latency_tracker_.AddEvent( - base::TimeTicks::FromInternalValue(time_internal), now); - } - - IPC::Message* msg = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); - msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - msg->WriteInt(msgid); - msg->WriteString(payload); - channel_->Send(msg); - return true; - } - - private: - IPC::Channel* channel_; - EventTimeTracker latency_tracker_; -}; - -class PerformanceChannelListener : public IPC::Listener { - public: - explicit PerformanceChannelListener(const std::string& label) - : label_(label), - sender_(NULL), - msg_count_(0), - msg_size_(0), - count_down_(0), - latency_tracker_("Server messages") { - VLOG(1) << "Server listener up"; - } - - virtual ~PerformanceChannelListener() { - VLOG(1) << "Server listener down"; - } - - void Init(IPC::Sender* sender) { - DCHECK(!sender_); - sender_ = sender; - } - - // Call this before running the message loop. - void SetTestParams(int msg_count, size_t msg_size) { - DCHECK_EQ(0, count_down_); - msg_count_ = msg_count; - msg_size_ = msg_size; - count_down_ = msg_count_; - payload_ = std::string(msg_size_, 'a'); - } - - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { - CHECK(sender_); - - PickleIterator iter(message); - int64 time_internal; - EXPECT_TRUE(iter.ReadInt64(&time_internal)); - int msgid; - EXPECT_TRUE(iter.ReadInt(&msgid)); - std::string reflected_payload; - EXPECT_TRUE(iter.ReadString(&reflected_payload)); - - // Include message deserialization in latency. - base::TimeTicks now = base::TimeTicks::Now(); - - if (reflected_payload == "hello") { - // Start timing on hello. - latency_tracker_.Reset(); - DCHECK(!perf_logger_.get()); - std::string test_name = - base::StringPrintf("IPC_%s_Perf_%dx_%u", - label_.c_str(), - msg_count_, - static_cast<unsigned>(msg_size_)); - perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str())); - } else { - DCHECK_EQ(payload_.size(), reflected_payload.size()); - - latency_tracker_.AddEvent( - base::TimeTicks::FromInternalValue(time_internal), now); - - CHECK(count_down_ > 0); - count_down_--; - if (count_down_ == 0) { - perf_logger_.reset(); // Stop the perf timer now. - latency_tracker_.ShowResults(); - base::MessageLoop::current()->QuitWhenIdle(); - return true; - } - } - - IPC::Message* msg = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); - msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - msg->WriteInt(count_down_); - msg->WriteString(payload_); - sender_->Send(msg); - return true; - } - - private: - std::string label_; - IPC::Sender* sender_; - int msg_count_; - size_t msg_size_; - - int count_down_; - std::string payload_; - EventTimeTracker latency_tracker_; - scoped_ptr<base::PerfTimeLogger> perf_logger_; +class IPCChannelPerfTest : public IPC::test::IPCChannelPerfTestBase { }; TEST_F(IPCChannelPerfTest, ChannelPingPong) { - Init("PerformanceClient"); - - // Set up IPC channel and start client. - PerformanceChannelListener listener("Channel"); - CreateChannel(&listener); - listener.Init(channel()); - ASSERT_TRUE(ConnectChannel()); - ASSERT_TRUE(StartClient()); - - // Test several sizes. We use 12^N for message size, and limit the message - // count to keep the test duration reasonable. - const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832}; - const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000}; - - for (size_t i = 0; i < 5; i++) { - listener.SetTestParams(kMessageCount[i], kMsgSize[i]); - - // This initial message will kick-start the ping-pong of messages. - IPC::Message* message = - new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); - message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - message->WriteInt(-1); - message->WriteString("hello"); - sender()->Send(message); - - // Run message loop. - base::MessageLoop::current()->Run(); - } - - // Send quit message. - IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); - message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - message->WriteInt(-1); - message->WriteString("quit"); - sender()->Send(message); - - EXPECT_TRUE(WaitForClientShutdown()); - DestroyChannel(); -} - -// This message loop bounces all messages back to the sender. -MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) { - base::MessageLoopForIO main_message_loop; - ChannelReflectorListener listener; - scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient( - IPCTestBase::GetChannelName("PerformanceClient"), &listener)); - listener.Init(channel.get()); - CHECK(channel->Connect()); - - base::MessageLoop::current()->Run(); - return 0; + RunTestChannelPingPong(GetDefaultTestParams()); } TEST_F(IPCChannelPerfTest, ChannelProxyPingPong) { - InitWithCustomMessageLoop("PerformanceClient", - make_scoped_ptr(new base::MessageLoop())); - - base::TestIOThread io_thread(base::TestIOThread::kAutoStart); - - // Set up IPC channel and start client. - PerformanceChannelListener listener("ChannelProxy"); - CreateChannelProxy(&listener, io_thread.task_runner()); - listener.Init(channel_proxy()); - ASSERT_TRUE(StartClient()); - - // Test several sizes. We use 12^N for message size, and limit the message - // count to keep the test duration reasonable. - const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832}; - const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000}; - - for (size_t i = 0; i < 5; i++) { - listener.SetTestParams(kMessageCount[i], kMsgSize[i]); - - // This initial message will kick-start the ping-pong of messages. - IPC::Message* message = - new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); - message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - message->WriteInt(-1); - message->WriteString("hello"); - sender()->Send(message); - - // Run message loop. - base::MessageLoop::current()->Run(); - } - - // Send quit message. - IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); - message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); - message->WriteInt(-1); - message->WriteString("quit"); - sender()->Send(message); + RunTestChannelProxyPingPong(GetDefaultTestParams()); +} - EXPECT_TRUE(WaitForClientShutdown()); - DestroyChannelProxy(); +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) { + IPC::test::PingPongTestClient client; + return client.RunMain(); } } // namespace diff --git a/ipc/ipc_test_base.cc b/ipc/ipc_test_base.cc index 80ddd2d..6abef0f 100644 --- a/ipc/ipc_test_base.cc +++ b/ipc/ipc_test_base.cc @@ -52,8 +52,8 @@ void IPCTestBase::InitWithCustomMessageLoop( } void IPCTestBase::CreateChannel(IPC::Listener* listener) { - return CreateChannelFromChannelHandle(GetChannelName(test_client_name_), - listener); + CreateChannelFromChannelHandle( + GetChannelName(test_client_name_), listener); } bool IPCTestBase::ConnectChannel() { @@ -80,7 +80,8 @@ void IPCTestBase::CreateChannelFromChannelHandle( IPC::Listener* listener) { CHECK(!channel_.get()); CHECK(!channel_proxy_.get()); - channel_ = IPC::Channel::CreateServer(channel_handle, listener); + channel_ = CreateChannelFactory( + channel_handle, task_runner().get())->BuildChannel(listener); } void IPCTestBase::CreateChannelProxy( @@ -88,10 +89,11 @@ void IPCTestBase::CreateChannelProxy( const scoped_refptr<base::SingleThreadTaskRunner>& ipc_task_runner) { CHECK(!channel_.get()); CHECK(!channel_proxy_.get()); - channel_proxy_ = IPC::ChannelProxy::Create(GetChannelName(test_client_name_), - IPC::Channel::MODE_SERVER, - listener, - ipc_task_runner); + channel_proxy_ = IPC::ChannelProxy::Create( + CreateChannelFactory(GetChannelName(test_client_name_), + ipc_task_runner.get()), + listener, + ipc_task_runner); } void IPCTestBase::DestroyChannelProxy() { @@ -135,3 +137,9 @@ bool IPCTestBase::WaitForClientShutdown() { scoped_refptr<base::TaskRunner> IPCTestBase::task_runner() { return message_loop_->message_loop_proxy(); } + +scoped_ptr<IPC::ChannelFactory> IPCTestBase::CreateChannelFactory( + const IPC::ChannelHandle& handle, + base::TaskRunner* runner) { + return IPC::ChannelFactory::Create(handle, IPC::Channel::MODE_SERVER); +} diff --git a/ipc/ipc_test_base.h b/ipc/ipc_test_base.h index ff34945..8fdcbb0 100644 --- a/ipc/ipc_test_base.h +++ b/ipc/ipc_test_base.h @@ -12,6 +12,7 @@ #include "base/process/process.h" #include "base/test/multiprocess_test.h" #include "ipc/ipc_channel.h" +#include "ipc/ipc_channel_factory.h" #include "ipc/ipc_channel_proxy.h" #include "ipc/ipc_multiprocess_test.h" @@ -95,6 +96,9 @@ class IPCTestBase : public base::MultiProcessTest { const base::ProcessHandle& client_process() const { return client_process_; } scoped_refptr<base::TaskRunner> task_runner(); + virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( + const IPC::ChannelHandle& handle, base::TaskRunner* runner); + private: std::string test_client_name_; scoped_ptr<base::MessageLoop> message_loop_; diff --git a/ipc/mojo/BUILD.gn b/ipc/mojo/BUILD.gn index d059b48..58c1f03 100644 --- a/ipc/mojo/BUILD.gn +++ b/ipc/mojo/BUILD.gn @@ -40,3 +40,22 @@ test("ipc_mojo_unittests") { "//url", ] } + +test("ipc_mojo_perftests") { + sources = [ + "ipc_mojo_perftest.cc", + ] + + deps = [ + "//base", + "//base/test:test_support", + "//base/test:test_support_perf", + "//base/third_party/dynamic_annotations", + "//ipc", + "//ipc:test_support", + "//ipc/mojo", + "//mojo/environment:chromium", + "//mojo/system", + "//url", + ] +} diff --git a/ipc/mojo/ipc_channel_mojo.cc b/ipc/mojo/ipc_channel_mojo.cc index 88034f1..cdb9281 100644 --- a/ipc/mojo/ipc_channel_mojo.cc +++ b/ipc/mojo/ipc_channel_mojo.cc @@ -456,19 +456,11 @@ void ChannelMojo::ChannelInfoDeleter::operator()( // static scoped_ptr<ChannelMojo> ChannelMojo::Create( - scoped_ptr<Channel> bootstrap, Mode mode, Listener* listener, - scoped_refptr<base::TaskRunner> io_thread_task_runner) { - return make_scoped_ptr(new ChannelMojo( - bootstrap.Pass(), mode, listener, io_thread_task_runner)); -} - -// static -scoped_ptr<ChannelMojo> ChannelMojo::Create( const ChannelHandle &channel_handle, Mode mode, Listener* listener, scoped_refptr<base::TaskRunner> io_thread_task_runner) { - return Create( + return make_scoped_ptr(new ChannelMojo( Channel::Create(channel_handle, mode, g_null_listener.Pointer()), - mode, listener, io_thread_task_runner); + mode, listener, io_thread_task_runner)); } // static diff --git a/ipc/mojo/ipc_channel_mojo.h b/ipc/mojo/ipc_channel_mojo.h index 4d4df63..dd57bc8 100644 --- a/ipc/mojo/ipc_channel_mojo.h +++ b/ipc/mojo/ipc_channel_mojo.h @@ -50,11 +50,6 @@ namespace IPC { // class IPC_MOJO_EXPORT ChannelMojo : public Channel { public: - // Create ChannelMojo on top of given |bootstrap| channel. - static scoped_ptr<ChannelMojo> Create( - scoped_ptr<Channel> bootstrap, Mode mode, Listener* listener, - scoped_refptr<base::TaskRunner> io_thread_task_runner); - // Create ChannelMojo. A bootstrap channel is created as well. static scoped_ptr<ChannelMojo> Create( const ChannelHandle &channel_handle, Mode mode, Listener* listener, diff --git a/ipc/mojo/ipc_channel_mojo_unittest.cc b/ipc/mojo/ipc_channel_mojo_unittest.cc index 60069b7..8ea828f 100644 --- a/ipc/mojo/ipc_channel_mojo_unittest.cc +++ b/ipc/mojo/ipc_channel_mojo_unittest.cc @@ -55,33 +55,11 @@ class ListenerThatExpectsOK : public IPC::Listener { bool received_ok_; }; -class ListenerThatShouldBeNeverCalled : public IPC::Listener { - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { - NOTREACHED(); - return true; - } - - virtual void OnChannelError() OVERRIDE { - NOTREACHED(); - } - - virtual void OnChannelConnected(int32 peer_pid) OVERRIDE { - NOTREACHED(); - } - - virtual void OnBadMessageReceived(const IPC::Message& message) OVERRIDE { - NOTREACHED(); - } -}; - class ChannelClient { public: explicit ChannelClient(IPC::Listener* listener, const char* name) { - scoped_ptr<IPC::Channel> bootstrap(IPC::Channel::CreateClient( - IPCTestBase::GetChannelName(name), - &never_called_)); channel_ = IPC::ChannelMojo::Create( - bootstrap.Pass(), IPC::Channel::MODE_CLIENT, listener, + IPCTestBase::GetChannelName(name), IPC::Channel::MODE_CLIENT, listener, main_message_loop_.message_loop_proxy()); } @@ -93,31 +71,20 @@ class ChannelClient { private: scoped_ptr<IPC::ChannelMojo> channel_; - ListenerThatShouldBeNeverCalled never_called_; base::MessageLoopForIO main_message_loop_; }; class IPCChannelMojoTest : public IPCTestBase { - public: - void CreateMojoChannel(IPC::Listener* listener); - protected: - virtual void SetUp() OVERRIDE { - IPCTestBase::SetUp(); + virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( + const IPC::ChannelHandle& handle, + base::TaskRunner* runner) OVERRIDE { + return IPC::ChannelMojo::CreateFactory( + handle, IPC::Channel::MODE_SERVER, runner); } - - ListenerThatShouldBeNeverCalled never_called_; }; -void IPCChannelMojoTest::CreateMojoChannel(IPC::Listener* listener) { - CreateChannel(&never_called_); - scoped_ptr<IPC::Channel> mojo_channel = IPC::ChannelMojo::Create( - ReleaseChannel(), IPC::Channel::MODE_SERVER, listener, - task_runner()).PassAs<IPC::Channel>(); - SetChannel(mojo_channel.PassAs<IPC::Channel>()); -} - class TestChannelListenerWithExtraExpectations : public IPC::TestChannelListener { public: @@ -142,7 +109,7 @@ TEST_F(IPCChannelMojoTest, ConnectedFromClient) { // Set up IPC channel and start client. TestChannelListenerWithExtraExpectations listener; - CreateMojoChannel(&listener); + CreateChannel(&listener); listener.Init(sender()); ASSERT_TRUE(ConnectChannel()); ASSERT_TRUE(StartClient()); @@ -236,7 +203,7 @@ TEST_F(IPCChannelMojoTest, SendPlatformHandle) { Init("IPCChannelMojoTestSendPlatformHandleClient"); ListenerThatExpectsOK listener; - CreateMojoChannel(&listener); + CreateChannel(&listener); ASSERT_TRUE(ConnectChannel()); ASSERT_TRUE(StartClient()); diff --git a/ipc/mojo/ipc_mojo.gyp b/ipc/mojo/ipc_mojo.gyp index c408a17..f01d48f 100644 --- a/ipc/mojo/ipc_mojo.gyp +++ b/ipc/mojo/ipc_mojo.gyp @@ -64,5 +64,30 @@ 'conditions': [ ], }, + { + 'target_name': 'ipc_mojo_perftests', + 'type': '<(gtest_target_type)', + 'dependencies': [ + '../ipc.gyp:ipc', + '../ipc.gyp:test_support_ipc', + '../../base/base.gyp:base', + '../../base/base.gyp:base_i18n', + '../../base/base.gyp:test_support_base', + '../../base/base.gyp:test_support_perf', + '../../mojo/mojo_base.gyp:mojo_cpp_bindings', + '../../mojo/mojo_base.gyp:mojo_environment_chromium', + '../../mojo/mojo_base.gyp:mojo_system_impl', + '../../testing/gtest.gyp:gtest', + 'ipc_mojo', + ], + 'include_dirs': [ + '..' + ], + 'sources': [ + 'ipc_mojo_perftest.cc', + ], + 'conditions': [ + ], + }, ], } diff --git a/ipc/mojo/ipc_mojo_perftest.cc b/ipc/mojo/ipc_mojo_perftest.cc new file mode 100644 index 0000000..d433703 --- /dev/null +++ b/ipc/mojo/ipc_mojo_perftest.cc @@ -0,0 +1,87 @@ +// 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/lazy_instance.h" +#include "ipc/ipc_perftest_support.h" +#include "ipc/mojo/ipc_channel_mojo.h" +#include "mojo/embedder/test_embedder.h" + +namespace { + +// This is needed because we rely on //base/test:test_support_perf and +// it provides main() which doesn't have Mojo initialization. We need +// some way to call InitWithSimplePlatformSupport() only once before +// using Mojo. +struct MojoInitialier { + MojoInitialier() { + mojo::embedder::test::InitWithSimplePlatformSupport(); + } +}; + +base::LazyInstance<MojoInitialier> g_mojo_initializer + = LAZY_INSTANCE_INITIALIZER; + +class MojoChannelPerfTest : public IPC::test::IPCChannelPerfTestBase { +public: + typedef IPC::test::IPCChannelPerfTestBase Super; + + MojoChannelPerfTest(); + + virtual scoped_ptr<IPC::ChannelFactory> CreateChannelFactory( + const IPC::ChannelHandle& handle, + base::TaskRunner* runner) OVERRIDE { + return IPC::ChannelMojo::CreateFactory( + handle, IPC::Channel::MODE_SERVER, runner); + } + + void set_io_thread_task_runner(base::TaskRunner* runner) { + io_thread_task_runner_ = runner; + } + + private: + base::TaskRunner* io_thread_task_runner_; +}; + +MojoChannelPerfTest::MojoChannelPerfTest() + : io_thread_task_runner_() { + g_mojo_initializer.Get(); +} + + +TEST_F(MojoChannelPerfTest, ChannelPingPong) { + RunTestChannelPingPong(GetDefaultTestParams()); +} + +TEST_F(MojoChannelPerfTest, ChannelProxyPingPong) { + RunTestChannelProxyPingPong(GetDefaultTestParams()); +} + +class MojoTestClient : public IPC::test::PingPongTestClient { + public: + typedef IPC::test::PingPongTestClient SuperType; + + MojoTestClient(); + + virtual scoped_ptr<IPC::Channel> CreateChannel( + IPC::Listener* listener) OVERRIDE; +}; + +MojoTestClient::MojoTestClient() { + g_mojo_initializer.Get(); +} + +scoped_ptr<IPC::Channel> MojoTestClient::CreateChannel( + IPC::Listener* listener) { + return scoped_ptr<IPC::Channel>(IPC::ChannelMojo::Create( + IPCTestBase::GetChannelName("PerformanceClient"), + IPC::Channel::MODE_CLIENT, listener, + task_runner())); +} + +MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) { + MojoTestClient client; + return client.RunMain(); +} + +} // namespace |