forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This change adds ipc_mojo_perftests that runs the same benchmark as of ipc_perftests. Now head-to-head comparison becomes possible. For this change, whole ipc_perftests logic is extracted to ipc_perftest_support.cc to make it reusable by ipc_mojo_perftests. TEST=none BUG=none R=jam@chromium.org, darin@chromium.org, yuzhu@chromium.org Review URL: https://codereview.chromium.org/536213002 Cr-Commit-Position: refs/heads/master@{#293988}
- Loading branch information
Showing
15 changed files
with
575 additions
and
370 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,342 @@ | ||
// Copyright (c) 2012 The Chromium Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "ipc/ipc_perftest_support.h" | ||
|
||
#include <algorithm> | ||
#include <string> | ||
|
||
#include "base/basictypes.h" | ||
#include "base/logging.h" | ||
#include "base/memory/scoped_ptr.h" | ||
#include "base/pickle.h" | ||
#include "base/strings/stringprintf.h" | ||
#include "base/test/perf_time_logger.h" | ||
#include "base/test/test_io_thread.h" | ||
#include "base/threading/thread.h" | ||
#include "base/time/time.h" | ||
#include "build/build_config.h" | ||
#include "ipc/ipc_channel.h" | ||
#include "ipc/ipc_channel_proxy.h" | ||
#include "ipc/ipc_descriptors.h" | ||
#include "ipc/ipc_message_utils.h" | ||
#include "ipc/ipc_sender.h" | ||
|
||
namespace IPC { | ||
namespace test { | ||
|
||
// This class simply collects stats about abstract "events" (each of which has a | ||
// start time and an end time). | ||
class EventTimeTracker { | ||
public: | ||
explicit EventTimeTracker(const char* name) | ||
: name_(name), | ||
count_(0) { | ||
} | ||
|
||
void AddEvent(const base::TimeTicks& start, const base::TimeTicks& end) { | ||
DCHECK(end >= start); | ||
count_++; | ||
base::TimeDelta duration = end - start; | ||
total_duration_ += duration; | ||
max_duration_ = std::max(max_duration_, duration); | ||
} | ||
|
||
void ShowResults() const { | ||
VLOG(1) << name_ << " count: " << count_; | ||
VLOG(1) << name_ << " total duration: " | ||
<< total_duration_.InMillisecondsF() << " ms"; | ||
VLOG(1) << name_ << " average duration: " | ||
<< (total_duration_.InMillisecondsF() / static_cast<double>(count_)) | ||
<< " ms"; | ||
VLOG(1) << name_ << " maximum duration: " | ||
<< max_duration_.InMillisecondsF() << " ms"; | ||
} | ||
|
||
void Reset() { | ||
count_ = 0; | ||
total_duration_ = base::TimeDelta(); | ||
max_duration_ = base::TimeDelta(); | ||
} | ||
|
||
private: | ||
const std::string name_; | ||
|
||
uint64 count_; | ||
base::TimeDelta total_duration_; | ||
base::TimeDelta max_duration_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(EventTimeTracker); | ||
}; | ||
|
||
// This channel listener just replies to all messages with the exact same | ||
// message. It assumes each message has one string parameter. When the string | ||
// "quit" is sent, it will exit. | ||
class ChannelReflectorListener : public Listener { | ||
public: | ||
ChannelReflectorListener() | ||
: channel_(NULL), | ||
latency_tracker_("Client messages") { | ||
VLOG(1) << "Client listener up"; | ||
} | ||
|
||
virtual ~ChannelReflectorListener() { | ||
VLOG(1) << "Client listener down"; | ||
latency_tracker_.ShowResults(); | ||
} | ||
|
||
void Init(Channel* channel) { | ||
DCHECK(!channel_); | ||
channel_ = channel; | ||
} | ||
|
||
virtual bool OnMessageReceived(const Message& message) OVERRIDE { | ||
CHECK(channel_); | ||
|
||
PickleIterator iter(message); | ||
int64 time_internal; | ||
EXPECT_TRUE(iter.ReadInt64(&time_internal)); | ||
int msgid; | ||
EXPECT_TRUE(iter.ReadInt(&msgid)); | ||
std::string payload; | ||
EXPECT_TRUE(iter.ReadString(&payload)); | ||
|
||
// Include message deserialization in latency. | ||
base::TimeTicks now = base::TimeTicks::Now(); | ||
|
||
if (payload == "hello") { | ||
latency_tracker_.Reset(); | ||
} else if (payload == "quit") { | ||
latency_tracker_.ShowResults(); | ||
base::MessageLoop::current()->QuitWhenIdle(); | ||
return true; | ||
} else { | ||
// Don't track hello and quit messages. | ||
latency_tracker_.AddEvent( | ||
base::TimeTicks::FromInternalValue(time_internal), now); | ||
} | ||
|
||
Message* msg = new Message(0, 2, Message::PRIORITY_NORMAL); | ||
msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); | ||
msg->WriteInt(msgid); | ||
msg->WriteString(payload); | ||
channel_->Send(msg); | ||
return true; | ||
} | ||
|
||
private: | ||
Channel* channel_; | ||
EventTimeTracker latency_tracker_; | ||
}; | ||
|
||
class PerformanceChannelListener : public Listener { | ||
public: | ||
explicit PerformanceChannelListener(const std::string& label) | ||
: label_(label), | ||
sender_(NULL), | ||
msg_count_(0), | ||
msg_size_(0), | ||
count_down_(0), | ||
latency_tracker_("Server messages") { | ||
VLOG(1) << "Server listener up"; | ||
} | ||
|
||
virtual ~PerformanceChannelListener() { | ||
VLOG(1) << "Server listener down"; | ||
} | ||
|
||
void Init(Sender* sender) { | ||
DCHECK(!sender_); | ||
sender_ = sender; | ||
} | ||
|
||
// Call this before running the message loop. | ||
void SetTestParams(int msg_count, size_t msg_size) { | ||
DCHECK_EQ(0, count_down_); | ||
msg_count_ = msg_count; | ||
msg_size_ = msg_size; | ||
count_down_ = msg_count_; | ||
payload_ = std::string(msg_size_, 'a'); | ||
} | ||
|
||
virtual bool OnMessageReceived(const Message& message) OVERRIDE { | ||
CHECK(sender_); | ||
|
||
PickleIterator iter(message); | ||
int64 time_internal; | ||
EXPECT_TRUE(iter.ReadInt64(&time_internal)); | ||
int msgid; | ||
EXPECT_TRUE(iter.ReadInt(&msgid)); | ||
std::string reflected_payload; | ||
EXPECT_TRUE(iter.ReadString(&reflected_payload)); | ||
|
||
// Include message deserialization in latency. | ||
base::TimeTicks now = base::TimeTicks::Now(); | ||
|
||
if (reflected_payload == "hello") { | ||
// Start timing on hello. | ||
latency_tracker_.Reset(); | ||
DCHECK(!perf_logger_.get()); | ||
std::string test_name = | ||
base::StringPrintf("IPC_%s_Perf_%dx_%u", | ||
label_.c_str(), | ||
msg_count_, | ||
static_cast<unsigned>(msg_size_)); | ||
perf_logger_.reset(new base::PerfTimeLogger(test_name.c_str())); | ||
} else { | ||
DCHECK_EQ(payload_.size(), reflected_payload.size()); | ||
|
||
latency_tracker_.AddEvent( | ||
base::TimeTicks::FromInternalValue(time_internal), now); | ||
|
||
CHECK(count_down_ > 0); | ||
count_down_--; | ||
if (count_down_ == 0) { | ||
perf_logger_.reset(); // Stop the perf timer now. | ||
latency_tracker_.ShowResults(); | ||
base::MessageLoop::current()->QuitWhenIdle(); | ||
return true; | ||
} | ||
} | ||
|
||
Message* msg = new Message(0, 2, Message::PRIORITY_NORMAL); | ||
msg->WriteInt64(base::TimeTicks::Now().ToInternalValue()); | ||
msg->WriteInt(count_down_); | ||
msg->WriteString(payload_); | ||
sender_->Send(msg); | ||
return true; | ||
} | ||
|
||
private: | ||
std::string label_; | ||
Sender* sender_; | ||
int msg_count_; | ||
size_t msg_size_; | ||
|
||
int count_down_; | ||
std::string payload_; | ||
EventTimeTracker latency_tracker_; | ||
scoped_ptr<base::PerfTimeLogger> perf_logger_; | ||
}; | ||
|
||
std::vector<PingPongTestParams> | ||
IPCChannelPerfTestBase::GetDefaultTestParams() { | ||
// Test several sizes. We use 12^N for message size, and limit the message | ||
// count to keep the test duration reasonable. | ||
std::vector<PingPongTestParams> list; | ||
list.push_back(PingPongTestParams(12, 50000)); | ||
list.push_back(PingPongTestParams(144, 50000)); | ||
list.push_back(PingPongTestParams(1728, 50000)); | ||
list.push_back(PingPongTestParams(20736, 12000)); | ||
list.push_back(PingPongTestParams(248832, 100)); | ||
return list; | ||
} | ||
|
||
void IPCChannelPerfTestBase::RunTestChannelPingPong( | ||
const std::vector<PingPongTestParams>& params) { | ||
Init("PerformanceClient"); | ||
|
||
// Set up IPC channel and start client. | ||
PerformanceChannelListener listener("Channel"); | ||
CreateChannel(&listener); | ||
listener.Init(channel()); | ||
ASSERT_TRUE(ConnectChannel()); | ||
ASSERT_TRUE(StartClient()); | ||
|
||
for (size_t i = 0; i < params.size(); i++) { | ||
listener.SetTestParams(params[i].message_count(), | ||
params[i].message_size()); | ||
|
||
// This initial message will kick-start the ping-pong of messages. | ||
Message* message = | ||
new Message(0, 2, Message::PRIORITY_NORMAL); | ||
message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); | ||
message->WriteInt(-1); | ||
message->WriteString("hello"); | ||
sender()->Send(message); | ||
|
||
// Run message loop. | ||
base::MessageLoop::current()->Run(); | ||
} | ||
|
||
// Send quit message. | ||
Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); | ||
message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); | ||
message->WriteInt(-1); | ||
message->WriteString("quit"); | ||
sender()->Send(message); | ||
|
||
EXPECT_TRUE(WaitForClientShutdown()); | ||
DestroyChannel(); | ||
} | ||
|
||
void IPCChannelPerfTestBase::RunTestChannelProxyPingPong( | ||
const std::vector<PingPongTestParams>& params) { | ||
InitWithCustomMessageLoop("PerformanceClient", | ||
make_scoped_ptr(new base::MessageLoop())); | ||
|
||
base::TestIOThread io_thread(base::TestIOThread::kAutoStart); | ||
|
||
// Set up IPC channel and start client. | ||
PerformanceChannelListener listener("ChannelProxy"); | ||
CreateChannelProxy(&listener, io_thread.task_runner()); | ||
listener.Init(channel_proxy()); | ||
ASSERT_TRUE(StartClient()); | ||
|
||
for (size_t i = 0; i < params.size(); i++) { | ||
listener.SetTestParams(params[i].message_count(), | ||
params[i].message_size()); | ||
|
||
// This initial message will kick-start the ping-pong of messages. | ||
Message* message = | ||
new Message(0, 2, Message::PRIORITY_NORMAL); | ||
message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); | ||
message->WriteInt(-1); | ||
message->WriteString("hello"); | ||
sender()->Send(message); | ||
|
||
// Run message loop. | ||
base::MessageLoop::current()->Run(); | ||
} | ||
|
||
// Send quit message. | ||
Message* message = new Message(0, 2, Message::PRIORITY_NORMAL); | ||
message->WriteInt64(base::TimeTicks::Now().ToInternalValue()); | ||
message->WriteInt(-1); | ||
message->WriteString("quit"); | ||
sender()->Send(message); | ||
|
||
EXPECT_TRUE(WaitForClientShutdown()); | ||
DestroyChannelProxy(); | ||
} | ||
|
||
|
||
PingPongTestClient::PingPongTestClient() | ||
: listener_(new ChannelReflectorListener()) { | ||
} | ||
|
||
PingPongTestClient::~PingPongTestClient() { | ||
} | ||
|
||
scoped_ptr<Channel> PingPongTestClient::CreateChannel( | ||
Listener* listener) { | ||
return Channel::CreateClient( | ||
IPCTestBase::GetChannelName("PerformanceClient"), listener); | ||
} | ||
|
||
int PingPongTestClient::RunMain() { | ||
scoped_ptr<Channel> channel = CreateChannel(listener_.get()); | ||
listener_->Init(channel.get()); | ||
CHECK(channel->Connect()); | ||
|
||
base::MessageLoop::current()->Run(); | ||
return 0; | ||
} | ||
|
||
scoped_refptr<base::TaskRunner> PingPongTestClient::task_runner() { | ||
return main_message_loop_.message_loop_proxy(); | ||
} | ||
|
||
} // namespace test | ||
} // namespace IPC |
Oops, something went wrong.