[go: nahoru, domu]

Add ipc_mojo_perftests

This change adds ipc_mojo_perftests that runs the same benchmark
as of ipc_perftests. Now head-to-head comparison becomes possible.

For this change, whole ipc_perftests logic is extracted to
ipc_perftest_support.cc to make it reusable by ipc_mojo_perftests.

TEST=none
BUG=none
R=jam@chromium.org, darin@chromium.org, yuzhu@chromium.org

Review URL: https://codereview.chromium.org/536213002

Cr-Commit-Position: refs/heads/master@{#293988}
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 @@
   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 fbd4ae0a..d27af58 100644
--- a/ipc/ipc_channel.h
+++ b/ipc/ipc_channel.h
@@ -118,7 +118,7 @@
   // 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 @@
 // 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..b8264204
--- /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..cb406260 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 @@
 //
 // 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()));
+  RunTestChannelProxyPingPong(GetDefaultTestParams());
+}
 
-  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);
-
-  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..6abef0f14 100644
--- a/ipc/ipc_test_base.cc
+++ b/ipc/ipc_test_base.cc
@@ -52,8 +52,8 @@
 }
 
 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 @@
     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 @@
     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 @@
 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 ff34945f..8fdcbb0f 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 @@
   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..58c1f030 100644
--- a/ipc/mojo/BUILD.gn
+++ b/ipc/mojo/BUILD.gn
@@ -40,3 +40,22 @@
     "//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 @@
 
 // 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 @@
 //
 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 60069b7df..8ea828f4 100644
--- a/ipc/mojo/ipc_channel_mojo_unittest.cc
+++ b/ipc/mojo/ipc_channel_mojo_unittest.cc
@@ -55,33 +55,11 @@
   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 @@
 
  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 @@
 
   // 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 @@
   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 c408a170..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