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