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/system/message_pipe.h"
     16 #include "mojo/public/cpp/system/wait.h"
     17 #include "mojo/public/cpp/test_support/test_support.h"
     18 #include "mojo/public/cpp/test_support/test_utils.h"
     19 #include "testing/gtest/include/gtest/gtest.h"
     20 
     21 #if !defined(WIN32)
     22 #include <time.h>
     23 #endif  // !defined(WIN32)
     24 
     25 namespace {
     26 
     27 #if !defined(WIN32)
     28 class MessagePipeWriterThread : public base::SimpleThread {
     29  public:
     30   MessagePipeWriterThread(MojoHandle handle, uint32_t num_bytes)
     31       : SimpleThread("MessagePipeWriterThread"),
     32         handle_(handle),
     33         num_bytes_(num_bytes),
     34         num_writes_(0) {}
     35   ~MessagePipeWriterThread() override {}
     36 
     37   void Run() override {
     38     char buffer[10000];
     39     assert(num_bytes_ <= sizeof(buffer));
     40 
     41     for (;;) {
     42       MojoResult result = mojo::WriteMessageRaw(
     43           mojo::MessagePipeHandle(handle_), buffer, num_bytes_, nullptr, 0,
     44           MOJO_WRITE_MESSAGE_FLAG_NONE);
     45       if (result == MOJO_RESULT_OK) {
     46         num_writes_++;
     47         continue;
     48       }
     49 
     50       // We failed to write.
     51       // Either |handle_| or its peer was closed.
     52       assert(result == MOJO_RESULT_INVALID_ARGUMENT ||
     53              result == MOJO_RESULT_FAILED_PRECONDITION);
     54       break;
     55     }
     56   }
     57 
     58   // Use only after joining the thread.
     59   int64_t num_writes() const { return num_writes_; }
     60 
     61  private:
     62   const MojoHandle handle_;
     63   const uint32_t num_bytes_;
     64   int64_t num_writes_;
     65 
     66   DISALLOW_COPY_AND_ASSIGN(MessagePipeWriterThread);
     67 };
     68 
     69 class MessagePipeReaderThread : public base::SimpleThread {
     70  public:
     71   explicit MessagePipeReaderThread(MojoHandle handle)
     72       : SimpleThread("MessagePipeReaderThread"),
     73         handle_(handle),
     74         num_reads_(0) {}
     75   ~MessagePipeReaderThread() override {}
     76 
     77   void Run() override {
     78     for (;;) {
     79       std::vector<uint8_t> bytes;
     80       MojoResult result =
     81           mojo::ReadMessageRaw(mojo::MessagePipeHandle(handle_), &bytes,
     82                                nullptr, MOJO_READ_MESSAGE_FLAG_NONE);
     83       if (result == MOJO_RESULT_OK) {
     84         num_reads_++;
     85         continue;
     86       }
     87 
     88       if (result == MOJO_RESULT_SHOULD_WAIT) {
     89         result = mojo::Wait(mojo::Handle(handle_), MOJO_HANDLE_SIGNAL_READABLE);
     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() {}
    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 = mojo::WriteMessageRaw(
    136         mojo::MessagePipeHandle(self->h0_), self->buffer_.data(),
    137         self->buffer_.size(), nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE);
    138     ALLOW_UNUSED_LOCAL(result);
    139     assert(result == MOJO_RESULT_OK);
    140     result =
    141         mojo::ReadMessageRaw(mojo::MessagePipeHandle(self->h1_), &self->buffer_,
    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     MojoMessageHandle message;
    149     MojoResult result = MojoReadMessage(self->h0_, nullptr, &message);
    150     ALLOW_UNUSED_LOCAL(result);
    151     assert(result == MOJO_RESULT_SHOULD_WAIT);
    152   }
    153 
    154  protected:
    155 #if !defined(WIN32)
    156   void DoMessagePipeThreadedTest(unsigned num_writers,
    157                                  unsigned num_readers,
    158                                  uint32_t num_bytes) {
    159     static const int64_t kPerftestTimeMicroseconds = 3 * 1000000;
    160 
    161     assert(num_writers > 0);
    162     assert(num_readers > 0);
    163 
    164     MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_);
    165     ALLOW_UNUSED_LOCAL(result);
    166     assert(result == MOJO_RESULT_OK);
    167 
    168     std::vector<MessagePipeWriterThread*> writers;
    169     for (unsigned i = 0; i < num_writers; i++)
    170       writers.push_back(new MessagePipeWriterThread(h0_, num_bytes));
    171 
    172     std::vector<MessagePipeReaderThread*> readers;
    173     for (unsigned i = 0; i < num_readers; i++)
    174       readers.push_back(new MessagePipeReaderThread(h1_));
    175 
    176     // Start time here, just before we fire off the threads.
    177     const MojoTimeTicks start_time = MojoGetTimeTicksNow();
    178 
    179     // Interleave the starts.
    180     for (unsigned i = 0; i < num_writers || i < num_readers; i++) {
    181       if (i < num_writers)
    182         writers[i]->Start();
    183       if (i < num_readers)
    184         readers[i]->Start();
    185     }
    186 
    187     Sleep(kPerftestTimeMicroseconds);
    188 
    189     // Close both handles to make writers and readers stop immediately.
    190     result = MojoClose(h0_);
    191     assert(result == MOJO_RESULT_OK);
    192     result = MojoClose(h1_);
    193     assert(result == MOJO_RESULT_OK);
    194 
    195     // Join everything.
    196     for (unsigned i = 0; i < num_writers; i++)
    197       writers[i]->Join();
    198     for (unsigned i = 0; i < num_readers; i++)
    199       readers[i]->Join();
    200 
    201     // Stop time here.
    202     MojoTimeTicks end_time = MojoGetTimeTicksNow();
    203 
    204     // Add up write and read counts, and destroy the threads.
    205     int64_t num_writes = 0;
    206     for (unsigned i = 0; i < num_writers; i++) {
    207       num_writes += writers[i]->num_writes();
    208       delete writers[i];
    209     }
    210     writers.clear();
    211     int64_t num_reads = 0;
    212     for (unsigned i = 0; i < num_readers; i++) {
    213       num_reads += readers[i]->num_reads();
    214       delete readers[i];
    215     }
    216     readers.clear();
    217 
    218     char sub_test_name[200];
    219     sprintf(sub_test_name, "%uw_%ur_%ubytes", num_writers, num_readers,
    220             static_cast<unsigned>(num_bytes));
    221     mojo::test::LogPerfResult(
    222         "MessagePipe_Threaded_Writes", sub_test_name,
    223         1000000.0 * static_cast<double>(num_writes) / (end_time - start_time),
    224         "writes/second");
    225     mojo::test::LogPerfResult(
    226         "MessagePipe_Threaded_Reads", sub_test_name,
    227         1000000.0 * static_cast<double>(num_reads) / (end_time - start_time),
    228         "reads/second");
    229   }
    230 #endif  // !defined(WIN32)
    231 
    232   MojoHandle h0_;
    233   MojoHandle h1_;
    234 
    235   std::vector<uint8_t> buffer_;
    236 
    237  private:
    238 #if !defined(WIN32)
    239   void Sleep(int64_t microseconds) {
    240     struct timespec req = {
    241         static_cast<time_t>(microseconds / 1000000),       // Seconds.
    242         static_cast<long>(microseconds % 1000000) * 1000L  // Nanoseconds.
    243     };
    244     int rv = nanosleep(&req, nullptr);
    245     ALLOW_UNUSED_LOCAL(rv);
    246     assert(rv == 0);
    247   }
    248 #endif  // !defined(WIN32)
    249 
    250   DISALLOW_COPY_AND_ASSIGN(CorePerftest);
    251 };
    252 
    253 // A no-op test so we can compare performance.
    254 TEST_F(CorePerftest, NoOp) {
    255   mojo::test::IterateAndReportPerf("Iterate_NoOp", nullptr, &CorePerftest::NoOp,
    256                                    this);
    257 }
    258 
    259 TEST_F(CorePerftest, MessagePipe_CreateAndClose) {
    260   mojo::test::IterateAndReportPerf("MessagePipe_CreateAndClose", nullptr,
    261                                    &CorePerftest::MessagePipe_CreateAndClose,
    262                                    this);
    263 }
    264 
    265 TEST_F(CorePerftest, MessagePipe_WriteAndRead) {
    266   MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_);
    267   ALLOW_UNUSED_LOCAL(result);
    268   assert(result == MOJO_RESULT_OK);
    269   buffer_.resize(10);
    270   mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead", "10bytes",
    271                                    &CorePerftest::MessagePipe_WriteAndRead,
    272                                    this);
    273   buffer_.resize(100);
    274   mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead", "100bytes",
    275                                    &CorePerftest::MessagePipe_WriteAndRead,
    276                                    this);
    277   buffer_.resize(1000);
    278   mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead", "1000bytes",
    279                                    &CorePerftest::MessagePipe_WriteAndRead,
    280                                    this);
    281   buffer_.resize(10000);
    282   mojo::test::IterateAndReportPerf("MessagePipe_WriteAndRead", "10000bytes",
    283                                    &CorePerftest::MessagePipe_WriteAndRead,
    284                                    this);
    285   result = MojoClose(h0_);
    286   assert(result == MOJO_RESULT_OK);
    287   result = MojoClose(h1_);
    288   assert(result == MOJO_RESULT_OK);
    289 }
    290 
    291 TEST_F(CorePerftest, MessagePipe_EmptyRead) {
    292   MojoResult result = MojoCreateMessagePipe(nullptr, &h0_, &h1_);
    293   ALLOW_UNUSED_LOCAL(result);
    294   assert(result == MOJO_RESULT_OK);
    295   mojo::test::IterateAndReportPerf("MessagePipe_EmptyRead", nullptr,
    296                                    &CorePerftest::MessagePipe_EmptyRead, this);
    297   result = MojoClose(h0_);
    298   assert(result == MOJO_RESULT_OK);
    299   result = MojoClose(h1_);
    300   assert(result == MOJO_RESULT_OK);
    301 }
    302 
    303 #if !defined(WIN32)
    304 TEST_F(CorePerftest, MessagePipe_Threaded) {
    305   DoMessagePipeThreadedTest(1u, 1u, 100u);
    306   DoMessagePipeThreadedTest(2u, 2u, 100u);
    307   DoMessagePipeThreadedTest(3u, 3u, 100u);
    308   DoMessagePipeThreadedTest(10u, 10u, 100u);
    309   DoMessagePipeThreadedTest(10u, 1u, 100u);
    310   DoMessagePipeThreadedTest(1u, 10u, 100u);
    311 
    312   // For comparison of overhead:
    313   DoMessagePipeThreadedTest(1u, 1u, 10u);
    314   // 100 was done above.
    315   DoMessagePipeThreadedTest(1u, 1u, 1000u);
    316   DoMessagePipeThreadedTest(1u, 1u, 10000u);
    317 
    318   DoMessagePipeThreadedTest(3u, 3u, 10u);
    319   // 100 was done above.
    320   DoMessagePipeThreadedTest(3u, 3u, 1000u);
    321   DoMessagePipeThreadedTest(3u, 3u, 10000u);
    322 }
    323 #endif  // !defined(WIN32)
    324 
    325 }  // namespace
    326