• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 <stdint.h>
7 
8 #include <memory>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/test/perf_time_logger.h"
17 #include "base/threading/thread.h"
18 #include "mojo/core/embedder/embedder.h"
19 #include "mojo/core/handle_signals_state.h"
20 #include "mojo/core/test/mojo_test_base.h"
21 #include "mojo/core/test/test_utils.h"
22 #include "mojo/core/test_utils.h"
23 #include "mojo/public/c/system/functions.h"
24 #include "mojo/public/cpp/system/message_pipe.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 
27 namespace mojo {
28 namespace core {
29 namespace {
30 
31 class MessagePipePerfTest : public test::MojoTestBase {
32  public:
MessagePipePerfTest()33   MessagePipePerfTest() : message_count_(0), message_size_(0) {}
34 
SetUpMeasurement(int message_count,size_t message_size)35   void SetUpMeasurement(int message_count, size_t message_size) {
36     message_count_ = message_count;
37     message_size_ = message_size;
38     payload_ = std::string(message_size, '*');
39     read_buffer_.resize(message_size * 2);
40   }
41 
42  protected:
WriteWaitThenRead(MojoHandle mp)43   void WriteWaitThenRead(MojoHandle mp) {
44     CHECK_EQ(
45         WriteMessageRaw(MessagePipeHandle(mp), payload_.data(), payload_.size(),
46                         nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE),
47         MOJO_RESULT_OK);
48     HandleSignalsState hss;
49     CHECK_EQ(WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss),
50              MOJO_RESULT_OK);
51     CHECK_EQ(ReadMessageRaw(MessagePipeHandle(mp), &read_buffer_, nullptr,
52                             MOJO_READ_MESSAGE_FLAG_NONE),
53              MOJO_RESULT_OK);
54     CHECK_EQ(read_buffer_.size(), payload_.size());
55   }
56 
SendQuitMessage(MojoHandle mp)57   void SendQuitMessage(MojoHandle mp) {
58     CHECK_EQ(WriteMessageRaw(MessagePipeHandle(mp), "", 0, nullptr, 0,
59                              MOJO_WRITE_MESSAGE_FLAG_NONE),
60              MOJO_RESULT_OK);
61   }
62 
Measure(MojoHandle mp)63   void Measure(MojoHandle mp) {
64     // Have one ping-pong to ensure channel being established.
65     WriteWaitThenRead(mp);
66 
67     std::string test_name =
68         base::StringPrintf("IPC_Perf_%dx_%u", message_count_,
69                            static_cast<unsigned>(message_size_));
70     base::PerfTimeLogger logger(test_name.c_str());
71 
72     for (int i = 0; i < message_count_; ++i)
73       WriteWaitThenRead(mp);
74 
75     logger.Done();
76   }
77 
78  protected:
RunPingPongServer(MojoHandle mp)79   void RunPingPongServer(MojoHandle mp) {
80     // This values are set to align with one at ipc_pertests.cc for comparison.
81     const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
82     const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
83 
84     for (size_t i = 0; i < 5; i++) {
85       SetUpMeasurement(kMessageCount[i], kMsgSize[i]);
86       Measure(mp);
87     }
88 
89     SendQuitMessage(mp);
90   }
91 
RunPingPongClient(MojoHandle mp)92   static int RunPingPongClient(MojoHandle mp) {
93     std::vector<uint8_t> buffer;
94     int rv = 0;
95     while (true) {
96       // Wait for our end of the message pipe to be readable.
97       HandleSignalsState hss;
98       MojoResult result = WaitForSignals(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss);
99       if (result != MOJO_RESULT_OK) {
100         rv = result;
101         break;
102       }
103 
104       CHECK_EQ(ReadMessageRaw(MessagePipeHandle(mp), &buffer, nullptr,
105                               MOJO_READ_MESSAGE_FLAG_NONE),
106                MOJO_RESULT_OK);
107 
108       // Empty message indicates quit.
109       if (buffer.empty())
110         break;
111 
112       CHECK_EQ(
113           WriteMessageRaw(MessagePipeHandle(mp), buffer.data(), buffer.size(),
114                           nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE),
115           MOJO_RESULT_OK);
116     }
117 
118     return rv;
119   }
120 
121  private:
122   int message_count_;
123   size_t message_size_;
124   std::string payload_;
125   std::vector<uint8_t> read_buffer_;
126   std::unique_ptr<base::PerfTimeLogger> perf_logger_;
127 
128   DISALLOW_COPY_AND_ASSIGN(MessagePipePerfTest);
129 };
130 
TEST_F(MessagePipePerfTest,PingPong)131 TEST_F(MessagePipePerfTest, PingPong) {
132   MojoHandle server_handle, client_handle;
133   CreateMessagePipe(&server_handle, &client_handle);
134 
135   base::Thread client_thread("PingPongClient");
136   client_thread.Start();
137   client_thread.task_runner()->PostTask(
138       FROM_HERE,
139       base::Bind(base::IgnoreResult(&RunPingPongClient), client_handle));
140 
141   RunPingPongServer(server_handle);
142 }
143 
144 // For each message received, sends a reply message with the same contents
145 // repeated twice, until the other end is closed or it receives "quitquitquit"
146 // (which it doesn't reply to). It'll return the number of messages received,
147 // not including any "quitquitquit" message, modulo 100.
DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient,MessagePipePerfTest,h)148 DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient, MessagePipePerfTest, h) {
149   return RunPingPongClient(h);
150 }
151 
152 // Repeatedly sends messages as previous one got replied by the child.
153 // Waits for the child to close its end before quitting once specified
154 // number of messages has been sent.
TEST_F(MessagePipePerfTest,MultiprocessPingPong)155 TEST_F(MessagePipePerfTest, MultiprocessPingPong) {
156   RunTestClient("PingPongClient", [&](MojoHandle h) { RunPingPongServer(h); });
157 }
158 
159 }  // namespace
160 }  // namespace core
161 }  // namespace mojo
162