// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <stdint.h> #include <string> #include <utility> #include "base/auto_reset.h" #include "base/bind.h" #include "base/macros.h" #include "base/memory/scoped_vector.h" #include "base/run_loop.h" #include "base/time/time.h" #include "mojo/message_pump/handle_watcher.h" #include "mojo/message_pump/message_pump_mojo.h" #include "mojo/public/cpp/test_support/test_support.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { namespace common { namespace test { enum MessageLoopConfig { MESSAGE_LOOP_CONFIG_DEFAULT = 0, MESSAGE_LOOP_CONFIG_MOJO = 1 }; std::unique_ptr<base::MessageLoop> CreateMessageLoop(MessageLoopConfig config) { std::unique_ptr<base::MessageLoop> loop; if (config == MESSAGE_LOOP_CONFIG_DEFAULT) loop.reset(new base::MessageLoop()); else loop.reset(new base::MessageLoop(MessagePumpMojo::Create())); return loop; } void OnWatcherSignaled(const base::Closure& callback, MojoResult /* result */) { callback.Run(); } class ScopedPerfTimer { public: ScopedPerfTimer(const std::string& test_name, const std::string& sub_test_name, uint64_t iterations) : test_name_(test_name), sub_test_name_(sub_test_name), iterations_(iterations), start_time_(base::TimeTicks::Now()) {} ~ScopedPerfTimer() { base::TimeTicks end_time = base::TimeTicks::Now(); mojo::test::LogPerfResult( test_name_.c_str(), sub_test_name_.c_str(), iterations_ / (end_time - start_time_).InSecondsF(), "iterations/second"); } private: const std::string test_name_; const std::string sub_test_name_; const uint64_t iterations_; base::TimeTicks start_time_; DISALLOW_COPY_AND_ASSIGN(ScopedPerfTimer); }; class HandleWatcherPerftest : public testing::TestWithParam<MessageLoopConfig> { public: HandleWatcherPerftest() : message_loop_(CreateMessageLoop(GetParam())) {} protected: std::string GetMessageLoopName() const { return (GetParam() == MESSAGE_LOOP_CONFIG_DEFAULT) ? "DefaultMessageLoop" : "MojoMessageLoop"; } private: std::unique_ptr<base::MessageLoop> message_loop_; DISALLOW_COPY_AND_ASSIGN(HandleWatcherPerftest); }; INSTANTIATE_TEST_CASE_P(MultipleMessageLoopConfigs, HandleWatcherPerftest, testing::Values(MESSAGE_LOOP_CONFIG_DEFAULT, MESSAGE_LOOP_CONFIG_MOJO)); void NeverReached(MojoResult result) { FAIL() << "Callback should never be invoked " << result; } TEST_P(HandleWatcherPerftest, StartStop) { const uint64_t kIterations = 100000; MessagePipe pipe; HandleWatcher watcher; ScopedPerfTimer timer("StartStop", GetMessageLoopName(), kIterations); for (uint64_t i = 0; i < kIterations; i++) { watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached)); watcher.Stop(); } } TEST_P(HandleWatcherPerftest, StartAllThenStop_1000Handles) { const uint64_t kIterations = 100; const uint64_t kHandles = 1000; struct TestData { MessagePipe pipe; HandleWatcher watcher; }; ScopedVector<TestData> data_vector; // Create separately from the start/stop loops to avoid affecting the // benchmark. for (uint64_t i = 0; i < kHandles; i++) { std::unique_ptr<TestData> test_data(new TestData); ASSERT_TRUE(test_data->pipe.handle0.is_valid()); data_vector.push_back(std::move(test_data)); } ScopedPerfTimer timer("StartAllThenStop_1000Handles", GetMessageLoopName(), kIterations * kHandles); for (uint64_t iter = 0; iter < kIterations; iter++) { for (uint64_t i = 0; i < kHandles; i++) { TestData* test_data = data_vector[i]; test_data->watcher.Start( test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached)); } for (uint64_t i = 0; i < kHandles; i++) { TestData* test_data = data_vector[i]; test_data->watcher.Stop(); } } } TEST_P(HandleWatcherPerftest, StartAndSignal) { const uint64_t kIterations = 10000; const std::string kMessage = "hello"; MessagePipe pipe; HandleWatcher watcher; std::string received_message; ScopedPerfTimer timer("StartAndSignal", GetMessageLoopName(), kIterations); for (uint64_t i = 0; i < kIterations; i++) { base::RunLoop run_loop; watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, base::Bind(&OnWatcherSignaled, run_loop.QuitClosure())); ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage)); run_loop.Run(); watcher.Stop(); ASSERT_TRUE( mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message)); EXPECT_EQ(kMessage, received_message); received_message.clear(); } } TEST_P(HandleWatcherPerftest, StartAndSignal_1000Waiting) { const uint64_t kIterations = 10000; const uint64_t kWaitingHandles = 1000; const std::string kMessage = "hello"; MessagePipe pipe; HandleWatcher watcher; std::string received_message; struct TestData { MessagePipe pipe; HandleWatcher watcher; }; ScopedVector<TestData> data_vector; for (uint64_t i = 0; i < kWaitingHandles; i++) { std::unique_ptr<TestData> test_data(new TestData); ASSERT_TRUE(test_data->pipe.handle0.is_valid()); test_data->watcher.Start( test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached)); data_vector.push_back(std::move(test_data)); } ScopedPerfTimer timer("StartAndSignal_1000Waiting", GetMessageLoopName(), kIterations); for (uint64_t i = 0; i < kIterations; i++) { base::RunLoop run_loop; watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE, base::Bind(&OnWatcherSignaled, run_loop.QuitClosure())); ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage)); run_loop.Run(); watcher.Stop(); ASSERT_TRUE( mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message)); EXPECT_EQ(kMessage, received_message); received_message.clear(); } } } // namespace test } // namespace common } // namespace mojo