blob: 901f07afe156415d8f3fc0d152b6a35f94a22b6d [file] [log] [blame]
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +09001// 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
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090014#include <algorithm>
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090015#include <string>
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090016
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090017#include "base/basictypes.h"
18#include "base/logging.h"
19#include "base/memory/scoped_ptr.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090020#include "base/perftimer.h"
21#include "base/pickle.h"
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090022#include "base/stringprintf.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090023#include "base/threading/thread.h"
24#include "base/time.h"
25#include "ipc/ipc_descriptors.h"
26#include "ipc/ipc_channel.h"
27#include "ipc/ipc_channel_proxy.h"
28#include "ipc/ipc_message_utils.h"
29#include "ipc/ipc_multiprocess_test.h"
30#include "ipc/ipc_sender.h"
viettrungluu@chromium.orge9778422013-01-12 06:19:15 +090031#include "ipc/ipc_test_base.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090032
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090033namespace {
34
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090035// This test times the roundtrip IPC message cycle.
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090036//
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090037// TODO(brettw): Make this test run by default.
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090038
39class IPCChannelPerfTest : public IPCTestBase {
40};
41
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090042// This class simply collects stats about abstract "events" (each of which has a
43// start time and an end time).
44class EventTimeTracker {
45 public:
46 explicit EventTimeTracker(const char* name)
47 : name_(name),
48 count_(0) {
49 }
50
51 void AddEvent(const base::TimeTicks& start, const base::TimeTicks& end) {
52 DCHECK(end >= start);
53 count_++;
54 base::TimeDelta duration = end - start;
55 total_duration_ += duration;
56 max_duration_ = std::max(max_duration_, duration);
57 }
58
59 void ShowResults() const {
60 VLOG(1) << name_ << " count: " << count_;
61 VLOG(1) << name_ << " total duration: "
62 << total_duration_.InMillisecondsF() << " ms";
63 VLOG(1) << name_ << " average duration: "
64 << (total_duration_.InMillisecondsF() / static_cast<double>(count_))
65 << " ms";
66 VLOG(1) << name_ << " maximum duration: "
67 << max_duration_.InMillisecondsF() << " ms";
68 }
69
70 void Reset() {
71 count_ = 0;
72 total_duration_ = base::TimeDelta();
73 max_duration_ = base::TimeDelta();
74 }
75
76 private:
77 const std::string name_;
78
79 uint64 count_;
80 base::TimeDelta total_duration_;
81 base::TimeDelta max_duration_;
82
83 DISALLOW_COPY_AND_ASSIGN(EventTimeTracker);
84};
85
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090086// This channel listener just replies to all messages with the exact same
87// message. It assumes each message has one string parameter. When the string
88// "quit" is sent, it will exit.
89class ChannelReflectorListener : public IPC::Listener {
90 public:
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +090091 ChannelReflectorListener()
92 : channel_(NULL),
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090093 latency_tracker_("Client messages") {
94 VLOG(1) << "Client listener up";
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090095 }
96
97 ~ChannelReflectorListener() {
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090098 VLOG(1) << "Client listener down";
99 latency_tracker_.ShowResults();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900100 }
101
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900102 void Init(IPC::Channel* channel) {
103 DCHECK(!channel_);
104 channel_ = channel;
105 }
106
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900107 virtual bool OnMessageReceived(const IPC::Message& message) {
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900108 CHECK(channel_);
109
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900110 PickleIterator iter(message);
111 int64 time_internal;
112 EXPECT_TRUE(iter.ReadInt64(&time_internal));
113 int msgid;
114 EXPECT_TRUE(iter.ReadInt(&msgid));
115 std::string payload;
116 EXPECT_TRUE(iter.ReadString(&payload));
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900117
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900118 // Include message deserialization in latency.
119 base::TimeTicks now = base::TimeTicks::Now();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900120
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900121 if (payload == "hello") {
122 latency_tracker_.Reset();
123 } else if (payload == "quit") {
124 latency_tracker_.ShowResults();
125 MessageLoop::current()->QuitWhenIdle();
126 return true;
127 } else {
128 // Don't track hello and quit messages.
129 latency_tracker_.AddEvent(
130 base::TimeTicks::FromInternalValue(time_internal), now);
131 }
132
133 IPC::Message* msg = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900134 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
135 msg->WriteInt(msgid);
136 msg->WriteString(payload);
137 channel_->Send(msg);
138 return true;
139 }
140
141 private:
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900142 IPC::Channel* channel_;
143 EventTimeTracker latency_tracker_;
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900144};
145
146class ChannelPerfListener : public IPC::Listener {
147 public:
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900148 ChannelPerfListener()
149 : channel_(NULL),
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900150 msg_count_(0),
151 msg_size_(0),
152 count_down_(0),
153 latency_tracker_("Server messages") {
154 VLOG(1) << "Server listener up";
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900155 }
156
157 ~ChannelPerfListener() {
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900158 VLOG(1) << "Server listener down";
159 }
160
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900161 void Init(IPC::Channel* channel) {
162 DCHECK(!channel_);
163 channel_ = channel;
164 }
165
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900166 // Call this before running the message loop.
167 void SetTestParams(int msg_count, size_t msg_size) {
168 DCHECK_EQ(0, count_down_);
169 msg_count_ = msg_count;
170 msg_size_ = msg_size;
171 count_down_ = msg_count_;
172 payload_ = std::string(msg_size_, 'a');
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900173 }
174
175 virtual bool OnMessageReceived(const IPC::Message& message) {
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900176 CHECK(channel_);
177
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900178 PickleIterator iter(message);
179 int64 time_internal;
180 EXPECT_TRUE(iter.ReadInt64(&time_internal));
181 int msgid;
182 EXPECT_TRUE(iter.ReadInt(&msgid));
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900183 std::string reflected_payload;
184 EXPECT_TRUE(iter.ReadString(&reflected_payload));
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900185
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900186 // Include message deserialization in latency.
187 base::TimeTicks now = base::TimeTicks::Now();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900188
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900189 if (reflected_payload == "hello") {
190 // Start timing on hello.
191 latency_tracker_.Reset();
192 DCHECK(!perf_logger_.get());
193 std::string test_name = base::StringPrintf(
194 "IPC_Perf_%dx_%u", msg_count_, static_cast<unsigned>(msg_size_));
195 perf_logger_.reset(new PerfTimeLogger(test_name.c_str()));
196 } else {
197 DCHECK_EQ(payload_.size(), reflected_payload.size());
198
199 latency_tracker_.AddEvent(
200 base::TimeTicks::FromInternalValue(time_internal), now);
201
202 CHECK(count_down_ > 0);
203 count_down_--;
204 if (count_down_ == 0) {
205 perf_logger_.reset(); // Stop the perf timer now.
206 latency_tracker_.ShowResults();
207 MessageLoop::current()->QuitWhenIdle();
208 return true;
209 }
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900210 }
211
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900212 IPC::Message* msg = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900213 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
214 msg->WriteInt(count_down_);
215 msg->WriteString(payload_);
216 channel_->Send(msg);
217 return true;
218 }
219
220 private:
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900221 IPC::Channel* channel_;
222 int msg_count_;
223 size_t msg_size_;
224
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900225 int count_down_;
226 std::string payload_;
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900227 EventTimeTracker latency_tracker_;
228 scoped_ptr<PerfTimeLogger> perf_logger_;
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900229};
230
231TEST_F(IPCChannelPerfTest, Performance) {
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900232 // Setup IPC channel.
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900233 ChannelPerfListener perf_listener;
234 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_SERVER,
235 &perf_listener);
236 perf_listener.Init(&chan);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900237 ASSERT_TRUE(chan.Connect());
238
239 base::ProcessHandle process_handle = SpawnChild(TEST_REFLECTOR, &chan);
240 ASSERT_TRUE(process_handle);
241
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900242 const size_t kMsgSizeBase = 12;
243 const int kMsgSizeMaxExp = 5;
244 int msg_count = 100000;
245 size_t msg_size = kMsgSizeBase;
246 for (int i = 1; i <= kMsgSizeMaxExp; i++) {
247 perf_listener.SetTestParams(msg_count, msg_size);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900248
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900249 // This initial message will kick-start the ping-pong of messages.
250 IPC::Message* message =
251 new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
252 message->WriteInt64(base::TimeTicks::Now().ToInternalValue());
253 message->WriteInt(-1);
254 message->WriteString("hello");
255 chan.Send(message);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900256
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900257 // Run message loop.
258 MessageLoop::current()->Run();
259
260 msg_size *= kMsgSizeBase;
261 }
262
263 // Send quit message.
264 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900265 message->WriteInt64(base::TimeTicks::Now().ToInternalValue());
266 message->WriteInt(-1);
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900267 message->WriteString("quit");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900268 chan.Send(message);
269
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900270 // Clean up child process.
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900271 EXPECT_TRUE(base::WaitForSingleProcess(process_handle,
272 base::TimeDelta::FromSeconds(5)));
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900273 base::CloseProcessHandle(process_handle);
274}
275
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900276// This message loop bounces all messages back to the sender.
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900277MULTIPROCESS_IPC_TEST_MAIN(RunReflector) {
278 MessageLoopForIO main_message_loop;
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900279 ChannelReflectorListener channel_reflector_listener;
280 IPC::Channel chan(kReflectorChannel, IPC::Channel::MODE_CLIENT,
281 &channel_reflector_listener);
282 channel_reflector_listener.Init(&chan);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900283 CHECK(chan.Connect());
284
285 MessageLoop::current()->Run();
286 return 0;
287}
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900288
289} // namespace