• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 // This tests the performance of the C API.
6 
7 #include "mojo/public/c/system/core.h"
8 
9 #include <assert.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 
13 #include "base/macros.h"
14 #include "base/threading/simple_thread.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"
18 
19 #if !defined(WIN32)
20 #include <time.h>
21 #endif  // !defined(WIN32)
22 
23 namespace {
24 
25 #if !defined(WIN32)
26 class MessagePipeWriterThread : public base::SimpleThread {
27  public:
MessagePipeWriterThread(MojoHandle handle,uint32_t num_bytes)28   MessagePipeWriterThread(MojoHandle handle, uint32_t num_bytes)
29       : SimpleThread("MessagePipeWriterThread"),
30         handle_(handle),
31         num_bytes_(num_bytes),
32         num_writes_(0) {}
~MessagePipeWriterThread()33   ~MessagePipeWriterThread() override {}
34 
Run()35   void Run() override {
36     char buffer[10000];
37     assert(num_bytes_ <= sizeof(buffer));
38 
39     // TODO(vtl): Should I throttle somehow?
40     for (;;) {
41       MojoResult result = MojoWriteMessage(handle_, buffer, num_bytes_, nullptr,
42                                            0, MOJO_WRITE_MESSAGE_FLAG_NONE);
43       if (result == MOJO_RESULT_OK) {
44         num_writes_++;
45         continue;
46       }
47 
48       // We failed to write.
49       // Either |handle_| or its peer was closed.
50       assert(result == MOJO_RESULT_INVALID_ARGUMENT ||
51              result == MOJO_RESULT_FAILED_PRECONDITION);
52       break;
53     }
54   }
55 
56   // Use only after joining the thread.
num_writes() const57   int64_t num_writes() const { return num_writes_; }
58 
59  private:
60   const MojoHandle handle_;
61   const uint32_t num_bytes_;
62   int64_t num_writes_;
63 
64   DISALLOW_COPY_AND_ASSIGN(MessagePipeWriterThread);
65 };
66 
67 class MessagePipeReaderThread : public base::SimpleThread {
68  public:
MessagePipeReaderThread(MojoHandle handle)69   explicit MessagePipeReaderThread(MojoHandle handle)
70       : SimpleThread("MessagePipeReaderThread"),
71         handle_(handle),
72         num_reads_(0) {}
~MessagePipeReaderThread()73   ~MessagePipeReaderThread() override {}
74 
Run()75   void Run() override {
76     char buffer[10000];
77 
78     for (;;) {
79       uint32_t num_bytes = static_cast<uint32_t>(sizeof(buffer));
80       MojoResult result = MojoReadMessage(handle_, buffer, &num_bytes, nullptr,
81                                           nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
82       if (result == MOJO_RESULT_OK) {
83         num_reads_++;
84         continue;
85       }
86 
87       if (result == MOJO_RESULT_SHOULD_WAIT) {
88         result = MojoWait(handle_, MOJO_HANDLE_SIGNAL_READABLE,
89                           MOJO_DEADLINE_INDEFINITE, nullptr);
90         if (result == MOJO_RESULT_OK) {
91           // Go to the top of the loop to read again.
92           continue;
93         }
94       }
95 
96       // We failed to read and possibly failed to wait.
97       // Either |handle_| or its peer was closed.
98       assert(result == MOJO_RESULT_INVALID_ARGUMENT ||
99              result == MOJO_RESULT_FAILED_PRECONDITION);
100       break;
101     }
102   }
103 
104   // Use only after joining the thread.
num_reads() const105   int64_t num_reads() const { return num_reads_; }
106 
107  private:
108   const MojoHandle handle_;
109   int64_t num_reads_;
110 
111   DISALLOW_COPY_AND_ASSIGN(MessagePipeReaderThread);
112 };
113 #endif  // !defined(WIN32)
114 
115 class CorePerftest : public testing::Test {
116  public:
CorePerftest()117   CorePerftest() : buffer_(nullptr), num_bytes_(0) {}
~CorePerftest()118   ~CorePerftest() override {}
119 
NoOp(void *)120   static void NoOp(void* /*closure*/) {}
121 
MessagePipe_CreateAndClose(void * closure)122   static void MessagePipe_CreateAndClose(void* closure) {
123     CorePerftest* self = static_cast<CorePerftest*>(closure);
124     MojoResult result = MojoCreateMessagePipe(nullptr, &self->h0_, &self->h1_);
125     ALLOW_UNUSED_LOCAL(result);
126     assert(result == MOJO_RESULT_OK);
127     result = MojoClose(self->h0_);
128     assert(result == MOJO_RESULT_OK);
129     result = MojoClose(self->h1_);
130     assert(result == MOJO_RESULT_OK);
131   }
132 
MessagePipe_WriteAndRead(void * closure)133   static void MessagePipe_WriteAndRead(void* closure) {
134     CorePerftest* self = static_cast<CorePerftest*>(closure);
135     MojoResult result =
136         MojoWriteMessage(self->h0_, self->buffer_, self->num_bytes_, nullptr, 0,
137                          MOJO_WRITE_MESSAGE_FLAG_NONE);
138     ALLOW_UNUSED_LOCAL(result);
139     assert(result == MOJO_RESULT_OK);
140     uint32_t read_bytes = self->num_bytes_;
141     result = MojoReadMessage(self->h1_, self->buffer_, &read_bytes, nullptr,
142                              nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
143     assert(result == MOJO_RESULT_OK);
144   }
145 
MessagePipe_EmptyRead(void * closure)146   static void MessagePipe_EmptyRead(void* closure) {
147     CorePerftest* self = static_cast<CorePerftest*>(closure);
148     MojoResult result =
149         MojoReadMessage(self->h0_, nullptr, nullptr, nullptr, nullptr,
150                         MOJO_READ_MESSAGE_FLAG_MAY_DISCARD);
151     ALLOW_UNUSED_LOCAL(result);
152     assert(result == MOJO_RESULT_SHOULD_WAIT);
153   }
154 
155  protected:
156 #if !defined(WIN32)
DoMessagePipeThreadedTest(unsigned num_writers,unsigned num_readers,uint32_t num_bytes)157   void DoMessagePipeThreadedTest(unsigned num_writers,
158                                  unsigned num_readers,
159                                  uint32_t num_bytes) {
160     static const int64_t kPerftestTimeMicroseconds = 3 * 1000000;
161 
162     assert(num_writers > 0);
163     assert(num_readers > 0);
164 
165     MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_);
166     ALLOW_UNUSED_LOCAL(result);
167     assert(result == MOJO_RESULT_OK);
168 
169     std::vector<MessagePipeWriterThread*> writers;
170     for (unsigned i = 0; i < num_writers; i++)
171       writers.push_back(new MessagePipeWriterThread(h0_, num_bytes));
172 
173     std::vector<MessagePipeReaderThread*> readers;
174     for (unsigned i = 0; i < num_readers; i++)
175       readers.push_back(new MessagePipeReaderThread(h1_));
176 
177     // Start time here, just before we fire off the threads.
178     const MojoTimeTicks start_time = MojoGetTimeTicksNow();
179 
180     // Interleave the starts.
181     for (unsigned i = 0; i < num_writers || i < num_readers; i++) {
182       if (i < num_writers)
183         writers[i]->Start();
184       if (i < num_readers)
185         readers[i]->Start();
186     }
187 
188     Sleep(kPerftestTimeMicroseconds);
189 
190     // Close both handles to make writers and readers stop immediately.
191     result = MojoClose(h0_);
192     assert(result == MOJO_RESULT_OK);
193     result = MojoClose(h1_);
194     assert(result == MOJO_RESULT_OK);
195 
196     // Join everything.
197     for (unsigned i = 0; i < num_writers; i++)
198       writers[i]->Join();
199     for (unsigned i = 0; i < num_readers; i++)
200       readers[i]->Join();
201 
202     // Stop time here.
203     MojoTimeTicks end_time = MojoGetTimeTicksNow();
204 
205     // Add up write and read counts, and destroy the threads.
206     int64_t num_writes = 0;
207     for (unsigned i = 0; i < num_writers; i++) {
208       num_writes += writers[i]->num_writes();
209       delete writers[i];
210     }
211     writers.clear();
212     int64_t num_reads = 0;
213     for (unsigned i = 0; i < num_readers; i++) {
214       num_reads += readers[i]->num_reads();
215       delete readers[i];
216     }
217     readers.clear();
218 
219     char sub_test_name[200];
220     sprintf(sub_test_name, "%uw_%ur_%ubytes", num_writers, num_readers,
221             static_cast<unsigned>(num_bytes));
222     mojo::test::LogPerfResult(
223         "MessagePipe_Threaded_Writes", sub_test_name,
224         1000000.0 * static_cast<double>(num_writes) / (end_time - start_time),
225         "writes/second");
226     mojo::test::LogPerfResult(
227         "MessagePipe_Threaded_Reads", sub_test_name,
228         1000000.0 * static_cast<double>(num_reads) / (end_time - start_time),
229         "reads/second");
230   }
231 #endif  // !defined(WIN32)
232 
233   MojoHandle h0_;
234   MojoHandle h1_;
235 
236   void* buffer_;
237   uint32_t num_bytes_;
238 
239  private:
240 #if !defined(WIN32)
Sleep(int64_t microseconds)241   void Sleep(int64_t microseconds) {
242     struct timespec req = {
243         static_cast<time_t>(microseconds / 1000000),       // Seconds.
244         static_cast<long>(microseconds % 1000000) * 1000L  // Nanoseconds.
245     };
246     int rv = nanosleep(&req, nullptr);
247     ALLOW_UNUSED_LOCAL(rv);
248     assert(rv == 0);
249   }
250 #endif  // !defined(WIN32)
251 
252   DISALLOW_COPY_AND_ASSIGN(CorePerftest);
253 };
254 
255 // A no-op test so we can compare performance.
TEST_F(CorePerftest,NoOp)256 TEST_F(CorePerftest, NoOp) {
257   mojo::test::IterateAndReportPerf("Iterate_NoOp", nullptr, &CorePerftest::NoOp,
258                                    this);
259 }
260 
TEST_F(CorePerftest,MessagePipe_CreateAndClose)261 TEST_F(CorePerftest, MessagePipe_CreateAndClose) {
262   mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose", nullptr,
263                                    &CorePerftest::MessagePipe_CreateAndClose,
264                                    this);
265 }
266 
TEST_F(CorePerftest,MessagePipe_WriteAndRead)267 TEST_F(CorePerftest, MessagePipe_WriteAndRead) {
268   MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_);
269   ALLOW_UNUSED_LOCAL(result);
270   assert(result == MOJO_RESULT_OK);
271   char buffer[10000] = {0};
272   buffer_ = buffer;
273   num_bytes_ = 10u;
274   mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead", "10bytes",
275                                    &CorePerftest::MessagePipe_WriteAndRead,
276                                    this);
277   num_bytes_ = 100u;
278   mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead", "100bytes",
279                                    &CorePerftest::MessagePipe_WriteAndRead,
280                                    this);
281   num_bytes_ = 1000u;
282   mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead", "1000bytes",
283                                    &CorePerftest::MessagePipe_WriteAndRead,
284                                    this);
285   num_bytes_ = 10000u;
286   mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead", "10000bytes",
287                                    &CorePerftest::MessagePipe_WriteAndRead,
288                                    this);
289   result = MojoClose(h0_);
290   assert(result == MOJO_RESULT_OK);
291   result = MojoClose(h1_);
292   assert(result == MOJO_RESULT_OK);
293 }
294 
TEST_F(CorePerftest,MessagePipe_EmptyRead)295 TEST_F(CorePerftest, MessagePipe_EmptyRead) {
296   MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_);
297   ALLOW_UNUSED_LOCAL(result);
298   assert(result == MOJO_RESULT_OK);
299   mojo::test::IterateAndReportPerf("MessagePipe_EmptyRead", nullptr,
300                                    &CorePerftest::MessagePipe_EmptyRead, this);
301   result = MojoClose(h0_);
302   assert(result == MOJO_RESULT_OK);
303   result = MojoClose(h1_);
304   assert(result == MOJO_RESULT_OK);
305 }
306 
307 #if !defined(WIN32)
TEST_F(CorePerftest,MessagePipe_Threaded)308 TEST_F(CorePerftest, MessagePipe_Threaded) {
309   DoMessagePipeThreadedTest(1u, 1u, 100u);
310   DoMessagePipeThreadedTest(2u, 2u, 100u);
311   DoMessagePipeThreadedTest(3u, 3u, 100u);
312   DoMessagePipeThreadedTest(10u, 10u, 100u);
313   DoMessagePipeThreadedTest(10u, 1u, 100u);
314   DoMessagePipeThreadedTest(1u, 10u, 100u);
315 
316   // For comparison of overhead:
317   DoMessagePipeThreadedTest(1u, 1u, 10u);
318   // 100 was done above.
319   DoMessagePipeThreadedTest(1u, 1u, 1000u);
320   DoMessagePipeThreadedTest(1u, 1u, 10000u);
321 
322   DoMessagePipeThreadedTest(3u, 3u, 10u);
323   // 100 was done above.
324   DoMessagePipeThreadedTest(3u, 3u, 1000u);
325   DoMessagePipeThreadedTest(3u, 3u, 10000u);
326 }
327 #endif  // !defined(WIN32)
328 
329 }  // namespace
330