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