OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 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 "build/build_config.h" |
| 6 |
| 7 #if defined(OS_WIN) |
| 8 #include <windows.h> |
| 9 #elif defined(OS_POSIX) |
| 10 #include <sys/types.h> |
| 11 #include <unistd.h> |
| 12 #endif |
| 13 |
| 14 #include <stdio.h> |
| 15 #include <string> |
| 16 #include <utility> |
| 17 |
| 18 #include "ipc/ipc_test_base.h" |
| 19 |
| 20 #include "base/base_switches.h" |
| 21 #include "base/command_line.h" |
| 22 #include "base/debug/debug_on_start_win.h" |
| 23 #include "base/perftimer.h" |
| 24 #include "base/pickle.h" |
| 25 #include "base/test/perf_test_suite.h" |
| 26 #include "base/threading/thread.h" |
| 27 #include "base/time.h" |
| 28 #include "ipc/ipc_descriptors.h" |
| 29 #include "ipc/ipc_channel.h" |
| 30 #include "ipc/ipc_channel_proxy.h" |
| 31 #include "ipc/ipc_message_utils.h" |
| 32 #include "ipc/ipc_multiprocess_test.h" |
| 33 #include "ipc/ipc_sender.h" |
| 34 #include "ipc/ipc_switches.h" |
| 35 #include "testing/multiprocess_func_list.h" |
| 36 |
| 37 // This test times the roundtrip IPC message cycle. It is enabled with a |
| 38 // special preprocessor define to enable it instead of the standard IPC |
| 39 // unit tests. This works around some funny termination conditions in the |
| 40 // regular unit tests. |
| 41 // |
| 42 // This test is not automated. To test, you will want to vary the message |
| 43 // count and message size in TEST to get the numbers you want. |
| 44 // |
| 45 // FIXME(brettw): Automate this test and have it run by default. |
| 46 |
| 47 class IPCChannelPerfTest : public IPCTestBase { |
| 48 }; |
| 49 |
| 50 // This channel listener just replies to all messages with the exact same |
| 51 // message. It assumes each message has one string parameter. When the string |
| 52 // "quit" is sent, it will exit. |
| 53 class ChannelReflectorListener : public IPC::Listener { |
| 54 public: |
| 55 explicit ChannelReflectorListener(IPC::Channel *channel) : |
| 56 channel_(channel), |
| 57 count_messages_(0) { |
| 58 std::cout << "Reflector up" << std::endl; |
| 59 } |
| 60 |
| 61 ~ChannelReflectorListener() { |
| 62 std::cout << "Client Messages: " << count_messages_ << std::endl; |
| 63 std::cout << "Client Latency: " << latency_messages_.InMilliseconds() |
| 64 << std::endl; |
| 65 } |
| 66 |
| 67 virtual bool OnMessageReceived(const IPC::Message& message) { |
| 68 count_messages_++; |
| 69 PickleIterator iter(message); |
| 70 int64 time_internal; |
| 71 EXPECT_TRUE(iter.ReadInt64(&time_internal)); |
| 72 int msgid; |
| 73 EXPECT_TRUE(iter.ReadInt(&msgid)); |
| 74 std::string payload; |
| 75 EXPECT_TRUE(iter.ReadString(&payload)); |
| 76 // TODO(vtl): Should we use |HighResNow()| instead of |Now()|? |
| 77 latency_messages_ += base::TimeTicks::Now() - |
| 78 base::TimeTicks::FromInternalValue(time_internal); |
| 79 |
| 80 // cout << "reflector msg received: " << msgid << endl; |
| 81 if (payload == "quit") |
| 82 MessageLoop::current()->Quit(); |
| 83 |
| 84 IPC::Message* msg = new IPC::Message(0, |
| 85 2, |
| 86 IPC::Message::PRIORITY_NORMAL); |
| 87 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); |
| 88 msg->WriteInt(msgid); |
| 89 msg->WriteString(payload); |
| 90 channel_->Send(msg); |
| 91 return true; |
| 92 } |
| 93 |
| 94 private: |
| 95 IPC::Channel *channel_; |
| 96 int count_messages_; |
| 97 base::TimeDelta latency_messages_; |
| 98 }; |
| 99 |
| 100 class ChannelPerfListener : public IPC::Listener { |
| 101 public: |
| 102 ChannelPerfListener(IPC::Channel* channel, int msg_count, int msg_size) : |
| 103 count_down_(msg_count), |
| 104 channel_(channel), |
| 105 count_messages_(0) { |
| 106 payload_.resize(msg_size); |
| 107 for (int i = 0; i < static_cast<int>(payload_.size()); i++) |
| 108 payload_[i] = 'a'; |
| 109 std::cout << "perflistener up" << std::endl; |
| 110 } |
| 111 |
| 112 ~ChannelPerfListener() { |
| 113 std::cout << "Server Messages: " << count_messages_ << std::endl; |
| 114 std::cout << "Server Latency: " << latency_messages_.InMilliseconds() |
| 115 << std::endl; |
| 116 } |
| 117 |
| 118 virtual bool OnMessageReceived(const IPC::Message& message) { |
| 119 count_messages_++; |
| 120 // Decode the string so this gets counted in the total time. |
| 121 PickleIterator iter(message); |
| 122 int64 time_internal; |
| 123 EXPECT_TRUE(iter.ReadInt64(&time_internal)); |
| 124 int msgid; |
| 125 EXPECT_TRUE(iter.ReadInt(&msgid)); |
| 126 std::string cur; |
| 127 EXPECT_TRUE(iter.ReadString(&cur)); |
| 128 latency_messages_ += base::TimeTicks::Now() - |
| 129 base::TimeTicks::FromInternalValue(time_internal); |
| 130 |
| 131 count_down_--; |
| 132 if (count_down_ == 0) { |
| 133 IPC::Message* msg = new IPC::Message(0, |
| 134 2, |
| 135 IPC::Message::PRIORITY_NORMAL); |
| 136 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); |
| 137 msg->WriteInt(count_down_); |
| 138 msg->WriteString("quit"); |
| 139 channel_->Send(msg); |
| 140 |
| 141 MessageLoop::current()->QuitWhenIdle(); |
| 142 return true; |
| 143 } |
| 144 |
| 145 IPC::Message* msg = new IPC::Message(0, |
| 146 2, |
| 147 IPC::Message::PRIORITY_NORMAL); |
| 148 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); |
| 149 msg->WriteInt(count_down_); |
| 150 msg->WriteString(payload_); |
| 151 channel_->Send(msg); |
| 152 return true; |
| 153 } |
| 154 |
| 155 private: |
| 156 int count_down_; |
| 157 std::string payload_; |
| 158 IPC::Channel *channel_; |
| 159 int count_messages_; |
| 160 base::TimeDelta latency_messages_; |
| 161 }; |
| 162 |
| 163 TEST_F(IPCChannelPerfTest, Performance) { |
| 164 // setup IPC channel |
| 165 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER, NULL); |
| 166 ChannelPerfListener perf_listener(&chan, 10000, 100000); |
| 167 chan.set_listener(&perf_listener); |
| 168 ASSERT_TRUE(chan.Connect()); |
| 169 |
| 170 base::ProcessHandle process_handle = SpawnChild(TEST_REFLECTOR, &chan); |
| 171 ASSERT_TRUE(process_handle); |
| 172 |
| 173 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1)); |
| 174 |
| 175 PerfTimeLogger logger("IPC_Perf"); |
| 176 |
| 177 // this initial message will kick-start the ping-pong of messages |
| 178 IPC::Message* message = new IPC::Message(0, |
| 179 2, |
| 180 IPC::Message::PRIORITY_NORMAL); |
| 181 message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); |
| 182 message->WriteInt(-1); |
| 183 message->WriteString("Hello"); |
| 184 chan.Send(message); |
| 185 |
| 186 // run message loop |
| 187 MessageLoop::current()->Run(); |
| 188 |
| 189 // Clean up child process. |
| 190 EXPECT_TRUE(base::WaitForSingleProcess( |
| 191 process_handle, base::TimeDelta::FromSeconds(5))); |
| 192 base::CloseProcessHandle(process_handle); |
| 193 } |
| 194 |
| 195 // This message loop bounces all messages back to the sender |
| 196 MULTIPROCESS_IPC_TEST_MAIN(RunReflector) { |
| 197 MessageLoopForIO main_message_loop; |
| 198 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT, NULL); |
| 199 ChannelReflectorListener channel_reflector_listener(&chan); |
| 200 chan.set_listener(&channel_reflector_listener); |
| 201 CHECK(chan.Connect()); |
| 202 |
| 203 MessageLoop::current()->Run(); |
| 204 return 0; |
| 205 } |
OLD | NEW |