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