1 // Copyright 2015 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 <utility>
7
8 #include "base/bind.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/threading/thread_task_runner_handle.h"
12 #include "base/time/time.h"
13 #include "mojo/public/cpp/bindings/binding.h"
14 #include "mojo/public/cpp/bindings/interface_endpoint_client.h"
15 #include "mojo/public/cpp/bindings/lib/multiplex_router.h"
16 #include "mojo/public/cpp/bindings/message.h"
17 #include "mojo/public/cpp/test_support/test_support.h"
18 #include "mojo/public/cpp/test_support/test_utils.h"
19 #include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace mojo {
23 namespace {
24
25 const double kMojoTicksPerSecond = 1000000.0;
26
MojoTicksToSeconds(MojoTimeTicks ticks)27 double MojoTicksToSeconds(MojoTimeTicks ticks) {
28 return ticks / kMojoTicksPerSecond;
29 }
30
31 class PingServiceImpl : public test::PingService {
32 public:
PingServiceImpl()33 PingServiceImpl() {}
~PingServiceImpl()34 ~PingServiceImpl() override {}
35
36 // |PingService| methods:
37 void Ping(const PingCallback& callback) override;
38
39 private:
40 DISALLOW_COPY_AND_ASSIGN(PingServiceImpl);
41 };
42
Ping(const PingCallback & callback)43 void PingServiceImpl::Ping(const PingCallback& callback) {
44 callback.Run();
45 }
46
47 class PingPongTest {
48 public:
49 explicit PingPongTest(test::PingServicePtr service);
50
51 void Run(unsigned int iterations);
52
53 private:
54 void OnPingDone();
55
56 test::PingServicePtr service_;
57 unsigned int iterations_to_run_;
58 unsigned int current_iterations_;
59
60 base::Closure quit_closure_;
61
62 DISALLOW_COPY_AND_ASSIGN(PingPongTest);
63 };
64
PingPongTest(test::PingServicePtr service)65 PingPongTest::PingPongTest(test::PingServicePtr service)
66 : service_(std::move(service)) {}
67
Run(unsigned int iterations)68 void PingPongTest::Run(unsigned int iterations) {
69 iterations_to_run_ = iterations;
70 current_iterations_ = 0;
71
72 base::RunLoop run_loop;
73 quit_closure_ = run_loop.QuitClosure();
74 service_->Ping(base::Bind(&PingPongTest::OnPingDone, base::Unretained(this)));
75 run_loop.Run();
76 }
77
OnPingDone()78 void PingPongTest::OnPingDone() {
79 current_iterations_++;
80 if (current_iterations_ >= iterations_to_run_) {
81 quit_closure_.Run();
82 return;
83 }
84
85 service_->Ping(base::Bind(&PingPongTest::OnPingDone, base::Unretained(this)));
86 }
87
88 struct BoundPingService {
BoundPingServicemojo::__anon25a194a60111::BoundPingService89 BoundPingService() : binding(&impl) { binding.Bind(MakeRequest(&service)); }
90
91 PingServiceImpl impl;
92 test::PingServicePtr service;
93 Binding<test::PingService> binding;
94 };
95
96 class MojoBindingsPerftest : public testing::Test {
97 public:
MojoBindingsPerftest()98 MojoBindingsPerftest() {}
99
100 protected:
101 base::MessageLoop loop_;
102 };
103
TEST_F(MojoBindingsPerftest,InProcessPingPong)104 TEST_F(MojoBindingsPerftest, InProcessPingPong) {
105 test::PingServicePtr service;
106 PingServiceImpl impl;
107 Binding<test::PingService> binding(&impl, MakeRequest(&service));
108 PingPongTest test(std::move(service));
109
110 {
111 const unsigned int kIterations = 100000;
112 const MojoTimeTicks start_time = MojoGetTimeTicksNow();
113 test.Run(kIterations);
114 const MojoTimeTicks end_time = MojoGetTimeTicksNow();
115 test::LogPerfResult(
116 "InProcessPingPong", "0_Inactive",
117 kIterations / MojoTicksToSeconds(end_time - start_time),
118 "pings/second");
119 }
120
121 {
122 const size_t kNumInactiveServices = 1000;
123 BoundPingService* inactive_services =
124 new BoundPingService[kNumInactiveServices];
125
126 const unsigned int kIterations = 10000;
127 const MojoTimeTicks start_time = MojoGetTimeTicksNow();
128 test.Run(kIterations);
129 const MojoTimeTicks end_time = MojoGetTimeTicksNow();
130 test::LogPerfResult(
131 "InProcessPingPong", "1000_Inactive",
132 kIterations / MojoTicksToSeconds(end_time - start_time),
133 "pings/second");
134
135 delete[] inactive_services;
136 }
137 }
138
139 class PingPongPaddle : public MessageReceiverWithResponderStatus {
140 public:
PingPongPaddle(MessageReceiver * sender)141 PingPongPaddle(MessageReceiver* sender) : sender_(sender) {}
142
set_sender(MessageReceiver * sender)143 void set_sender(MessageReceiver* sender) { sender_ = sender; }
144
Accept(Message * message)145 bool Accept(Message* message) override {
146 uint32_t count = message->header()->name;
147 if (!quit_closure_.is_null()) {
148 count++;
149 if (count >= expected_count_) {
150 end_time_ = base::TimeTicks::Now();
151 quit_closure_.Run();
152 return true;
153 }
154 }
155
156 Message reply(count, 0, 0, 0, nullptr);
157 bool result = sender_->Accept(&reply);
158 DCHECK(result);
159 return true;
160 }
161
AcceptWithResponder(Message * message,std::unique_ptr<MessageReceiverWithStatus> responder)162 bool AcceptWithResponder(
163 Message* message,
164 std::unique_ptr<MessageReceiverWithStatus> responder) override {
165 NOTREACHED();
166 return true;
167 }
168
Serve(uint32_t expected_count)169 base::TimeDelta Serve(uint32_t expected_count) {
170 base::RunLoop run_loop;
171
172 expected_count_ = expected_count;
173 quit_closure_ = run_loop.QuitClosure();
174
175 start_time_ = base::TimeTicks::Now();
176 Message message(0, 0, 0, 0, nullptr);
177 bool result = sender_->Accept(&message);
178 DCHECK(result);
179
180 run_loop.Run();
181
182 return end_time_ - start_time_;
183 }
184
185 private:
186 base::TimeTicks start_time_;
187 base::TimeTicks end_time_;
188 uint32_t expected_count_ = 0;
189 MessageReceiver* sender_;
190 base::Closure quit_closure_;
191 };
192
TEST_F(MojoBindingsPerftest,MultiplexRouterPingPong)193 TEST_F(MojoBindingsPerftest, MultiplexRouterPingPong) {
194 MessagePipe pipe;
195 scoped_refptr<internal::MultiplexRouter> router0(
196 new internal::MultiplexRouter(std::move(pipe.handle0),
197 internal::MultiplexRouter::SINGLE_INTERFACE,
198 true, base::ThreadTaskRunnerHandle::Get()));
199 scoped_refptr<internal::MultiplexRouter> router1(
200 new internal::MultiplexRouter(
201 std::move(pipe.handle1), internal::MultiplexRouter::SINGLE_INTERFACE,
202 false, base::ThreadTaskRunnerHandle::Get()));
203
204 PingPongPaddle paddle0(nullptr);
205 PingPongPaddle paddle1(nullptr);
206
207 InterfaceEndpointClient client0(
208 router0->CreateLocalEndpointHandle(kMasterInterfaceId), &paddle0, nullptr,
209 false, base::ThreadTaskRunnerHandle::Get(), 0u);
210 InterfaceEndpointClient client1(
211 router1->CreateLocalEndpointHandle(kMasterInterfaceId), &paddle1, nullptr,
212 false, base::ThreadTaskRunnerHandle::Get(), 0u);
213
214 paddle0.set_sender(&client0);
215 paddle1.set_sender(&client1);
216
217 static const uint32_t kWarmUpIterations = 1000;
218 static const uint32_t kTestIterations = 1000000;
219
220 paddle0.Serve(kWarmUpIterations);
221
222 base::TimeDelta duration = paddle0.Serve(kTestIterations);
223
224 test::LogPerfResult("MultiplexRouterPingPong", nullptr,
225 kTestIterations / duration.InSecondsF(), "pings/second");
226 }
227
228 class CounterReceiver : public MessageReceiverWithResponderStatus {
229 public:
Accept(Message * message)230 bool Accept(Message* message) override {
231 counter_++;
232 return true;
233 }
234
AcceptWithResponder(Message * message,std::unique_ptr<MessageReceiverWithStatus> responder)235 bool AcceptWithResponder(
236 Message* message,
237 std::unique_ptr<MessageReceiverWithStatus> responder) override {
238 NOTREACHED();
239 return true;
240 }
241
counter() const242 uint32_t counter() const { return counter_; }
243
Reset()244 void Reset() { counter_ = 0; }
245
246 private:
247 uint32_t counter_ = 0;
248 };
249
TEST_F(MojoBindingsPerftest,MultiplexRouterDispatchCost)250 TEST_F(MojoBindingsPerftest, MultiplexRouterDispatchCost) {
251 MessagePipe pipe;
252 scoped_refptr<internal::MultiplexRouter> router(new internal::MultiplexRouter(
253 std::move(pipe.handle0), internal::MultiplexRouter::SINGLE_INTERFACE,
254 true, base::ThreadTaskRunnerHandle::Get()));
255 CounterReceiver receiver;
256 InterfaceEndpointClient client(
257 router->CreateLocalEndpointHandle(kMasterInterfaceId), &receiver, nullptr,
258 false, base::ThreadTaskRunnerHandle::Get(), 0u);
259
260 static const uint32_t kIterations[] = {1000, 3000000};
261
262 for (size_t i = 0; i < 2; ++i) {
263 receiver.Reset();
264 base::TimeTicks start_time = base::TimeTicks::Now();
265 for (size_t j = 0; j < kIterations[i]; ++j) {
266 Message message(0, 0, 8, 0, nullptr);
267 bool result = router->SimulateReceivingMessageForTesting(&message);
268 DCHECK(result);
269 }
270
271 base::TimeTicks end_time = base::TimeTicks::Now();
272 base::TimeDelta duration = end_time - start_time;
273 CHECK_EQ(kIterations[i], receiver.counter());
274
275 if (i == 1) {
276 test::LogPerfResult("MultiplexRouterDispatchCost", nullptr,
277 kIterations[i] / duration.InSecondsF(),
278 "times/second");
279 }
280 }
281 }
282
283 } // namespace
284 } // namespace mojo
285