1 // Copyright 2013 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.
5 // This tests the performance of the C API.
7 #include "mojo/public/c/system/core.h"
14 #include "mojo/public/cpp/system/macros.h"
15 #include "mojo/public/tests/test_support.h"
16 #include "mojo/public/tests/test_utils.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 // TODO(vtl): (here and below) crbug.com/342893
22 #include "mojo/public/utility/thread.h"
23 #endif // !defined(WIN32)
28 class MessagePipeWriterThread : public mojo::Thread {
30 MessagePipeWriterThread(MojoHandle handle, uint32_t num_bytes)
32 num_bytes_(num_bytes),
34 virtual ~MessagePipeWriterThread() {}
36 virtual void Run() MOJO_OVERRIDE {
38 assert(num_bytes_ <= sizeof(buffer));
40 // TODO(vtl): Should I throttle somehow?
42 MojoResult result = MojoWriteMessage(handle_, buffer, num_bytes_, NULL, 0,
43 MOJO_WRITE_MESSAGE_FLAG_NONE);
44 if (result == MOJO_RESULT_OK) {
49 // We failed to write.
50 // Either |handle_| or its peer was closed.
51 assert(result == MOJO_RESULT_INVALID_ARGUMENT ||
52 result == MOJO_RESULT_FAILED_PRECONDITION);
57 // Use only after joining the thread.
58 int64_t num_writes() const { return num_writes_; }
61 const MojoHandle handle_;
62 const uint32_t num_bytes_;
65 MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeWriterThread);
68 class MessagePipeReaderThread : public mojo::Thread {
70 explicit MessagePipeReaderThread(MojoHandle handle)
74 virtual ~MessagePipeReaderThread() {}
76 virtual void Run() MOJO_OVERRIDE {
80 uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
81 MojoResult result = MojoReadMessage(handle_, buffer, &num_bytes, NULL,
82 NULL, MOJO_READ_MESSAGE_FLAG_NONE);
83 if (result == MOJO_RESULT_OK) {
88 if (result == MOJO_RESULT_SHOULD_WAIT) {
89 result = MojoWait(handle_, MOJO_WAIT_FLAG_READABLE,
90 MOJO_DEADLINE_INDEFINITE);
91 if (result == MOJO_RESULT_OK) {
92 // Go to the top of the loop to read again.
97 // We failed to read and possibly failed to wait.
98 // Either |handle_| or its peer was closed.
99 assert(result == MOJO_RESULT_INVALID_ARGUMENT ||
100 result == MOJO_RESULT_FAILED_PRECONDITION);
105 // Use only after joining the thread.
106 int64_t num_reads() const { return num_reads_; }
109 const MojoHandle handle_;
112 MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeReaderThread);
114 #endif // !defined(WIN32)
116 class CorePerftest : public testing::Test {
118 CorePerftest() : buffer_(NULL), num_bytes_(0) {}
119 virtual ~CorePerftest() {}
121 static void NoOp(void* /*closure*/) {
124 static void MessagePipe_CreateAndClose(void* closure) {
125 CorePerftest* self = static_cast<CorePerftest*>(closure);
126 MojoResult result MOJO_ALLOW_UNUSED;
127 result = MojoCreateMessagePipe(&self->h0_, &self->h1_);
128 assert(result == MOJO_RESULT_OK);
129 result = MojoClose(self->h0_);
130 assert(result == MOJO_RESULT_OK);
131 result = MojoClose(self->h1_);
132 assert(result == MOJO_RESULT_OK);
135 static void MessagePipe_WriteAndRead(void* closure) {
136 CorePerftest* self = static_cast<CorePerftest*>(closure);
137 MojoResult result MOJO_ALLOW_UNUSED;
138 result = MojoWriteMessage(self->h0_,
139 self->buffer_, self->num_bytes_,
141 MOJO_WRITE_MESSAGE_FLAG_NONE);
142 assert(result == MOJO_RESULT_OK);
143 uint32_t read_bytes = self->num_bytes_;
144 result = MojoReadMessage(self->h1_,
145 self->buffer_, &read_bytes,
147 MOJO_READ_MESSAGE_FLAG_NONE);
148 assert(result == MOJO_RESULT_OK);
151 static void MessagePipe_EmptyRead(void* closure) {
152 CorePerftest* self = static_cast<CorePerftest*>(closure);
153 MojoResult result MOJO_ALLOW_UNUSED;
154 result = MojoReadMessage(self->h0_,
157 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
158 assert(result == MOJO_RESULT_SHOULD_WAIT);
163 void DoMessagePipeThreadedTest(unsigned num_writers,
164 unsigned num_readers,
165 uint32_t num_bytes) {
166 static const int64_t kPerftestTimeMicroseconds = 3 * 1000000;
168 assert(num_writers > 0);
169 assert(num_readers > 0);
171 MojoResult result MOJO_ALLOW_UNUSED;
172 result = MojoCreateMessagePipe(&h0_, &h1_);
173 assert(result == MOJO_RESULT_OK);
175 std::vector<MessagePipeWriterThread*> writers;
176 for (unsigned i = 0; i < num_writers; i++)
177 writers.push_back(new MessagePipeWriterThread(h0_, num_bytes));
179 std::vector<MessagePipeReaderThread*> readers;
180 for (unsigned i = 0; i < num_readers; i++)
181 readers.push_back(new MessagePipeReaderThread(h1_));
183 // Start time here, just before we fire off the threads.
184 const MojoTimeTicks start_time = MojoGetTimeTicksNow();
186 // Interleave the starts.
187 for (unsigned i = 0; i < num_writers || i < num_readers; i++) {
194 Sleep(kPerftestTimeMicroseconds);
196 // Close both handles to make writers and readers stop immediately.
197 result = MojoClose(h0_);
198 assert(result == MOJO_RESULT_OK);
199 result = MojoClose(h1_);
200 assert(result == MOJO_RESULT_OK);
203 for (unsigned i = 0; i < num_writers; i++)
205 for (unsigned i = 0; i < num_readers; i++)
209 MojoTimeTicks end_time = MojoGetTimeTicksNow();
211 // Add up write and read counts, and destroy the threads.
212 int64_t num_writes = 0;
213 for (unsigned i = 0; i < num_writers; i++) {
214 num_writes += writers[i]->num_writes();
218 int64_t num_reads = 0;
219 for (unsigned i = 0; i < num_readers; i++) {
220 num_reads += readers[i]->num_reads();
226 sprintf(test_name, "MessagePipe_Threaded_Writes_%uw_%ur_%ubytes",
227 num_writers, num_readers, static_cast<unsigned>(num_bytes));
228 mojo::test::LogPerfResult(test_name,
229 1000000.0 * static_cast<double>(num_writes) /
230 (end_time - start_time),
232 sprintf(test_name, "MessagePipe_Threaded_Reads_%uw_%ur_%ubytes",
233 num_writers, num_readers, static_cast<unsigned>(num_bytes));
234 mojo::test::LogPerfResult(test_name,
235 1000000.0 * static_cast<double>(num_reads) /
236 (end_time - start_time),
239 #endif // !defined(WIN32)
249 void Sleep(int64_t microseconds) {
250 struct timespec req = {
251 static_cast<time_t>(microseconds / 1000000), // Seconds.
252 static_cast<long>(microseconds % 1000000) * 1000L // Nanoseconds.
254 int rv MOJO_ALLOW_UNUSED;
255 rv = nanosleep(&req, NULL);
258 #endif // !defined(WIN32)
260 MOJO_DISALLOW_COPY_AND_ASSIGN(CorePerftest);
263 // A no-op test so we can compare performance.
264 TEST_F(CorePerftest, NoOp) {
265 mojo::test::IterateAndReportPerf("NoOp", &CorePerftest::NoOp, this);
268 TEST_F(CorePerftest, MessagePipe_CreateAndClose) {
269 mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose",
270 &CorePerftest::MessagePipe_CreateAndClose,
274 TEST_F(CorePerftest, MessagePipe_WriteAndRead) {
275 MojoResult result MOJO_ALLOW_UNUSED;
276 result = MojoCreateMessagePipe(&h0_, &h1_);
277 assert(result == MOJO_RESULT_OK);
278 char buffer[10000] = { 0 };
281 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10bytes",
282 &CorePerftest::MessagePipe_WriteAndRead,
285 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_100bytes",
286 &CorePerftest::MessagePipe_WriteAndRead,
289 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_1000bytes",
290 &CorePerftest::MessagePipe_WriteAndRead,
293 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10000bytes",
294 &CorePerftest::MessagePipe_WriteAndRead,
296 result = MojoClose(h0_);
297 assert(result == MOJO_RESULT_OK);
298 result = MojoClose(h1_);
299 assert(result == MOJO_RESULT_OK);
302 TEST_F(CorePerftest, MessagePipe_EmptyRead) {
303 MojoResult result MOJO_ALLOW_UNUSED;
304 result = MojoCreateMessagePipe(&h0_, &h1_);
305 assert(result == MOJO_RESULT_OK);
306 mojo::test::IterateAndReportPerf("MessagePipe_EmptyRead",
307 &CorePerftest::MessagePipe_EmptyRead,
309 result = MojoClose(h0_);
310 assert(result == MOJO_RESULT_OK);
311 result = MojoClose(h1_);
312 assert(result == MOJO_RESULT_OK);
316 TEST_F(CorePerftest, MessagePipe_Threaded) {
317 DoMessagePipeThreadedTest(1u, 1u, 100u);
318 DoMessagePipeThreadedTest(2u, 2u, 100u);
319 DoMessagePipeThreadedTest(3u, 3u, 100u);
320 DoMessagePipeThreadedTest(10u, 10u, 100u);
321 DoMessagePipeThreadedTest(10u, 1u, 100u);
322 DoMessagePipeThreadedTest(1u, 10u, 100u);
324 // For comparison of overhead:
325 DoMessagePipeThreadedTest(1u, 1u, 10u);
326 // 100 was done above.
327 DoMessagePipeThreadedTest(1u, 1u, 1000u);
328 DoMessagePipeThreadedTest(1u, 1u, 10000u);
330 DoMessagePipeThreadedTest(3u, 3u, 10u);
331 // 100 was done above.
332 DoMessagePipeThreadedTest(3u, 3u, 1000u);
333 DoMessagePipeThreadedTest(3u, 3u, 10000u);
335 #endif // !defined(WIN32)