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