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