• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 <string>
6 #include <utility>
7 
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/test/perf_time_logger.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #include "mojo/edk/test/mojo_test_base.h"
16 #include "mojo/edk/test/scoped_ipc_support.h"
17 #include "mojo/public/cpp/bindings/strong_binding.h"
18 #include "mojo/public/interfaces/bindings/tests/ping_service.mojom.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 
21 namespace mojo {
22 namespace {
23 
24 class EchoServiceImpl : public test::EchoService {
25  public:
26   EchoServiceImpl(InterfaceRequest<EchoService> request,
27                   const base::Closure& quit_closure);
28   ~EchoServiceImpl() override;
29 
30   // |EchoService| methods:
31   void Echo(const std::string& test_data,
32             const EchoCallback& callback) override;
33 
34  private:
35   const StrongBinding<EchoService> binding_;
36   const base::Closure quit_closure_;
37 };
38 
EchoServiceImpl(InterfaceRequest<EchoService> request,const base::Closure & quit_closure)39 EchoServiceImpl::EchoServiceImpl(InterfaceRequest<EchoService> request,
40                                  const base::Closure& quit_closure)
41     : binding_(this, std::move(request)), quit_closure_(quit_closure) {}
42 
~EchoServiceImpl()43 EchoServiceImpl::~EchoServiceImpl() {
44   quit_closure_.Run();
45 }
46 
Echo(const std::string & test_data,const EchoCallback & callback)47 void EchoServiceImpl::Echo(const std::string& test_data,
48                            const EchoCallback& callback) {
49   callback.Run(test_data);
50 }
51 
52 class PingPongTest {
53  public:
54   explicit PingPongTest(test::EchoServicePtr service);
55 
56   void RunTest(int iterations, int batch_size, int message_size);
57 
58  private:
59   void DoPing();
60   void OnPingDone(const std::string& reply);
61 
62   test::EchoServicePtr service_;
63   const base::Callback<void(const std::string&)> ping_done_callback_;
64 
65   int iterations_;
66   int batch_size_;
67   std::string message_;
68 
69   int current_iterations_;
70   int calls_outstanding_;
71 
72   base::Closure quit_closure_;
73 };
74 
PingPongTest(test::EchoServicePtr service)75 PingPongTest::PingPongTest(test::EchoServicePtr service)
76     : service_(std::move(service)),
77       ping_done_callback_(
78           base::Bind(&PingPongTest::OnPingDone, base::Unretained(this))) {}
79 
RunTest(int iterations,int batch_size,int message_size)80 void PingPongTest::RunTest(int iterations, int batch_size, int message_size) {
81   iterations_ = iterations;
82   batch_size_ = batch_size;
83   message_ = std::string(message_size, 'a');
84   current_iterations_ = 0;
85   calls_outstanding_ = 0;
86 
87   base::MessageLoop::current()->SetNestableTasksAllowed(true);
88   base::RunLoop run_loop;
89   quit_closure_ = run_loop.QuitClosure();
90   base::ThreadTaskRunnerHandle::Get()->PostTask(
91       FROM_HERE, base::Bind(&PingPongTest::DoPing, base::Unretained(this)));
92   run_loop.Run();
93 }
94 
DoPing()95 void PingPongTest::DoPing() {
96   DCHECK_EQ(0, calls_outstanding_);
97   current_iterations_++;
98   if (current_iterations_ > iterations_) {
99     quit_closure_.Run();
100     return;
101   }
102 
103   calls_outstanding_ = batch_size_;
104   for (int i = 0; i < batch_size_; i++) {
105     service_->Echo(message_, ping_done_callback_);
106   }
107 }
108 
OnPingDone(const std::string & reply)109 void PingPongTest::OnPingDone(const std::string& reply) {
110   DCHECK_GT(calls_outstanding_, 0);
111   calls_outstanding_--;
112 
113   if (!calls_outstanding_)
114     DoPing();
115 }
116 
117 class MojoE2EPerftest : public edk::test::MojoTestBase {
118  public:
RunTestOnTaskRunner(base::TaskRunner * runner,MojoHandle client_mp,const std::string & test_name)119   void RunTestOnTaskRunner(base::TaskRunner* runner,
120                            MojoHandle client_mp,
121                            const std::string& test_name) {
122     if (runner == base::ThreadTaskRunnerHandle::Get().get()) {
123       RunTests(client_mp, test_name);
124     } else {
125       base::RunLoop run_loop;
126       runner->PostTaskAndReply(
127           FROM_HERE, base::Bind(&MojoE2EPerftest::RunTests,
128                                 base::Unretained(this), client_mp, test_name),
129           run_loop.QuitClosure());
130       run_loop.Run();
131     }
132   }
133 
134  protected:
135   base::MessageLoop message_loop_;
136 
137  private:
RunTests(MojoHandle client_mp,const std::string & test_name)138   void RunTests(MojoHandle client_mp, const std::string& test_name) {
139     const int kMessages = 10000;
140     const int kBatchSizes[] = {1, 10, 100};
141     const int kMessageSizes[] = {8, 64, 512, 4096, 65536};
142 
143     test::EchoServicePtr service;
144     service.Bind(InterfacePtrInfo<test::EchoService>(
145         ScopedMessagePipeHandle(MessagePipeHandle(client_mp)),
146         service.version()));
147     PingPongTest test(std::move(service));
148 
149     for (int batch_size : kBatchSizes) {
150       for (int message_size : kMessageSizes) {
151         int num_messages = kMessages;
152         if (message_size == 65536)
153           num_messages /= 10;
154         std::string sub_test_name = base::StringPrintf(
155             "%s/%dx%d/%dbytes", test_name.c_str(), num_messages / batch_size,
156             batch_size, message_size);
157         base::PerfTimeLogger timer(sub_test_name.c_str());
158         test.RunTest(num_messages / batch_size, batch_size, message_size);
159       }
160     }
161   }
162 };
163 
CreateAndRunService(InterfaceRequest<test::EchoService> request,const base::Closure & cb)164 void CreateAndRunService(InterfaceRequest<test::EchoService> request,
165                          const base::Closure& cb) {
166   new EchoServiceImpl(std::move(request), cb);
167 }
168 
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingService,MojoE2EPerftest,mp)169 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(PingService, MojoE2EPerftest, mp) {
170   MojoHandle service_mp;
171   EXPECT_EQ("hello", ReadMessageWithHandles(mp, &service_mp, 1));
172 
173   InterfaceRequest<test::EchoService> request;
174   request.Bind(ScopedMessagePipeHandle(MessagePipeHandle(service_mp)));
175   base::RunLoop run_loop;
176   edk::test::GetIoTaskRunner()->PostTask(
177       FROM_HERE,
178       base::Bind(&CreateAndRunService, base::Passed(&request),
179                  base::Bind(base::IgnoreResult(&base::TaskRunner::PostTask),
180                             message_loop_.task_runner(), FROM_HERE,
181                             run_loop.QuitClosure())));
182   run_loop.Run();
183 }
184 
TEST_F(MojoE2EPerftest,MultiProcessEchoMainThread)185 TEST_F(MojoE2EPerftest, MultiProcessEchoMainThread) {
186   RUN_CHILD_ON_PIPE(PingService, mp)
187     MojoHandle client_mp, service_mp;
188     CreateMessagePipe(&client_mp, &service_mp);
189     WriteMessageWithHandles(mp, "hello", &service_mp, 1);
190     RunTestOnTaskRunner(message_loop_.task_runner().get(), client_mp,
191                         "MultiProcessEchoMainThread");
192   END_CHILD()
193 }
194 
TEST_F(MojoE2EPerftest,MultiProcessEchoIoThread)195 TEST_F(MojoE2EPerftest, MultiProcessEchoIoThread) {
196   RUN_CHILD_ON_PIPE(PingService, mp)
197     MojoHandle client_mp, service_mp;
198     CreateMessagePipe(&client_mp, &service_mp);
199     WriteMessageWithHandles(mp, "hello", &service_mp, 1);
200     RunTestOnTaskRunner(edk::test::GetIoTaskRunner(), client_mp,
201                         "MultiProcessEchoIoThread");
202   END_CHILD()
203 }
204 
205 }  // namespace
206 }  // namespace mojo
207