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