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