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/cpp/test_support/test_support.h"
16 #include "mojo/public/cpp/test_support/test_utils.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 // TODO(vtl): (here and below) crbug.com/342893
22 #include "mojo/public/cpp/utility/thread.h"
23 #endif // !defined(WIN32)
28 class MessagePipeWriterThread
: public mojo::Thread
{
30 MessagePipeWriterThread(MojoHandle handle
, uint32_t num_bytes
)
31 : handle_(handle
), num_bytes_(num_bytes
), num_writes_(0) {}
32 ~MessagePipeWriterThread() override
{}
36 assert(num_bytes_
<= sizeof(buffer
));
38 // TODO(vtl): Should I throttle somehow?
40 MojoResult result
= MojoWriteMessage(
41 handle_
, buffer
, num_bytes_
, NULL
, 0, MOJO_WRITE_MESSAGE_FLAG_NONE
);
42 if (result
== MOJO_RESULT_OK
) {
47 // We failed to write.
48 // Either |handle_| or its peer was closed.
49 assert(result
== MOJO_RESULT_INVALID_ARGUMENT
||
50 result
== MOJO_RESULT_FAILED_PRECONDITION
);
55 // Use only after joining the thread.
56 int64_t num_writes() const { return num_writes_
; }
59 const MojoHandle handle_
;
60 const uint32_t num_bytes_
;
63 MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeWriterThread
);
66 class MessagePipeReaderThread
: public mojo::Thread
{
68 explicit MessagePipeReaderThread(MojoHandle handle
)
69 : handle_(handle
), num_reads_(0) {}
70 ~MessagePipeReaderThread() override
{}
76 uint32_t num_bytes
= static_cast<uint32_t>(sizeof(buffer
));
77 MojoResult result
= MojoReadMessage(
78 handle_
, buffer
, &num_bytes
, NULL
, NULL
, MOJO_READ_MESSAGE_FLAG_NONE
);
79 if (result
== MOJO_RESULT_OK
) {
84 if (result
== MOJO_RESULT_SHOULD_WAIT
) {
86 handle_
, MOJO_HANDLE_SIGNAL_READABLE
, MOJO_DEADLINE_INDEFINITE
);
87 if (result
== MOJO_RESULT_OK
) {
88 // Go to the top of the loop to read again.
93 // We failed to read and possibly failed to wait.
94 // Either |handle_| or its peer was closed.
95 assert(result
== MOJO_RESULT_INVALID_ARGUMENT
||
96 result
== MOJO_RESULT_FAILED_PRECONDITION
);
101 // Use only after joining the thread.
102 int64_t num_reads() const { return num_reads_
; }
105 const MojoHandle handle_
;
108 MOJO_DISALLOW_COPY_AND_ASSIGN(MessagePipeReaderThread
);
110 #endif // !defined(WIN32)
112 class CorePerftest
: public testing::Test
{
114 CorePerftest() : buffer_(NULL
), num_bytes_(0) {}
115 ~CorePerftest() override
{}
117 static void NoOp(void* /*closure*/) {}
119 static void MessagePipe_CreateAndClose(void* closure
) {
120 CorePerftest
* self
= static_cast<CorePerftest
*>(closure
);
121 MojoResult result
= MojoCreateMessagePipe(NULL
, &self
->h0_
, &self
->h1_
);
122 MOJO_ALLOW_UNUSED_LOCAL(result
);
123 assert(result
== MOJO_RESULT_OK
);
124 result
= MojoClose(self
->h0_
);
125 assert(result
== MOJO_RESULT_OK
);
126 result
= MojoClose(self
->h1_
);
127 assert(result
== MOJO_RESULT_OK
);
130 static void MessagePipe_WriteAndRead(void* closure
) {
131 CorePerftest
* self
= static_cast<CorePerftest
*>(closure
);
132 MojoResult result
= MojoWriteMessage(self
->h0_
, self
->buffer_
,
133 self
->num_bytes_
, NULL
, 0,
134 MOJO_WRITE_MESSAGE_FLAG_NONE
);
135 MOJO_ALLOW_UNUSED_LOCAL(result
);
136 assert(result
== MOJO_RESULT_OK
);
137 uint32_t read_bytes
= self
->num_bytes_
;
138 result
= MojoReadMessage(self
->h1_
, self
->buffer_
, &read_bytes
, NULL
, NULL
,
139 MOJO_READ_MESSAGE_FLAG_NONE
);
140 assert(result
== MOJO_RESULT_OK
);
143 static void MessagePipe_EmptyRead(void* closure
) {
144 CorePerftest
* self
= static_cast<CorePerftest
*>(closure
);
145 MojoResult result
= MojoReadMessage(self
->h0_
, NULL
, NULL
, NULL
, NULL
,
146 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD
);
147 MOJO_ALLOW_UNUSED_LOCAL(result
);
148 assert(result
== MOJO_RESULT_SHOULD_WAIT
);
153 void DoMessagePipeThreadedTest(unsigned num_writers
,
154 unsigned num_readers
,
155 uint32_t num_bytes
) {
156 static const int64_t kPerftestTimeMicroseconds
= 3 * 1000000;
158 assert(num_writers
> 0);
159 assert(num_readers
> 0);
161 MojoResult result
= MojoCreateMessagePipe(NULL
, &h0_
, &h1_
);
162 MOJO_ALLOW_UNUSED_LOCAL(result
);
163 assert(result
== MOJO_RESULT_OK
);
165 std::vector
<MessagePipeWriterThread
*> writers
;
166 for (unsigned i
= 0; i
< num_writers
; i
++)
167 writers
.push_back(new MessagePipeWriterThread(h0_
, num_bytes
));
169 std::vector
<MessagePipeReaderThread
*> readers
;
170 for (unsigned i
= 0; i
< num_readers
; i
++)
171 readers
.push_back(new MessagePipeReaderThread(h1_
));
173 // Start time here, just before we fire off the threads.
174 const MojoTimeTicks start_time
= MojoGetTimeTicksNow();
176 // Interleave the starts.
177 for (unsigned i
= 0; i
< num_writers
|| i
< num_readers
; i
++) {
184 Sleep(kPerftestTimeMicroseconds
);
186 // Close both handles to make writers and readers stop immediately.
187 result
= MojoClose(h0_
);
188 assert(result
== MOJO_RESULT_OK
);
189 result
= MojoClose(h1_
);
190 assert(result
== MOJO_RESULT_OK
);
193 for (unsigned i
= 0; i
< num_writers
; i
++)
195 for (unsigned i
= 0; i
< num_readers
; i
++)
199 MojoTimeTicks end_time
= MojoGetTimeTicksNow();
201 // Add up write and read counts, and destroy the threads.
202 int64_t num_writes
= 0;
203 for (unsigned i
= 0; i
< num_writers
; i
++) {
204 num_writes
+= writers
[i
]->num_writes();
208 int64_t num_reads
= 0;
209 for (unsigned i
= 0; i
< num_readers
; i
++) {
210 num_reads
+= readers
[i
]->num_reads();
217 "MessagePipe_Threaded_Writes_%uw_%ur_%ubytes",
220 static_cast<unsigned>(num_bytes
));
221 mojo::test::LogPerfResult(
223 1000000.0 * static_cast<double>(num_writes
) / (end_time
- start_time
),
226 "MessagePipe_Threaded_Reads_%uw_%ur_%ubytes",
229 static_cast<unsigned>(num_bytes
));
230 mojo::test::LogPerfResult(
232 1000000.0 * static_cast<double>(num_reads
) / (end_time
- start_time
),
235 #endif // !defined(WIN32)
245 void Sleep(int64_t microseconds
) {
246 struct timespec req
= {
247 static_cast<time_t>(microseconds
/ 1000000), // Seconds.
248 static_cast<long>(microseconds
% 1000000) * 1000L // Nanoseconds.
250 int rv
= nanosleep(&req
, NULL
);
251 MOJO_ALLOW_UNUSED_LOCAL(rv
);
254 #endif // !defined(WIN32)
256 MOJO_DISALLOW_COPY_AND_ASSIGN(CorePerftest
);
259 // A no-op test so we can compare performance.
260 TEST_F(CorePerftest
, NoOp
) {
261 mojo::test::IterateAndReportPerf("NoOp", &CorePerftest::NoOp
, this);
264 TEST_F(CorePerftest
, MessagePipe_CreateAndClose
) {
265 mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose",
266 &CorePerftest::MessagePipe_CreateAndClose
,
270 TEST_F(CorePerftest
, MessagePipe_WriteAndRead
) {
271 MojoResult result
= MojoCreateMessagePipe(NULL
, &h0_
, &h1_
);
272 MOJO_ALLOW_UNUSED_LOCAL(result
);
273 assert(result
== MOJO_RESULT_OK
);
274 char buffer
[10000] = {0};
277 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10bytes",
278 &CorePerftest::MessagePipe_WriteAndRead
,
281 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_100bytes",
282 &CorePerftest::MessagePipe_WriteAndRead
,
285 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_1000bytes",
286 &CorePerftest::MessagePipe_WriteAndRead
,
289 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10000bytes",
290 &CorePerftest::MessagePipe_WriteAndRead
,
292 result
= MojoClose(h0_
);
293 assert(result
== MOJO_RESULT_OK
);
294 result
= MojoClose(h1_
);
295 assert(result
== MOJO_RESULT_OK
);
298 TEST_F(CorePerftest
, MessagePipe_EmptyRead
) {
299 MojoResult result
= MojoCreateMessagePipe(NULL
, &h0_
, &h1_
);
300 MOJO_ALLOW_UNUSED_LOCAL(result
);
301 assert(result
== MOJO_RESULT_OK
);
302 mojo::test::IterateAndReportPerf(
303 "MessagePipe_EmptyRead", &CorePerftest::MessagePipe_EmptyRead
, this);
304 result
= MojoClose(h0_
);
305 assert(result
== MOJO_RESULT_OK
);
306 result
= MojoClose(h1_
);
307 assert(result
== MOJO_RESULT_OK
);
311 TEST_F(CorePerftest
, MessagePipe_Threaded
) {
312 DoMessagePipeThreadedTest(1u, 1u, 100u);
313 DoMessagePipeThreadedTest(2u, 2u, 100u);
314 DoMessagePipeThreadedTest(3u, 3u, 100u);
315 DoMessagePipeThreadedTest(10u, 10u, 100u);
316 DoMessagePipeThreadedTest(10u, 1u, 100u);
317 DoMessagePipeThreadedTest(1u, 10u, 100u);
319 // For comparison of overhead:
320 DoMessagePipeThreadedTest(1u, 1u, 10u);
321 // 100 was done above.
322 DoMessagePipeThreadedTest(1u, 1u, 1000u);
323 DoMessagePipeThreadedTest(1u, 1u, 10000u);
325 DoMessagePipeThreadedTest(3u, 3u, 10u);
326 // 100 was done above.
327 DoMessagePipeThreadedTest(3u, 3u, 1000u);
328 DoMessagePipeThreadedTest(3u, 3u, 10000u);
330 #endif // !defined(WIN32)