Home | History | Annotate | Download | only in tests
      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:
     28   MessagePipeWriterThread(MojoHandle handle, uint32_t num_bytes)
     29       : SimpleThread("MessagePipeWriterThread"),
     30         handle_(handle),
     31         num_bytes_(num_bytes),
     32         num_writes_(0) {}
     33   ~MessagePipeWriterThread() override {}
     34 
     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.
     57   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:
     69   explicit MessagePipeReaderThread(MojoHandle handle)
     70       : SimpleThread("MessagePipeReaderThread"),
     71         handle_(handle),
     72         num_reads_(0) {}
     73   ~MessagePipeReaderThread() override {}
     74 
     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.
    105   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:
    117   CorePerftest() : buffer_(nullptr), num_bytes_(0) {}
    118   ~CorePerftest() override {}
    119 
    120   static void NoOp(void* /*closure*/) {}
    121 
    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 
    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 
    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)
    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)
    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.
    256 TEST_F(CorePerftest, NoOp) {
    257   mojo::test::IterateAndReportPerf("Iterate_NoOp", nullptr, &CorePerftest::NoOp,
    258                                    this);
    259 }
    260 
    261 TEST_F(CorePerftest, MessagePipe_CreateAndClose) {
    262   mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose", nullptr,
    263                                    &CorePerftest::MessagePipe_CreateAndClose,
    264                                    this);
    265 }
    266 
    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 
    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)
    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