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
22namespace mojo {
23namespace common {
24namespace test {
25
26enum MessageLoopConfig {
27  MESSAGE_LOOP_CONFIG_DEFAULT = 0,
28  MESSAGE_LOOP_CONFIG_MOJO = 1
29};
30
31std::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
40void OnWatcherSignaled(const base::Closure& callback, MojoResult /* result */) {
41  callback.Run();
42}
43
44class ScopedPerfTimer {
45 public:
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()) {}
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
70class HandleWatcherPerftest : public testing::TestWithParam<MessageLoopConfig> {
71 public:
72  HandleWatcherPerftest() : message_loop_(CreateMessageLoop(GetParam())) {}
73
74 protected:
75  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
86INSTANTIATE_TEST_CASE_P(MultipleMessageLoopConfigs,
87                        HandleWatcherPerftest,
88                        testing::Values(MESSAGE_LOOP_CONFIG_DEFAULT,
89                                        MESSAGE_LOOP_CONFIG_MOJO));
90
91void NeverReached(MojoResult result) {
92  FAIL() << "Callback should never be invoked " << result;
93}
94
95TEST_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
108TEST_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
141TEST_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
165TEST_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