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 <stdint.h>
6
7 #include <string>
8 #include <utility>
9
10 #include "base/auto_reset.h"
11 #include "base/bind.h"
12 #include "base/macros.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/run_loop.h"
15 #include "base/time/time.h"
16 #include "mojo/message_pump/handle_watcher.h"
17 #include "mojo/message_pump/message_pump_mojo.h"
18 #include "mojo/public/cpp/test_support/test_support.h"
19 #include "mojo/public/cpp/test_support/test_utils.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace mojo {
23 namespace common {
24 namespace test {
25
26 enum MessageLoopConfig {
27 MESSAGE_LOOP_CONFIG_DEFAULT = 0,
28 MESSAGE_LOOP_CONFIG_MOJO = 1
29 };
30
CreateMessageLoop(MessageLoopConfig config)31 std::unique_ptr<base::MessageLoop> CreateMessageLoop(MessageLoopConfig config) {
32 std::unique_ptr<base::MessageLoop> loop;
33 if (config == MESSAGE_LOOP_CONFIG_DEFAULT)
34 loop.reset(new base::MessageLoop());
35 else
36 loop.reset(new base::MessageLoop(MessagePumpMojo::Create()));
37 return loop;
38 }
39
OnWatcherSignaled(const base::Closure & callback,MojoResult)40 void OnWatcherSignaled(const base::Closure& callback, MojoResult /* result */) {
41 callback.Run();
42 }
43
44 class ScopedPerfTimer {
45 public:
ScopedPerfTimer(const std::string & test_name,const std::string & sub_test_name,uint64_t iterations)46 ScopedPerfTimer(const std::string& test_name,
47 const std::string& sub_test_name,
48 uint64_t iterations)
49 : test_name_(test_name),
50 sub_test_name_(sub_test_name),
51 iterations_(iterations),
52 start_time_(base::TimeTicks::Now()) {}
~ScopedPerfTimer()53 ~ScopedPerfTimer() {
54 base::TimeTicks end_time = base::TimeTicks::Now();
55 mojo::test::LogPerfResult(
56 test_name_.c_str(), sub_test_name_.c_str(),
57 iterations_ / (end_time - start_time_).InSecondsF(),
58 "iterations/second");
59 }
60
61 private:
62 const std::string test_name_;
63 const std::string sub_test_name_;
64 const uint64_t iterations_;
65 base::TimeTicks start_time_;
66
67 DISALLOW_COPY_AND_ASSIGN(ScopedPerfTimer);
68 };
69
70 class HandleWatcherPerftest : public testing::TestWithParam<MessageLoopConfig> {
71 public:
HandleWatcherPerftest()72 HandleWatcherPerftest() : message_loop_(CreateMessageLoop(GetParam())) {}
73
74 protected:
GetMessageLoopName() const75 std::string GetMessageLoopName() const {
76 return (GetParam() == MESSAGE_LOOP_CONFIG_DEFAULT) ? "DefaultMessageLoop"
77 : "MojoMessageLoop";
78 }
79
80 private:
81 std::unique_ptr<base::MessageLoop> message_loop_;
82
83 DISALLOW_COPY_AND_ASSIGN(HandleWatcherPerftest);
84 };
85
86 INSTANTIATE_TEST_CASE_P(MultipleMessageLoopConfigs,
87 HandleWatcherPerftest,
88 testing::Values(MESSAGE_LOOP_CONFIG_DEFAULT,
89 MESSAGE_LOOP_CONFIG_MOJO));
90
NeverReached(MojoResult result)91 void NeverReached(MojoResult result) {
92 FAIL() << "Callback should never be invoked " << result;
93 }
94
TEST_P(HandleWatcherPerftest,StartStop)95 TEST_P(HandleWatcherPerftest, StartStop) {
96 const uint64_t kIterations = 100000;
97 MessagePipe pipe;
98 HandleWatcher watcher;
99
100 ScopedPerfTimer timer("StartStop", GetMessageLoopName(), kIterations);
101 for (uint64_t i = 0; i < kIterations; i++) {
102 watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
103 MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
104 watcher.Stop();
105 }
106 }
107
TEST_P(HandleWatcherPerftest,StartAllThenStop_1000Handles)108 TEST_P(HandleWatcherPerftest, StartAllThenStop_1000Handles) {
109 const uint64_t kIterations = 100;
110 const uint64_t kHandles = 1000;
111
112 struct TestData {
113 MessagePipe pipe;
114 HandleWatcher watcher;
115 };
116 ScopedVector<TestData> data_vector;
117 // Create separately from the start/stop loops to avoid affecting the
118 // benchmark.
119 for (uint64_t i = 0; i < kHandles; i++) {
120 std::unique_ptr<TestData> test_data(new TestData);
121 ASSERT_TRUE(test_data->pipe.handle0.is_valid());
122 data_vector.push_back(std::move(test_data));
123 }
124
125 ScopedPerfTimer timer("StartAllThenStop_1000Handles", GetMessageLoopName(),
126 kIterations * kHandles);
127 for (uint64_t iter = 0; iter < kIterations; iter++) {
128 for (uint64_t i = 0; i < kHandles; i++) {
129 TestData* test_data = data_vector[i];
130 test_data->watcher.Start(
131 test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
132 MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
133 }
134 for (uint64_t i = 0; i < kHandles; i++) {
135 TestData* test_data = data_vector[i];
136 test_data->watcher.Stop();
137 }
138 }
139 }
140
TEST_P(HandleWatcherPerftest,StartAndSignal)141 TEST_P(HandleWatcherPerftest, StartAndSignal) {
142 const uint64_t kIterations = 10000;
143 const std::string kMessage = "hello";
144 MessagePipe pipe;
145 HandleWatcher watcher;
146 std::string received_message;
147
148 ScopedPerfTimer timer("StartAndSignal", GetMessageLoopName(), kIterations);
149 for (uint64_t i = 0; i < kIterations; i++) {
150 base::RunLoop run_loop;
151 watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
152 MOJO_DEADLINE_INDEFINITE,
153 base::Bind(&OnWatcherSignaled, run_loop.QuitClosure()));
154 ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage));
155 run_loop.Run();
156 watcher.Stop();
157
158 ASSERT_TRUE(
159 mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message));
160 EXPECT_EQ(kMessage, received_message);
161 received_message.clear();
162 }
163 }
164
TEST_P(HandleWatcherPerftest,StartAndSignal_1000Waiting)165 TEST_P(HandleWatcherPerftest, StartAndSignal_1000Waiting) {
166 const uint64_t kIterations = 10000;
167 const uint64_t kWaitingHandles = 1000;
168 const std::string kMessage = "hello";
169 MessagePipe pipe;
170 HandleWatcher watcher;
171 std::string received_message;
172
173 struct TestData {
174 MessagePipe pipe;
175 HandleWatcher watcher;
176 };
177 ScopedVector<TestData> data_vector;
178 for (uint64_t i = 0; i < kWaitingHandles; i++) {
179 std::unique_ptr<TestData> test_data(new TestData);
180 ASSERT_TRUE(test_data->pipe.handle0.is_valid());
181 test_data->watcher.Start(
182 test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
183 MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
184 data_vector.push_back(std::move(test_data));
185 }
186
187 ScopedPerfTimer timer("StartAndSignal_1000Waiting", GetMessageLoopName(),
188 kIterations);
189 for (uint64_t i = 0; i < kIterations; i++) {
190 base::RunLoop run_loop;
191 watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
192 MOJO_DEADLINE_INDEFINITE,
193 base::Bind(&OnWatcherSignaled, run_loop.QuitClosure()));
194 ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage));
195 run_loop.Run();
196 watcher.Stop();
197
198 ASSERT_TRUE(
199 mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message));
200 EXPECT_EQ(kMessage, received_message);
201 received_message.clear();
202 }
203 }
204
205 } // namespace test
206 } // namespace common
207 } // namespace mojo
208