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 virtual ~MessagePipeWriterThread() {}
34 virtual void Run() MOJO_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 virtual ~MessagePipeReaderThread() {}
72 virtual void Run() MOJO_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 virtual ~CorePerftest() {}
117 static void NoOp(void* /*closure*/) {}
119 static void MessagePipe_CreateAndClose(void* closure) {
120 CorePerftest* self = static_cast<CorePerftest*>(closure);
121 MojoResult result MOJO_ALLOW_UNUSED;
122 result = MojoCreateMessagePipe(NULL, &self->h0_, &self->h1_);
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 MOJO_ALLOW_UNUSED;
133 result = MojoWriteMessage(self->h0_,
138 MOJO_WRITE_MESSAGE_FLAG_NONE);
139 assert(result == MOJO_RESULT_OK);
140 uint32_t read_bytes = self->num_bytes_;
141 result = MojoReadMessage(self->h1_,
146 MOJO_READ_MESSAGE_FLAG_NONE);
147 assert(result == MOJO_RESULT_OK);
150 static void MessagePipe_EmptyRead(void* closure) {
151 CorePerftest* self = static_cast<CorePerftest*>(closure);
152 MojoResult result MOJO_ALLOW_UNUSED;
153 result = MojoReadMessage(
154 self->h0_, NULL, NULL, NULL, NULL, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
155 assert(result == MOJO_RESULT_SHOULD_WAIT);
160 void DoMessagePipeThreadedTest(unsigned num_writers,
161 unsigned num_readers,
162 uint32_t num_bytes) {
163 static const int64_t kPerftestTimeMicroseconds = 3 * 1000000;
165 assert(num_writers > 0);
166 assert(num_readers > 0);
168 MojoResult result MOJO_ALLOW_UNUSED;
169 result = MojoCreateMessagePipe(NULL, &h0_, &h1_);
170 assert(result == MOJO_RESULT_OK);
172 std::vector<MessagePipeWriterThread*> writers;
173 for (unsigned i = 0; i < num_writers; i++)
174 writers.push_back(new MessagePipeWriterThread(h0_, num_bytes));
176 std::vector<MessagePipeReaderThread*> readers;
177 for (unsigned i = 0; i < num_readers; i++)
178 readers.push_back(new MessagePipeReaderThread(h1_));
180 // Start time here, just before we fire off the threads.
181 const MojoTimeTicks start_time = MojoGetTimeTicksNow();
183 // Interleave the starts.
184 for (unsigned i = 0; i < num_writers || i < num_readers; i++) {
191 Sleep(kPerftestTimeMicroseconds);
193 // Close both handles to make writers and readers stop immediately.
194 result = MojoClose(h0_);
195 assert(result == MOJO_RESULT_OK);
196 result = MojoClose(h1_);
197 assert(result == MOJO_RESULT_OK);
200 for (unsigned i = 0; i < num_writers; i++)
202 for (unsigned i = 0; i < num_readers; i++)
206 MojoTimeTicks end_time = MojoGetTimeTicksNow();
208 // Add up write and read counts, and destroy the threads.
209 int64_t num_writes = 0;
210 for (unsigned i = 0; i < num_writers; i++) {
211 num_writes += writers[i]->num_writes();
215 int64_t num_reads = 0;
216 for (unsigned i = 0; i < num_readers; i++) {
217 num_reads += readers[i]->num_reads();
224 "MessagePipe_Threaded_Writes_%uw_%ur_%ubytes",
227 static_cast<unsigned>(num_bytes));
228 mojo::test::LogPerfResult(
230 1000000.0 * static_cast<double>(num_writes) / (end_time - start_time),
233 "MessagePipe_Threaded_Reads_%uw_%ur_%ubytes",
236 static_cast<unsigned>(num_bytes));
237 mojo::test::LogPerfResult(
239 1000000.0 * static_cast<double>(num_reads) / (end_time - start_time),
242 #endif // !defined(WIN32)
252 void Sleep(int64_t microseconds) {
253 struct timespec req = {
254 static_cast<time_t>(microseconds / 1000000), // Seconds.
255 static_cast<long>(microseconds % 1000000) * 1000L // Nanoseconds.
257 int rv MOJO_ALLOW_UNUSED;
258 rv = nanosleep(&req, NULL);
261 #endif // !defined(WIN32)
263 MOJO_DISALLOW_COPY_AND_ASSIGN(CorePerftest);
266 // A no-op test so we can compare performance.
267 TEST_F(CorePerftest, NoOp) {
268 mojo::test::IterateAndReportPerf("NoOp", &CorePerftest::NoOp, this);
271 TEST_F(CorePerftest, MessagePipe_CreateAndClose) {
272 mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose",
273 &CorePerftest::MessagePipe_CreateAndClose,
277 TEST_F(CorePerftest, MessagePipe_WriteAndRead) {
278 MojoResult result MOJO_ALLOW_UNUSED;
279 result = MojoCreateMessagePipe(NULL, &h0_, &h1_);
280 assert(result == MOJO_RESULT_OK);
281 char buffer[10000] = {0};
284 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10bytes",
285 &CorePerftest::MessagePipe_WriteAndRead,
288 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_100bytes",
289 &CorePerftest::MessagePipe_WriteAndRead,
292 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_1000bytes",
293 &CorePerftest::MessagePipe_WriteAndRead,
296 mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead_10000bytes",
297 &CorePerftest::MessagePipe_WriteAndRead,
299 result = MojoClose(h0_);
300 assert(result == MOJO_RESULT_OK);
301 result = MojoClose(h1_);
302 assert(result == MOJO_RESULT_OK);
305 TEST_F(CorePerftest, MessagePipe_EmptyRead) {
306 MojoResult result MOJO_ALLOW_UNUSED;
307 result = MojoCreateMessagePipe(NULL, &h0_, &h1_);
308 assert(result == MOJO_RESULT_OK);
309 mojo::test::IterateAndReportPerf(
310 "MessagePipe_EmptyRead", &CorePerftest::MessagePipe_EmptyRead, this);
311 result = MojoClose(h0_);
312 assert(result == MOJO_RESULT_OK);
313 result = MojoClose(h1_);
314 assert(result == MOJO_RESULT_OK);
318 TEST_F(CorePerftest, MessagePipe_Threaded) {
319 DoMessagePipeThreadedTest(1u, 1u, 100u);
320 DoMessagePipeThreadedTest(2u, 2u, 100u);
321 DoMessagePipeThreadedTest(3u, 3u, 100u);
322 DoMessagePipeThreadedTest(10u, 10u, 100u);
323 DoMessagePipeThreadedTest(10u, 1u, 100u);
324 DoMessagePipeThreadedTest(1u, 10u, 100u);
326 // For comparison of overhead:
327 DoMessagePipeThreadedTest(1u, 1u, 10u);
328 // 100 was done above.
329 DoMessagePipeThreadedTest(1u, 1u, 1000u);
330 DoMessagePipeThreadedTest(1u, 1u, 10000u);
332 DoMessagePipeThreadedTest(3u, 3u, 10u);
333 // 100 was done above.
334 DoMessagePipeThreadedTest(3u, 3u, 1000u);
335 DoMessagePipeThreadedTest(3u, 3u, 10000u);
337 #endif // !defined(WIN32)