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 <stdint.h>
6#include <stdio.h>
7#include <string.h>
8
9#include <string>
10#include <vector>
11
12#include "base/bind.h"
13#include "base/location.h"
14#include "base/logging.h"
15#include "base/macros.h"
16#include "base/pickle.h"
17#include "base/strings/stringprintf.h"
18#include "base/test/perf_time_logger.h"
19#include "base/time/time.h"
20#include "mojo/common/test/test_utils.h"
21#include "mojo/embedder/scoped_platform_handle.h"
22#include "mojo/system/channel.h"
23#include "mojo/system/local_message_pipe_endpoint.h"
24#include "mojo/system/message_pipe.h"
25#include "mojo/system/message_pipe_test_utils.h"
26#include "mojo/system/proxy_message_pipe_endpoint.h"
27#include "mojo/system/raw_channel.h"
28#include "mojo/system/test_utils.h"
29#include "testing/gtest/include/gtest/gtest.h"
30
31namespace mojo {
32namespace system {
33namespace {
34
35class MultiprocessMessagePipePerfTest
36    : public test::MultiprocessMessagePipeTestBase {
37 public:
38  MultiprocessMessagePipePerfTest() : message_count_(0), message_size_(0) {}
39
40  void SetUpMeasurement(int message_count, size_t message_size) {
41    message_count_ = message_count;
42    message_size_ = message_size;
43    payload_ = Pickle();
44    payload_.WriteString(std::string(message_size, '*'));
45    read_buffer_.resize(message_size * 2);
46  }
47
48 protected:
49  void WriteWaitThenRead(scoped_refptr<MessagePipe> mp) {
50    CHECK_EQ(mp->WriteMessage(0,
51                              UserPointer<const void>(payload_.data()),
52                              static_cast<uint32_t>(payload_.size()),
53                              nullptr,
54                              MOJO_WRITE_MESSAGE_FLAG_NONE),
55             MOJO_RESULT_OK);
56    HandleSignalsState hss;
57    CHECK_EQ(test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss),
58             MOJO_RESULT_OK);
59    uint32_t read_buffer_size = static_cast<uint32_t>(read_buffer_.size());
60    CHECK_EQ(mp->ReadMessage(0,
61                             UserPointer<void>(&read_buffer_[0]),
62                             MakeUserPointer(&read_buffer_size),
63                             nullptr,
64                             nullptr,
65                             MOJO_READ_MESSAGE_FLAG_NONE),
66             MOJO_RESULT_OK);
67    CHECK_EQ(read_buffer_size, static_cast<uint32_t>(payload_.size()));
68  }
69
70  void SendQuitMessage(scoped_refptr<MessagePipe> mp) {
71    CHECK_EQ(mp->WriteMessage(0,
72                              UserPointer<const void>(""),
73                              0,
74                              nullptr,
75                              MOJO_WRITE_MESSAGE_FLAG_NONE),
76             MOJO_RESULT_OK);
77  }
78
79  void Measure(scoped_refptr<MessagePipe> mp) {
80    // Have one ping-pong to ensure channel being established.
81    WriteWaitThenRead(mp);
82
83    std::string test_name =
84        base::StringPrintf("IPC_Perf_%dx_%u",
85                           message_count_,
86                           static_cast<unsigned>(message_size_));
87    base::PerfTimeLogger logger(test_name.c_str());
88
89    for (int i = 0; i < message_count_; ++i)
90      WriteWaitThenRead(mp);
91
92    logger.Done();
93  }
94
95 private:
96  int message_count_;
97  size_t message_size_;
98  Pickle payload_;
99  std::string read_buffer_;
100  scoped_ptr<base::PerfTimeLogger> perf_logger_;
101};
102
103// For each message received, sends a reply message with the same contents
104// repeated twice, until the other end is closed or it receives "quitquitquit"
105// (which it doesn't reply to). It'll return the number of messages received,
106// not including any "quitquitquit" message, modulo 100.
107MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PingPongClient) {
108  embedder::SimplePlatformSupport platform_support;
109  test::ChannelThread channel_thread(&platform_support);
110  embedder::ScopedPlatformHandle client_platform_handle =
111      mojo::test::MultiprocessTestHelper::client_platform_handle.Pass();
112  CHECK(client_platform_handle.is_valid());
113  scoped_refptr<ChannelEndpoint> ep;
114  scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalProxy(&ep));
115  channel_thread.Start(client_platform_handle.Pass(), ep);
116
117  std::string buffer(1000000, '\0');
118  int rv = 0;
119  while (true) {
120    // Wait for our end of the message pipe to be readable.
121    HandleSignalsState hss;
122    MojoResult result =
123        test::WaitIfNecessary(mp, MOJO_HANDLE_SIGNAL_READABLE, &hss);
124    if (result != MOJO_RESULT_OK) {
125      rv = result;
126      break;
127    }
128
129    uint32_t read_size = static_cast<uint32_t>(buffer.size());
130    CHECK_EQ(mp->ReadMessage(0,
131                             UserPointer<void>(&buffer[0]),
132                             MakeUserPointer(&read_size),
133                             nullptr,
134                             nullptr,
135                             MOJO_READ_MESSAGE_FLAG_NONE),
136             MOJO_RESULT_OK);
137
138    // Empty message indicates quitting
139    if (0 == read_size)
140      break;
141
142    CHECK_EQ(mp->WriteMessage(0,
143                              UserPointer<const void>(&buffer[0]),
144                              static_cast<uint32_t>(read_size),
145                              nullptr,
146                              MOJO_WRITE_MESSAGE_FLAG_NONE),
147             MOJO_RESULT_OK);
148  }
149
150  mp->Close(0);
151  return rv;
152}
153
154// Repeatedly sends messages as previous one got replied by the child.
155// Waits for the child to close its end before quitting once specified
156// number of messages has been sent.
157TEST_F(MultiprocessMessagePipePerfTest, PingPong) {
158  helper()->StartChild("PingPongClient");
159
160  scoped_refptr<ChannelEndpoint> ep;
161  scoped_refptr<MessagePipe> mp(MessagePipe::CreateLocalProxy(&ep));
162  Init(ep);
163
164  // This values are set to align with one at ipc_pertests.cc for comparison.
165  const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
166  const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
167
168  for (size_t i = 0; i < 5; i++) {
169    SetUpMeasurement(kMessageCount[i], kMsgSize[i]);
170    Measure(mp);
171  }
172
173  SendQuitMessage(mp);
174  mp->Close(0);
175  EXPECT_EQ(0, helper()->WaitForChildShutdown());
176}
177
178}  // namespace
179}  // namespace system
180}  // namespace mojo
181