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