• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stddef.h>
6 #include <memory>
7 
8 #include "base/memory/ptr_util.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/message_loop/message_loop_current.h"
11 #include "base/process/process_metrics.h"
12 #include "base/run_loop.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/test/perf_time_logger.h"
16 #include "base/threading/thread.h"
17 #include "build/build_config.h"
18 #include "ipc/ipc_channel_mojo.h"
19 #include "ipc/ipc_perftest_messages.h"
20 #include "ipc/ipc_perftest_util.h"
21 #include "ipc/ipc_sync_channel.h"
22 #include "ipc/ipc_test.mojom.h"
23 #include "ipc/ipc_test_base.h"
24 #include "mojo/core/embedder/embedder.h"
25 #include "mojo/core/test/mojo_test_base.h"
26 #include "mojo/core/test/multiprocess_test_helper.h"
27 #include "mojo/public/cpp/bindings/associated_binding_set.h"
28 #include "mojo/public/cpp/bindings/binding.h"
29 #include "mojo/public/cpp/bindings/binding_set.h"
30 #include "mojo/public/cpp/system/message_pipe.h"
31 
32 namespace IPC {
33 namespace {
34 
35 class PerformanceChannelListener : public Listener {
36  public:
PerformanceChannelListener(const std::string & label)37   explicit PerformanceChannelListener(const std::string& label)
38       : label_(label),
39         sender_(NULL),
40         msg_count_(0),
41         msg_size_(0),
42         sync_(false),
43         count_down_(0) {
44     VLOG(1) << "Server listener up";
45   }
46 
~PerformanceChannelListener()47   ~PerformanceChannelListener() override { VLOG(1) << "Server listener down"; }
48 
Init(Sender * sender)49   void Init(Sender* sender) {
50     DCHECK(!sender_);
51     sender_ = sender;
52   }
53 
54   // Call this before running the message loop.
SetTestParams(int msg_count,size_t msg_size,bool sync)55   void SetTestParams(int msg_count, size_t msg_size, bool sync) {
56     DCHECK_EQ(0, count_down_);
57     msg_count_ = msg_count;
58     msg_size_ = msg_size;
59     sync_ = sync;
60     count_down_ = msg_count_;
61     payload_ = std::string(msg_size_, 'a');
62   }
63 
OnMessageReceived(const Message & message)64   bool OnMessageReceived(const Message& message) override {
65     CHECK(sender_);
66 
67     bool handled = true;
68     IPC_BEGIN_MESSAGE_MAP(PerformanceChannelListener, message)
69       IPC_MESSAGE_HANDLER(TestMsg_Hello, OnHello)
70       IPC_MESSAGE_HANDLER(TestMsg_Ping, OnPing)
71       IPC_MESSAGE_UNHANDLED(handled = false)
72     IPC_END_MESSAGE_MAP()
73     return handled;
74   }
75 
OnHello()76   void OnHello() {
77     // Start timing on hello.
78     DCHECK(!perf_logger_.get());
79     std::string test_name =
80         base::StringPrintf("IPC_%s_Perf_%dx_%u", label_.c_str(), msg_count_,
81                            static_cast<unsigned>(msg_size_));
82     perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str()));
83     if (sync_) {
84       for (; count_down_ > 0; --count_down_) {
85         std::string response;
86         sender_->Send(new TestMsg_SyncPing(payload_, &response));
87         DCHECK_EQ(response, payload_);
88       }
89       perf_logger_.reset();
90       base::RunLoop::QuitCurrentWhenIdleDeprecated();
91     } else {
92       SendPong();
93     }
94   }
95 
OnPing(const std::string & payload)96   void OnPing(const std::string& payload) {
97     // Include message deserialization in latency.
98     DCHECK_EQ(payload_.size(), payload.size());
99 
100     CHECK(count_down_ > 0);
101     count_down_--;
102     if (count_down_ == 0) {
103       perf_logger_.reset();  // Stop the perf timer now.
104       base::RunLoop::QuitCurrentWhenIdleDeprecated();
105       return;
106     }
107 
108     SendPong();
109   }
110 
SendPong()111   void SendPong() { sender_->Send(new TestMsg_Ping(payload_)); }
112 
113  private:
114   std::string label_;
115   Sender* sender_;
116   int msg_count_;
117   size_t msg_size_;
118   bool sync_;
119 
120   int count_down_;
121   std::string payload_;
122   std::unique_ptr<base::PerfTimeLogger> perf_logger_;
123 };
124 
125 class PingPongTestParams {
126  public:
PingPongTestParams(size_t size,int count)127   PingPongTestParams(size_t size, int count)
128       : message_size_(size), message_count_(count) {}
129 
message_size() const130   size_t message_size() const { return message_size_; }
message_count() const131   int message_count() const { return message_count_; }
132 
133  private:
134   size_t message_size_;
135   int message_count_;
136 };
137 
138 class InterfacePassingTestParams {
139  public:
InterfacePassingTestParams(size_t rounds,size_t num_interfaces)140   InterfacePassingTestParams(size_t rounds, size_t num_interfaces)
141       : rounds_(rounds), num_interfaces_(num_interfaces) {}
142 
rounds() const143   size_t rounds() const { return rounds_; }
num_interfaces() const144   size_t num_interfaces() const { return num_interfaces_; }
145 
146  private:
147   size_t rounds_;
148   size_t num_interfaces_;
149 };
150 
151 #ifdef NDEBUG
152 const int kMultiplier = 100;
153 #else
154   // Debug builds on Windows run these tests orders of magnitude more slowly.
155 const int kMultiplier = 1;
156 #endif
157 
GetDefaultTestParams()158 std::vector<PingPongTestParams> GetDefaultTestParams() {
159   // Test several sizes. We use 12^N for message size, and limit the message
160   // count to keep the test duration reasonable.
161   std::vector<PingPongTestParams> list;
162   list.push_back(PingPongTestParams(12, 500 * kMultiplier));
163   list.push_back(PingPongTestParams(144, 500 * kMultiplier));
164   list.push_back(PingPongTestParams(1728, 500 * kMultiplier));
165   list.push_back(PingPongTestParams(20736, 120 * kMultiplier));
166   list.push_back(PingPongTestParams(248832, 10 * kMultiplier));
167   return list;
168 }
169 
GetDefaultInterfacePassingTestParams()170 std::vector<InterfacePassingTestParams> GetDefaultInterfacePassingTestParams() {
171   std::vector<InterfacePassingTestParams> list;
172   list.push_back({500 * kMultiplier, 0});
173   list.push_back({500 * kMultiplier, 1});
174   list.push_back({500 * kMultiplier, 2});
175   list.push_back({500 * kMultiplier, 4});
176   list.push_back({500 * kMultiplier, 8});
177   return list;
178 }
179 
180 class MojoChannelPerfTest : public IPCChannelMojoTestBase {
181  public:
182   MojoChannelPerfTest() = default;
183   ~MojoChannelPerfTest() override = default;
184 
RunTestChannelProxyPingPong()185   void RunTestChannelProxyPingPong() {
186     Init("MojoPerfTestClient");
187 
188     // Set up IPC channel and start client.
189     PerformanceChannelListener listener("ChannelProxy");
190     auto channel_proxy = IPC::ChannelProxy::Create(
191         TakeHandle().release(), IPC::Channel::MODE_SERVER, &listener,
192         GetIOThreadTaskRunner(), base::ThreadTaskRunnerHandle::Get());
193     listener.Init(channel_proxy.get());
194 
195     LockThreadAffinity thread_locker(kSharedCore);
196     std::vector<PingPongTestParams> params = GetDefaultTestParams();
197     for (size_t i = 0; i < params.size(); i++) {
198       listener.SetTestParams(params[i].message_count(),
199                              params[i].message_size(), false);
200 
201       // This initial message will kick-start the ping-pong of messages.
202       channel_proxy->Send(new TestMsg_Hello);
203 
204       // Run message loop.
205       base::RunLoop().Run();
206     }
207 
208     // Send quit message.
209     channel_proxy->Send(new TestMsg_Quit);
210 
211     EXPECT_TRUE(WaitForClientShutdown());
212     channel_proxy.reset();
213   }
214 
RunTestChannelProxySyncPing()215   void RunTestChannelProxySyncPing() {
216     Init("MojoPerfTestClient");
217 
218     // Set up IPC channel and start client.
219     PerformanceChannelListener listener("ChannelProxy");
220     base::WaitableEvent shutdown_event(
221         base::WaitableEvent::ResetPolicy::MANUAL,
222         base::WaitableEvent::InitialState::NOT_SIGNALED);
223     auto channel_proxy = IPC::SyncChannel::Create(
224         TakeHandle().release(), IPC::Channel::MODE_SERVER, &listener,
225         GetIOThreadTaskRunner(), base::ThreadTaskRunnerHandle::Get(), false,
226         &shutdown_event);
227     listener.Init(channel_proxy.get());
228 
229     LockThreadAffinity thread_locker(kSharedCore);
230     std::vector<PingPongTestParams> params = GetDefaultTestParams();
231     for (size_t i = 0; i < params.size(); i++) {
232       listener.SetTestParams(params[i].message_count(),
233                              params[i].message_size(), true);
234 
235       // This initial message will kick-start the ping-pong of messages.
236       channel_proxy->Send(new TestMsg_Hello);
237 
238       // Run message loop.
239       base::RunLoop().Run();
240     }
241 
242     // Send quit message.
243     channel_proxy->Send(new TestMsg_Quit);
244 
245     EXPECT_TRUE(WaitForClientShutdown());
246     channel_proxy.reset();
247   }
248 };
249 
TEST_F(MojoChannelPerfTest,ChannelProxyPingPong)250 TEST_F(MojoChannelPerfTest, ChannelProxyPingPong) {
251   RunTestChannelProxyPingPong();
252 
253   base::RunLoop run_loop;
254   run_loop.RunUntilIdle();
255 }
256 
TEST_F(MojoChannelPerfTest,ChannelProxySyncPing)257 TEST_F(MojoChannelPerfTest, ChannelProxySyncPing) {
258   RunTestChannelProxySyncPing();
259 
260   base::RunLoop run_loop;
261   run_loop.RunUntilIdle();
262 }
263 
MULTIPROCESS_TEST_MAIN(MojoPerfTestClientTestChildMain)264 MULTIPROCESS_TEST_MAIN(MojoPerfTestClientTestChildMain) {
265   MojoPerfTestClient client;
266   int rv = mojo::core::test::MultiprocessTestHelper::RunClientMain(
267       base::Bind(&MojoPerfTestClient::Run, base::Unretained(&client)),
268       true /* pass_pipe_ownership_to_main */);
269 
270   base::RunLoop run_loop;
271   run_loop.RunUntilIdle();
272 
273   return rv;
274 }
275 
276 class MojoInterfacePerfTest : public mojo::core::test::MojoTestBase {
277  public:
MojoInterfacePerfTest()278   MojoInterfacePerfTest() : message_count_(0), count_down_(0) {}
279 
280  protected:
RunPingPongServer(MojoHandle mp,const std::string & label)281   void RunPingPongServer(MojoHandle mp, const std::string& label) {
282     label_ = label;
283 
284     mojo::MessagePipeHandle mp_handle(mp);
285     mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
286     ping_receiver_.Bind(IPC::mojom::ReflectorPtrInfo(std::move(scoped_mp), 0u));
287 
288     LockThreadAffinity thread_locker(kSharedCore);
289     std::vector<PingPongTestParams> params = GetDefaultTestParams();
290     for (size_t i = 0; i < params.size(); i++) {
291       ping_receiver_->Ping("hello", base::Bind(&MojoInterfacePerfTest::OnPong,
292                                                base::Unretained(this)));
293       message_count_ = count_down_ = params[i].message_count();
294       payload_ = std::string(params[i].message_size(), 'a');
295 
296       base::RunLoop().Run();
297     }
298 
299     ping_receiver_->Quit();
300 
301     ignore_result(ping_receiver_.PassInterface().PassHandle().release());
302   }
303 
OnPong(const std::string & value)304   void OnPong(const std::string& value) {
305     if (value == "hello") {
306       DCHECK(!perf_logger_.get());
307       std::string test_name =
308           base::StringPrintf("IPC_%s_Perf_%dx_%zu", label_.c_str(),
309                              message_count_, payload_.size());
310       perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str()));
311     } else {
312       DCHECK_EQ(payload_.size(), value.size());
313 
314       CHECK(count_down_ > 0);
315       count_down_--;
316       if (count_down_ == 0) {
317         perf_logger_.reset();
318         base::RunLoop::QuitCurrentWhenIdleDeprecated();
319         return;
320       }
321     }
322 
323     if (sync_) {
324       for (int i = 0; i < count_down_; ++i) {
325         std::string response;
326         ping_receiver_->SyncPing(payload_, &response);
327         DCHECK_EQ(response, payload_);
328       }
329       perf_logger_.reset();
330       base::RunLoop::QuitCurrentWhenIdleDeprecated();
331     } else {
332       ping_receiver_->Ping(payload_, base::Bind(&MojoInterfacePerfTest::OnPong,
333                                                 base::Unretained(this)));
334     }
335   }
336 
RunPingPongClient(MojoHandle mp)337   static int RunPingPongClient(MojoHandle mp) {
338     mojo::MessagePipeHandle mp_handle(mp);
339     mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
340 
341     LockThreadAffinity thread_locker(kSharedCore);
342     // In single process mode, this is running in a task and by default other
343     // tasks (in particular, the binding) won't run. To keep the single process
344     // and multi-process code paths the same, enable nestable tasks.
345     base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
346     ReflectorImpl impl(std::move(scoped_mp), run_loop.QuitWhenIdleClosure());
347     run_loop.Run();
348     return 0;
349   }
350 
351   bool sync_ = false;
352 
353  private:
354   int message_count_;
355   int count_down_;
356   std::string label_;
357   std::string payload_;
358   IPC::mojom::ReflectorPtr ping_receiver_;
359   std::unique_ptr<base::PerfTimeLogger> perf_logger_;
360 
361   DISALLOW_COPY_AND_ASSIGN(MojoInterfacePerfTest);
362 };
363 
364 class InterfacePassingTestDriverImpl : public mojom::InterfacePassingTestDriver,
365                                        public mojom::PingReceiver {
366  public:
InterfacePassingTestDriverImpl(mojo::ScopedMessagePipeHandle handle,const base::Closure & quit_closure)367   InterfacePassingTestDriverImpl(mojo::ScopedMessagePipeHandle handle,
368                                  const base::Closure& quit_closure)
369       : binding_(this,
370                  mojom::InterfacePassingTestDriverRequest(std::move(handle))),
371         quit_closure_(quit_closure) {}
~InterfacePassingTestDriverImpl()372   ~InterfacePassingTestDriverImpl() override {
373     ignore_result(binding_.Unbind().PassMessagePipe().release());
374   }
375 
376  private:
377   // mojom::InterfacePassingTestDriver implementation:
Init(InitCallback callback)378   void Init(InitCallback callback) override { std::move(callback).Run(); }
379 
GetPingReceiver(std::vector<mojom::PingReceiverRequest> requests,GetPingReceiverCallback callback)380   void GetPingReceiver(std::vector<mojom::PingReceiverRequest> requests,
381                        GetPingReceiverCallback callback) override {
382     for (auto& request : requests)
383       ping_receiver_bindings_.AddBinding(this, std::move(request));
384     ping_receiver_bindings_.CloseAllBindings();
385     std::move(callback).Run();
386   }
387 
GetAssociatedPingReceiver(std::vector<mojom::PingReceiverAssociatedRequest> requests,GetAssociatedPingReceiverCallback callback)388   void GetAssociatedPingReceiver(
389       std::vector<mojom::PingReceiverAssociatedRequest> requests,
390       GetAssociatedPingReceiverCallback callback) override {
391     for (auto& request : requests)
392       ping_receiver_associated_bindings_.AddBinding(this, std::move(request));
393     ping_receiver_associated_bindings_.CloseAllBindings();
394     std::move(callback).Run();
395   }
396 
Quit()397   void Quit() override {
398     if (quit_closure_)
399       quit_closure_.Run();
400   }
401 
402   // mojom::PingReceiver implementation:
Ping(PingCallback callback)403   void Ping(PingCallback callback) override { std::move(callback).Run(); }
404 
405   mojo::BindingSet<mojom::PingReceiver> ping_receiver_bindings_;
406   mojo::AssociatedBindingSet<mojom::PingReceiver>
407       ping_receiver_associated_bindings_;
408   mojo::Binding<mojom::InterfacePassingTestDriver> binding_;
409 
410   base::Closure quit_closure_;
411 };
412 
413 class MojoInterfacePassingPerfTest : public mojo::core::test::MojoTestBase {
414  public:
415   MojoInterfacePassingPerfTest() = default;
416 
417  protected:
RunInterfacePassingServer(MojoHandle mp,const std::string & label,bool associated)418   void RunInterfacePassingServer(MojoHandle mp,
419                                  const std::string& label,
420                                  bool associated) {
421     label_ = label;
422     associated_ = associated;
423 
424     mojo::MessagePipeHandle mp_handle(mp);
425     mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
426     driver_ptr_.Bind(
427         mojom::InterfacePassingTestDriverPtrInfo(std::move(scoped_mp), 0u));
428 
429     auto params = GetDefaultInterfacePassingTestParams();
430 
431     LockThreadAffinity thread_locker(kSharedCore);
432     for (size_t i = 0; i < params.size(); ++i) {
433       driver_ptr_->Init(
434           base::Bind(&MojoInterfacePassingPerfTest::OnInitCallback,
435                      base::Unretained(this)));
436       rounds_ = count_down_ = params[i].rounds();
437       num_interfaces_ = params[i].num_interfaces();
438 
439       base::RunLoop run_loop;
440       quit_closure_ = run_loop.QuitWhenIdleClosure();
441       run_loop.Run();
442     }
443 
444     driver_ptr_->Quit();
445 
446     ignore_result(driver_ptr_.PassInterface().PassHandle().release());
447   }
448 
OnInitCallback()449   void OnInitCallback() {
450     DCHECK(!perf_logger_.get());
451     std::string test_name = base::StringPrintf(
452         "IPC_%s_Perf_%zux_%zu", label_.c_str(), rounds_, num_interfaces_);
453     perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str()));
454 
455     DoNextRound();
456   }
457 
DoNextRound()458   void DoNextRound() {
459     if (associated_) {
460       std::vector<mojom::PingReceiverAssociatedPtr> associated_interfaces(
461           num_interfaces_);
462 
463       std::vector<mojom::PingReceiverAssociatedRequest> requests(
464           num_interfaces_);
465       for (size_t i = 0; i < num_interfaces_; ++i) {
466         requests[i] = mojo::MakeRequest(&associated_interfaces[i]);
467         // Force the interface pointer to do full initialization.
468         associated_interfaces[i].get();
469       }
470 
471       driver_ptr_->GetAssociatedPingReceiver(
472           std::move(requests),
473           base::Bind(&MojoInterfacePassingPerfTest::OnGetReceiverCallback,
474                      base::Unretained(this)));
475     } else {
476       std::vector<mojom::PingReceiverPtr> interfaces(num_interfaces_);
477 
478       std::vector<mojom::PingReceiverRequest> requests(num_interfaces_);
479       for (size_t i = 0; i < num_interfaces_; ++i) {
480         requests[i] = mojo::MakeRequest(&interfaces[i]);
481         // Force the interface pointer to do full initialization.
482         interfaces[i].get();
483       }
484 
485       driver_ptr_->GetPingReceiver(
486           std::move(requests),
487           base::Bind(&MojoInterfacePassingPerfTest::OnGetReceiverCallback,
488                      base::Unretained(this)));
489     }
490   }
491 
OnGetReceiverCallback()492   void OnGetReceiverCallback() {
493     CHECK_GT(count_down_, 0u);
494     count_down_--;
495 
496     if (count_down_ == 0) {
497       perf_logger_.reset();
498       quit_closure_.Run();
499       return;
500     }
501 
502     DoNextRound();
503   }
504 
RunInterfacePassingClient(MojoHandle mp)505   static int RunInterfacePassingClient(MojoHandle mp) {
506     mojo::MessagePipeHandle mp_handle(mp);
507     mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
508 
509     LockThreadAffinity thread_locker(kSharedCore);
510     // In single process mode, this is running in a task and by default other
511     // tasks (in particular, the binding) won't run. To keep the single process
512     // and multi-process code paths the same, enable nestable tasks.
513     base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
514     InterfacePassingTestDriverImpl impl(std::move(scoped_mp),
515                                         run_loop.QuitWhenIdleClosure());
516     run_loop.Run();
517     return 0;
518   }
519 
520  private:
521   size_t rounds_ = 0;
522   size_t count_down_ = 0;
523   size_t num_interfaces_ = 0;
524   std::string label_;
525   bool associated_ = false;
526   std::unique_ptr<base::PerfTimeLogger> perf_logger_;
527 
528   mojom::InterfacePassingTestDriverPtr driver_ptr_;
529 
530   base::Closure quit_closure_;
531 
532   DISALLOW_COPY_AND_ASSIGN(MojoInterfacePassingPerfTest);
533 };
534 
DEFINE_TEST_CLIENT_WITH_PIPE(InterfacePassingClient,MojoInterfacePassingPerfTest,h)535 DEFINE_TEST_CLIENT_WITH_PIPE(InterfacePassingClient,
536                              MojoInterfacePassingPerfTest,
537                              h) {
538   base::MessageLoop main_message_loop;
539   return RunInterfacePassingClient(h);
540 }
541 
542 enum class InProcessMessageMode {
543   kSerialized,
544   kUnserialized,
545 };
546 
547 template <class TestBase>
548 class InProcessPerfTest
549     : public TestBase,
550       public testing::WithParamInterface<InProcessMessageMode> {
551  public:
InProcessPerfTest()552   InProcessPerfTest() {
553     switch (GetParam()) {
554       case InProcessMessageMode::kSerialized:
555         mojo::Connector::OverrideDefaultSerializationBehaviorForTesting(
556             mojo::Connector::OutgoingSerializationMode::kEager,
557             mojo::Connector::IncomingSerializationMode::kDispatchAsIs);
558         break;
559       case InProcessMessageMode::kUnserialized:
560         mojo::Connector::OverrideDefaultSerializationBehaviorForTesting(
561             mojo::Connector::OutgoingSerializationMode::kLazy,
562             mojo::Connector::IncomingSerializationMode::kDispatchAsIs);
563         break;
564     }
565   }
566 };
567 
568 using MojoInProcessInterfacePerfTest = InProcessPerfTest<MojoInterfacePerfTest>;
569 using MojoInProcessInterfacePassingPerfTest =
570     InProcessPerfTest<MojoInterfacePassingPerfTest>;
571 
DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient,MojoInterfacePerfTest,h)572 DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient, MojoInterfacePerfTest, h) {
573   base::MessageLoop main_message_loop;
574   return RunPingPongClient(h);
575 }
576 
577 // Similar to MojoChannelPerfTest above, but uses a Mojo interface instead of
578 // raw IPC::Messages.
TEST_F(MojoInterfacePerfTest,MultiprocessPingPong)579 TEST_F(MojoInterfacePerfTest, MultiprocessPingPong) {
580   RunTestClient("PingPongClient", [&](MojoHandle h) {
581     base::MessageLoop main_message_loop;
582     RunPingPongServer(h, "Multiprocess");
583   });
584 }
585 
TEST_F(MojoInterfacePerfTest,MultiprocessSyncPing)586 TEST_F(MojoInterfacePerfTest, MultiprocessSyncPing) {
587   sync_ = true;
588   RunTestClient("PingPongClient", [&](MojoHandle h) {
589     base::MessageLoop main_message_loop;
590     RunPingPongServer(h, "MultiprocessSync");
591   });
592 }
593 
TEST_F(MojoInterfacePassingPerfTest,MultiprocessInterfacePassing)594 TEST_F(MojoInterfacePassingPerfTest, MultiprocessInterfacePassing) {
595   RunTestClient("InterfacePassingClient", [&](MojoHandle h) {
596     base::MessageLoop main_message_loop;
597     RunInterfacePassingServer(h, "InterfacePassing", false /* associated */);
598   });
599 }
600 
TEST_F(MojoInterfacePassingPerfTest,MultiprocessAssociatedInterfacePassing)601 TEST_F(MojoInterfacePassingPerfTest, MultiprocessAssociatedInterfacePassing) {
602   RunTestClient("InterfacePassingClient", [&](MojoHandle h) {
603     base::MessageLoop main_message_loop;
604     RunInterfacePassingServer(h, "AssociatedInterfacePassing",
605                               true /* associated*/);
606   });
607 }
608 
609 // A single process version of the above test.
TEST_P(MojoInProcessInterfacePerfTest,MultiThreadPingPong)610 TEST_P(MojoInProcessInterfacePerfTest, MultiThreadPingPong) {
611   MojoHandle server_handle, client_handle;
612   CreateMessagePipe(&server_handle, &client_handle);
613 
614   base::Thread client_thread("PingPongClient");
615   client_thread.Start();
616   client_thread.task_runner()->PostTask(
617       FROM_HERE,
618       base::Bind(base::IgnoreResult(&RunPingPongClient), client_handle));
619 
620   base::MessageLoop main_message_loop;
621   RunPingPongServer(server_handle, "SingleProcess");
622 }
623 
TEST_P(MojoInProcessInterfacePerfTest,SingleThreadPingPong)624 TEST_P(MojoInProcessInterfacePerfTest, SingleThreadPingPong) {
625   MojoHandle server_handle, client_handle;
626   CreateMessagePipe(&server_handle, &client_handle);
627 
628   base::MessageLoop main_message_loop;
629   mojo::MessagePipeHandle mp_handle(client_handle);
630   mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
631   LockThreadAffinity thread_locker(kSharedCore);
632   ReflectorImpl impl(std::move(scoped_mp), base::Closure());
633 
634   RunPingPongServer(server_handle, "SingleProcess");
635 }
636 
637 INSTANTIATE_TEST_CASE_P(,
638                         MojoInProcessInterfacePerfTest,
639                         testing::Values(InProcessMessageMode::kSerialized,
640                                         InProcessMessageMode::kUnserialized));
641 
TEST_P(MojoInProcessInterfacePassingPerfTest,MultiThreadInterfacePassing)642 TEST_P(MojoInProcessInterfacePassingPerfTest, MultiThreadInterfacePassing) {
643   MojoHandle server_handle, client_handle;
644   CreateMessagePipe(&server_handle, &client_handle);
645 
646   base::Thread client_thread("InterfacePassingClient");
647   client_thread.Start();
648   client_thread.task_runner()->PostTask(
649       FROM_HERE, base::Bind(base::IgnoreResult(&RunInterfacePassingClient),
650                             client_handle));
651 
652   base::MessageLoop main_message_loop;
653   RunInterfacePassingServer(server_handle, "SingleProcess",
654                             false /* associated */);
655 }
656 
TEST_P(MojoInProcessInterfacePassingPerfTest,MultiThreadAssociatedInterfacePassing)657 TEST_P(MojoInProcessInterfacePassingPerfTest,
658        MultiThreadAssociatedInterfacePassing) {
659   MojoHandle server_handle, client_handle;
660   CreateMessagePipe(&server_handle, &client_handle);
661 
662   base::Thread client_thread("InterfacePassingClient");
663   client_thread.Start();
664   client_thread.task_runner()->PostTask(
665       FROM_HERE, base::Bind(base::IgnoreResult(&RunInterfacePassingClient),
666                             client_handle));
667 
668   base::MessageLoop main_message_loop;
669   RunInterfacePassingServer(server_handle, "SingleProcess",
670                             true /* associated */);
671 }
672 
TEST_P(MojoInProcessInterfacePassingPerfTest,SingleThreadInterfacePassing)673 TEST_P(MojoInProcessInterfacePassingPerfTest, SingleThreadInterfacePassing) {
674   MojoHandle server_handle, client_handle;
675   CreateMessagePipe(&server_handle, &client_handle);
676 
677   base::MessageLoop main_message_loop;
678   mojo::MessagePipeHandle mp_handle(client_handle);
679   mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
680   LockThreadAffinity thread_locker(kSharedCore);
681   InterfacePassingTestDriverImpl impl(std::move(scoped_mp), base::Closure());
682 
683   RunInterfacePassingServer(server_handle, "SingleProcess",
684                             false /* associated */);
685 }
686 
TEST_P(MojoInProcessInterfacePassingPerfTest,SingleThreadAssociatedInterfacePassing)687 TEST_P(MojoInProcessInterfacePassingPerfTest,
688        SingleThreadAssociatedInterfacePassing) {
689   MojoHandle server_handle, client_handle;
690   CreateMessagePipe(&server_handle, &client_handle);
691 
692   base::MessageLoop main_message_loop;
693   mojo::MessagePipeHandle mp_handle(client_handle);
694   mojo::ScopedMessagePipeHandle scoped_mp(mp_handle);
695   LockThreadAffinity thread_locker(kSharedCore);
696   InterfacePassingTestDriverImpl impl(std::move(scoped_mp), base::Closure());
697 
698   RunInterfacePassingServer(server_handle, "SingleProcess",
699                             true /* associated */);
700 }
701 
702 INSTANTIATE_TEST_CASE_P(,
703                         MojoInProcessInterfacePassingPerfTest,
704                         testing::Values(InProcessMessageMode::kSerialized,
705                                         InProcessMessageMode::kUnserialized));
706 
707 class CallbackPerfTest : public testing::Test {
708  public:
CallbackPerfTest()709   CallbackPerfTest()
710       : client_thread_("PingPongClient"), message_count_(0), count_down_(0) {}
711 
712  protected:
RunMultiThreadPingPongServer()713   void RunMultiThreadPingPongServer() {
714     client_thread_.Start();
715 
716     LockThreadAffinity thread_locker(kSharedCore);
717     std::vector<PingPongTestParams> params = GetDefaultTestParams();
718     for (size_t i = 0; i < params.size(); i++) {
719       std::string hello("hello");
720       client_thread_.task_runner()->PostTask(
721           FROM_HERE,
722           base::Bind(&CallbackPerfTest::Ping, base::Unretained(this), hello));
723       message_count_ = count_down_ = params[i].message_count();
724       payload_ = std::string(params[i].message_size(), 'a');
725 
726       base::RunLoop().Run();
727     }
728   }
729 
Ping(const std::string & value)730   void Ping(const std::string& value) {
731     main_message_loop_.task_runner()->PostTask(
732         FROM_HERE,
733         base::Bind(&CallbackPerfTest::OnPong, base::Unretained(this), value));
734   }
735 
OnPong(const std::string & value)736   void OnPong(const std::string& value) {
737     if (value == "hello") {
738       DCHECK(!perf_logger_.get());
739       std::string test_name =
740           base::StringPrintf("Callback_MultiProcess_Perf_%dx_%zu",
741                              message_count_, payload_.size());
742       perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str()));
743     } else {
744       DCHECK_EQ(payload_.size(), value.size());
745 
746       CHECK(count_down_ > 0);
747       count_down_--;
748       if (count_down_ == 0) {
749         perf_logger_.reset();
750         base::RunLoop::QuitCurrentWhenIdleDeprecated();
751         return;
752       }
753     }
754 
755     client_thread_.task_runner()->PostTask(
756         FROM_HERE,
757         base::Bind(&CallbackPerfTest::Ping, base::Unretained(this), payload_));
758   }
759 
RunSingleThreadNoPostTaskPingPongServer()760   void RunSingleThreadNoPostTaskPingPongServer() {
761     LockThreadAffinity thread_locker(kSharedCore);
762     std::vector<PingPongTestParams> params = GetDefaultTestParams();
763     base::Callback<void(const std::string&, int,
764                         const base::Callback<void(const std::string&, int)>&)>
765         ping = base::Bind(&CallbackPerfTest::SingleThreadPingNoPostTask,
766                           base::Unretained(this));
767     for (size_t i = 0; i < params.size(); i++) {
768       payload_ = std::string(params[i].message_size(), 'a');
769       std::string test_name =
770           base::StringPrintf("Callback_SingleThreadNoPostTask_Perf_%dx_%zu",
771                              params[i].message_count(), payload_.size());
772       perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str()));
773       for (int j = 0; j < params[i].message_count(); ++j) {
774         ping.Run(payload_, j,
775                  base::Bind(&CallbackPerfTest::SingleThreadPongNoPostTask,
776                             base::Unretained(this)));
777       }
778       perf_logger_.reset();
779     }
780   }
781 
SingleThreadPingNoPostTask(const std::string & value,int i,const base::Callback<void (const std::string &,int)> & pong)782   void SingleThreadPingNoPostTask(
783       const std::string& value,
784       int i,
785       const base::Callback<void(const std::string&, int)>& pong) {
786     pong.Run(value, i);
787   }
788 
SingleThreadPongNoPostTask(const std::string & value,int i)789   void SingleThreadPongNoPostTask(const std::string& value, int i) {}
790 
RunSingleThreadPostTaskPingPongServer()791   void RunSingleThreadPostTaskPingPongServer() {
792     LockThreadAffinity thread_locker(kSharedCore);
793     std::vector<PingPongTestParams> params = GetDefaultTestParams();
794     for (size_t i = 0; i < params.size(); i++) {
795       std::string hello("hello");
796       base::MessageLoopCurrent::Get()->task_runner()->PostTask(
797           FROM_HERE, base::Bind(&CallbackPerfTest::SingleThreadPingPostTask,
798                                 base::Unretained(this), hello));
799       message_count_ = count_down_ = params[i].message_count();
800       payload_ = std::string(params[i].message_size(), 'a');
801 
802       base::RunLoop().Run();
803     }
804   }
805 
SingleThreadPingPostTask(const std::string & value)806   void SingleThreadPingPostTask(const std::string& value) {
807     base::MessageLoopCurrent::Get()->task_runner()->PostTask(
808         FROM_HERE, base::Bind(&CallbackPerfTest::SingleThreadPongPostTask,
809                               base::Unretained(this), value));
810   }
811 
SingleThreadPongPostTask(const std::string & value)812   void SingleThreadPongPostTask(const std::string& value) {
813     if (value == "hello") {
814       DCHECK(!perf_logger_.get());
815       std::string test_name =
816           base::StringPrintf("Callback_SingleThreadPostTask_Perf_%dx_%zu",
817                              message_count_, payload_.size());
818       perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str()));
819     } else {
820       DCHECK_EQ(payload_.size(), value.size());
821 
822       CHECK(count_down_ > 0);
823       count_down_--;
824       if (count_down_ == 0) {
825         perf_logger_.reset();
826         base::RunLoop::QuitCurrentWhenIdleDeprecated();
827         return;
828       }
829     }
830 
831     base::MessageLoopCurrent::Get()->task_runner()->PostTask(
832         FROM_HERE, base::Bind(&CallbackPerfTest::SingleThreadPingPostTask,
833                               base::Unretained(this), payload_));
834   }
835 
836  private:
837   base::Thread client_thread_;
838   base::MessageLoop main_message_loop_;
839   int message_count_;
840   int count_down_;
841   std::string payload_;
842   std::unique_ptr<base::PerfTimeLogger> perf_logger_;
843 
844   DISALLOW_COPY_AND_ASSIGN(CallbackPerfTest);
845 };
846 
847 // Sends the same data as above using PostTask to a different thread instead of
848 // IPCs for comparison.
TEST_F(CallbackPerfTest,MultiThreadPingPong)849 TEST_F(CallbackPerfTest, MultiThreadPingPong) {
850   RunMultiThreadPingPongServer();
851 }
852 
853 // Sends the same data as above using PostTask to the same thread.
TEST_F(CallbackPerfTest,SingleThreadPostTaskPingPong)854 TEST_F(CallbackPerfTest, SingleThreadPostTaskPingPong) {
855   RunSingleThreadPostTaskPingPongServer();
856 }
857 
858 // Sends the same data as above without using PostTask to the same thread.
TEST_F(CallbackPerfTest,SingleThreadNoPostTaskPingPong)859 TEST_F(CallbackPerfTest, SingleThreadNoPostTaskPingPong) {
860   RunSingleThreadNoPostTaskPingPongServer();
861 }
862 
863 }  // namespace
864 }  // namespace IPC
865