blob: 3feabda9d106382a2774714a49c492ce7d54c8a3 [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
viettrungluu@chromium.org06151432013-01-16 05:14:22 +09007#include <algorithm>
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +09008#include <string>
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +09009
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090010#include "base/basictypes.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090013#include "base/pickle.h"
avi@chromium.orge7eaf392013-06-11 15:32:18 +090014#include "base/strings/stringprintf.h"
tfarina@chromium.org530d8842013-09-17 09:34:38 +090015#include "base/test/perf_time_logger.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090016#include "base/threading/thread.h"
avi@chromium.org78a7e7b2013-06-29 00:20:02 +090017#include "base/time/time.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090018#include "ipc/ipc_channel.h"
19#include "ipc/ipc_channel_proxy.h"
avi@chromium.orge7eaf392013-06-11 15:32:18 +090020#include "ipc/ipc_descriptors.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090021#include "ipc/ipc_message_utils.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090022#include "ipc/ipc_sender.h"
viettrungluu@chromium.orge9778422013-01-12 06:19:15 +090023#include "ipc/ipc_test_base.h"
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090024
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +090025namespace {
26
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090027// This test times the roundtrip IPC message cycle.
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090028//
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090029// TODO(brettw): Make this test run by default.
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090030
31class IPCChannelPerfTest : public IPCTestBase {
32};
33
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090034// This class simply collects stats about abstract "events" (each of which has a
35// start time and an end time).
36class EventTimeTracker {
37 public:
38 explicit EventTimeTracker(const char* name)
39 : name_(name),
40 count_(0) {
41 }
42
43 void AddEvent(const base::TimeTicks& start, const base::TimeTicks& end) {
44 DCHECK(end >= start);
45 count_++;
46 base::TimeDelta duration = end - start;
47 total_duration_ += duration;
48 max_duration_ = std::max(max_duration_, duration);
49 }
50
51 void ShowResults() const {
52 VLOG(1) << name_ << " count: " << count_;
53 VLOG(1) << name_ << " total duration: "
54 << total_duration_.InMillisecondsF() << " ms";
55 VLOG(1) << name_ << " average duration: "
56 << (total_duration_.InMillisecondsF() / static_cast<double>(count_))
57 << " ms";
58 VLOG(1) << name_ << " maximum duration: "
59 << max_duration_.InMillisecondsF() << " ms";
60 }
61
62 void Reset() {
63 count_ = 0;
64 total_duration_ = base::TimeDelta();
65 max_duration_ = base::TimeDelta();
66 }
67
68 private:
69 const std::string name_;
70
71 uint64 count_;
72 base::TimeDelta total_duration_;
73 base::TimeDelta max_duration_;
74
75 DISALLOW_COPY_AND_ASSIGN(EventTimeTracker);
76};
77
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090078// This channel listener just replies to all messages with the exact same
79// message. It assumes each message has one string parameter. When the string
80// "quit" is sent, it will exit.
81class ChannelReflectorListener : public IPC::Listener {
82 public:
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +090083 ChannelReflectorListener()
84 : channel_(NULL),
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090085 latency_tracker_("Client messages") {
86 VLOG(1) << "Client listener up";
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090087 }
88
rsleevi@chromium.org5a8d7ef2013-02-06 19:08:55 +090089 virtual ~ChannelReflectorListener() {
viettrungluu@chromium.org06151432013-01-16 05:14:22 +090090 VLOG(1) << "Client listener down";
91 latency_tracker_.ShowResults();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +090092 }
93
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +090094 void Init(IPC::Channel* channel) {
95 DCHECK(!channel_);
96 channel_ = channel;
97 }
98
rsleevi@chromium.org5a8d7ef2013-02-06 19:08:55 +090099 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900100 CHECK(channel_);
101
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900102 PickleIterator iter(message);
103 int64 time_internal;
104 EXPECT_TRUE(iter.ReadInt64(&time_internal));
105 int msgid;
106 EXPECT_TRUE(iter.ReadInt(&msgid));
107 std::string payload;
108 EXPECT_TRUE(iter.ReadString(&payload));
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900109
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900110 // Include message deserialization in latency.
111 base::TimeTicks now = base::TimeTicks::Now();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900112
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900113 if (payload == "hello") {
114 latency_tracker_.Reset();
115 } else if (payload == "quit") {
116 latency_tracker_.ShowResults();
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900117 base::MessageLoop::current()->QuitWhenIdle();
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900118 return true;
119 } else {
120 // Don't track hello and quit messages.
121 latency_tracker_.AddEvent(
122 base::TimeTicks::FromInternalValue(time_internal), now);
123 }
124
bbudge@chromium.orgab4c6bc2013-11-05 07:28:12 +0900125 IPC::Message* msg = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900126 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
127 msg->WriteInt(msgid);
128 msg->WriteString(payload);
129 channel_->Send(msg);
130 return true;
131 }
132
133 private:
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900134 IPC::Channel* channel_;
135 EventTimeTracker latency_tracker_;
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900136};
137
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900138class PerformanceChannelListener : public IPC::Listener {
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900139 public:
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900140 PerformanceChannelListener()
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900141 : channel_(NULL),
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900142 msg_count_(0),
143 msg_size_(0),
144 count_down_(0),
145 latency_tracker_("Server messages") {
146 VLOG(1) << "Server listener up";
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900147 }
148
rsleevi@chromium.org5a8d7ef2013-02-06 19:08:55 +0900149 virtual ~PerformanceChannelListener() {
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900150 VLOG(1) << "Server listener down";
151 }
152
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900153 void Init(IPC::Channel* channel) {
154 DCHECK(!channel_);
155 channel_ = channel;
156 }
157
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900158 // Call this before running the message loop.
159 void SetTestParams(int msg_count, size_t msg_size) {
160 DCHECK_EQ(0, count_down_);
161 msg_count_ = msg_count;
162 msg_size_ = msg_size;
163 count_down_ = msg_count_;
164 payload_ = std::string(msg_size_, 'a');
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900165 }
166
rsleevi@chromium.org5a8d7ef2013-02-06 19:08:55 +0900167 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
viettrungluu@chromium.org721fe992013-01-17 04:33:32 +0900168 CHECK(channel_);
169
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900170 PickleIterator iter(message);
171 int64 time_internal;
172 EXPECT_TRUE(iter.ReadInt64(&time_internal));
173 int msgid;
174 EXPECT_TRUE(iter.ReadInt(&msgid));
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900175 std::string reflected_payload;
176 EXPECT_TRUE(iter.ReadString(&reflected_payload));
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900177
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900178 // Include message deserialization in latency.
179 base::TimeTicks now = base::TimeTicks::Now();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900180
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900181 if (reflected_payload == "hello") {
182 // Start timing on hello.
183 latency_tracker_.Reset();
184 DCHECK(!perf_logger_.get());
185 std::string test_name = base::StringPrintf(
186 "IPC_Perf_%dx_%u", msg_count_, static_cast<unsigned>(msg_size_));
tfarina@chromium.org530d8842013-09-17 09:34:38 +0900187 perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str()));
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900188 } else {
189 DCHECK_EQ(payload_.size(), reflected_payload.size());
190
191 latency_tracker_.AddEvent(
192 base::TimeTicks::FromInternalValue(time_internal), now);
193
194 CHECK(count_down_ > 0);
195 count_down_--;
196 if (count_down_ == 0) {
197 perf_logger_.reset(); // Stop the perf timer now.
198 latency_tracker_.ShowResults();
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900199 base::MessageLoop::current()->QuitWhenIdle();
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900200 return true;
201 }
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900202 }
203
bbudge@chromium.orgab4c6bc2013-11-05 07:28:12 +0900204 IPC::Message* msg = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900205 msg->WriteInt64(base::TimeTicks::Now().ToInternalValue());
206 msg->WriteInt(count_down_);
207 msg->WriteString(payload_);
208 channel_->Send(msg);
209 return true;
210 }
211
212 private:
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900213 IPC::Channel* channel_;
214 int msg_count_;
215 size_t msg_size_;
216
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900217 int count_down_;
218 std::string payload_;
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900219 EventTimeTracker latency_tracker_;
tfarina@chromium.org530d8842013-09-17 09:34:38 +0900220 scoped_ptr<base::PerfTimeLogger> perf_logger_;
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900221};
222
223TEST_F(IPCChannelPerfTest, Performance) {
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900224 Init("PerformanceClient");
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900225
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900226 // Set up IPC channel and start client.
227 PerformanceChannelListener listener;
228 CreateChannel(&listener);
229 listener.Init(channel());
230 ASSERT_TRUE(ConnectChannel());
231 ASSERT_TRUE(StartClient());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900232
epenner@chromium.org913c9482014-03-19 15:34:52 +0900233 // Test several sizes. We use 12^N for message size, and limit the message
234 // count to keep the test duration reasonable.
235 const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
epenner@chromium.orge0970ad2014-03-21 08:36:25 +0900236 const int kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
epenner@chromium.org913c9482014-03-19 15:34:52 +0900237
238 for (size_t i = 0; i < 5; i++) {
239 listener.SetTestParams(kMessageCount[i], kMsgSize[i]);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900240
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900241 // This initial message will kick-start the ping-pong of messages.
242 IPC::Message* message =
bbudge@chromium.orgab4c6bc2013-11-05 07:28:12 +0900243 new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900244 message->WriteInt64(base::TimeTicks::Now().ToInternalValue());
245 message->WriteInt(-1);
246 message->WriteString("hello");
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900247 sender()->Send(message);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900248
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900249 // Run message loop.
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900250 base::MessageLoop::current()->Run();
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900251 }
252
253 // Send quit message.
bbudge@chromium.orgab4c6bc2013-11-05 07:28:12 +0900254 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900255 message->WriteInt64(base::TimeTicks::Now().ToInternalValue());
256 message->WriteInt(-1);
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900257 message->WriteString("quit");
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900258 sender()->Send(message);
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900259
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900260 EXPECT_TRUE(WaitForClientShutdown());
261 DestroyChannel();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900262}
263
viettrungluu@chromium.org06151432013-01-16 05:14:22 +0900264// This message loop bounces all messages back to the sender.
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900265MULTIPROCESS_IPC_TEST_CLIENT_MAIN(PerformanceClient) {
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900266 base::MessageLoopForIO main_message_loop;
viettrungluu@chromium.org00155942013-01-26 06:51:35 +0900267 ChannelReflectorListener listener;
morrita@chromium.org2ced0042014-05-30 12:58:59 +0900268 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
269 IPCTestBase::GetChannelName("PerformanceClient"), &listener));
270 listener.Init(channel.get());
271 CHECK(channel->Connect());
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900272
xhwang@chromium.org0b2c2a52013-05-01 05:55:03 +0900273 base::MessageLoop::current()->Run();
viettrungluu@chromium.org7d86af22013-01-12 00:13:37 +0900274 return 0;
275}
viettrungluu@chromium.org7ca19132013-01-12 05:56:22 +0900276
277} // namespace