Home | History | Annotate | Download | only in system
      1 // Copyright 2014 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 #include <stddef.h>
      6 #include <stdint.h>
      7 
      8 #include <memory>
      9 #include <utility>
     10 
     11 #include "base/bind.h"
     12 #include "base/bind_helpers.h"
     13 #include "base/logging.h"
     14 #include "base/macros.h"
     15 #include "base/strings/stringprintf.h"
     16 #include "base/test/perf_time_logger.h"
     17 #include "base/threading/thread.h"
     18 #include "mojo/edk/embedder/embedder.h"
     19 #include "mojo/edk/embedder/scoped_platform_handle.h"
     20 #include "mojo/edk/system/handle_signals_state.h"
     21 #include "mojo/edk/system/test_utils.h"
     22 #include "mojo/edk/test/mojo_test_base.h"
     23 #include "mojo/edk/test/test_utils.h"
     24 #include "mojo/public/c/system/functions.h"
     25 #include "mojo/public/cpp/system/message_pipe.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 
     28 namespace mojo {
     29 namespace edk {
     30 namespace {
     31 
     32 class MessagePipePerfTest : public test::MojoTestBase {
     33  public:
     34   MessagePipePerfTest() : message_count_(0), message_size_(0) {}
     35 
     36   void SetUpMeasurement(int message_count, size_t message_size) {
     37     message_count_ = message_count;
     38     message_size_ = message_size;
     39     payload_ = std::string(message_size, '*');
     40     read_buffer_.resize(message_size * 2);
     41   }
     42 
     43  protected:
     44   void WriteWaitThenRead(MojoHandle mp) {
     45     CHECK_EQ(MojoWriteMessage(mp, payload_.data(),
     46                               static_cast<uint32_t>(payload_.size()), nullptr,
     47                               0, MOJO_WRITE_MESSAGE_FLAG_NONE),
     48              MOJO_RESULT_OK);
     49     HandleSignalsState hss;
     50     CHECK_EQ(MojoWait(mp, MOJO_HANDLE_SIGNAL_READABLE, MOJO_DEADLINE_INDEFINITE,
     51                       &hss),
     52              MOJO_RESULT_OK);
     53     uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer_.size());
     54     CHECK_EQ(MojoReadMessage(mp, &read_buffer_[0], &read_buffer_size, nullptr,
     55                              nullptr, MOJO_READ_MESSAGE_FLAG_NONE),
     56              MOJO_RESULT_OK);
     57     CHECK_EQ(read_buffer_size, static_cast<uint32_t>(payload_.size()));
     58   }
     59 
     60   void SendQuitMessage(MojoHandle mp) {
     61     CHECK_EQ(MojoWriteMessage(mp, "", 0, nullptr, 0,
     62                               MOJO_WRITE_MESSAGE_FLAG_NONE),
     63              MOJO_RESULT_OK);
     64   }
     65 
     66   void Measure(MojoHandle mp) {
     67     // Have one ping-pong to ensure channel being established.
     68     WriteWaitThenRead(mp);
     69 
     70     std::string test_name =
     71         base::StringPrintf("IPC_Perf_%dx_%u", message_count_,
     72                            static_cast<unsigned>(message_size_));
     73     base::PerfTimeLogger logger(test_name.c_str());
     74 
     75     for (int i = 0; i < message_count_; ++i)
     76       WriteWaitThenRead(mp);
     77 
     78     logger.Done();
     79   }
     80 
     81  protected:
     82   void RunPingPongServer(MojoHandle mp) {
     83     // This values are set to align with one at ipc_pertests.cc for comparison.
     84     const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
     85     const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
     86 
     87     for (size_t i = 0; i < 5; i++) {
     88       SetUpMeasurement(kMessageCount[i], kMsgSize[i]);
     89       Measure(mp);
     90     }
     91 
     92     SendQuitMessage(mp);
     93   }
     94 
     95   static int RunPingPongClient(MojoHandle mp) {
     96     std::string buffer(1000000, '\0');
     97     int rv = 0;
     98     while (true) {
     99       // Wait for our end of the message pipe to be readable.
    100       HandleSignalsState hss;
    101       MojoResult result =
    102           MojoWait(mp, MOJO_HANDLE_SIGNAL_READABLE,
    103                    MOJO_DEADLINE_INDEFINITE, &hss);
    104       if (result != MOJO_RESULT_OK) {
    105         rv = result;
    106         break;
    107       }
    108 
    109       uint32_t read_size = static_cast<uint32_t>(buffer.size());
    110       CHECK_EQ(MojoReadMessage(mp, &buffer[0],
    111                                &read_size, nullptr,
    112                                0, MOJO_READ_MESSAGE_FLAG_NONE),
    113                MOJO_RESULT_OK);
    114 
    115       // Empty message indicates quit.
    116       if (read_size == 0)
    117         break;
    118 
    119       CHECK_EQ(MojoWriteMessage(mp, &buffer[0],
    120                                 read_size,
    121                                 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE),
    122                MOJO_RESULT_OK);
    123     }
    124 
    125     return rv;
    126   }
    127 
    128  private:
    129   int message_count_;
    130   size_t message_size_;
    131   std::string payload_;
    132   std::string read_buffer_;
    133   std::unique_ptr<base::PerfTimeLogger> perf_logger_;
    134 
    135   DISALLOW_COPY_AND_ASSIGN(MessagePipePerfTest);
    136 };
    137 
    138 TEST_F(MessagePipePerfTest, PingPong) {
    139   MojoHandle server_handle, client_handle;
    140   CreateMessagePipe(&server_handle, &client_handle);
    141 
    142   base::Thread client_thread("PingPongClient");
    143   client_thread.Start();
    144   client_thread.task_runner()->PostTask(
    145       FROM_HERE,
    146       base::Bind(base::IgnoreResult(&RunPingPongClient), client_handle));
    147 
    148   RunPingPongServer(server_handle);
    149 }
    150 
    151 // For each message received, sends a reply message with the same contents
    152 // repeated twice, until the other end is closed or it receives "quitquitquit"
    153 // (which it doesn't reply to). It'll return the number of messages received,
    154 // not including any "quitquitquit" message, modulo 100.
    155 DEFINE_TEST_CLIENT_WITH_PIPE(PingPongClient, MessagePipePerfTest, h) {
    156   return RunPingPongClient(h);
    157 }
    158 
    159 // Repeatedly sends messages as previous one got replied by the child.
    160 // Waits for the child to close its end before quitting once specified
    161 // number of messages has been sent.
    162 TEST_F(MessagePipePerfTest, MultiprocessPingPong) {
    163   RUN_CHILD_ON_PIPE(PingPongClient, h)
    164     RunPingPongServer(h);
    165   END_CHILD()
    166 }
    167 
    168 }  // namespace
    169 }  // namespace edk
    170 }  // namespace mojo
    171