1 // Copyright 2017 The Chromium Authors
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 "ipc/ipc_perftest_util.h"
6
7 #include <tuple>
8
9 #include "base/logging.h"
10 #include "base/run_loop.h"
11 #include "base/task/single_thread_task_runner.h"
12 #include "build/build_config.h"
13 #include "ipc/ipc_channel_proxy.h"
14 #include "ipc/ipc_perftest_messages.h"
15 #include "mojo/core/embedder/embedder.h"
16 #include "mojo/core/test/multiprocess_test_helper.h"
17
18 namespace IPC {
19
GetIOThreadTaskRunner()20 scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() {
21 scoped_refptr<base::TaskRunner> runner = mojo::core::GetIOTaskRunner();
22 return scoped_refptr<base::SingleThreadTaskRunner>(
23 static_cast<base::SingleThreadTaskRunner*>(runner.get()));
24 }
25
ChannelReflectorListener()26 ChannelReflectorListener::ChannelReflectorListener() : channel_(nullptr) {
27 VLOG(1) << "Client listener up";
28 }
29
~ChannelReflectorListener()30 ChannelReflectorListener::~ChannelReflectorListener() {
31 VLOG(1) << "Client listener down";
32 }
33
Init(Sender * channel,base::OnceClosure quit_closure)34 void ChannelReflectorListener::Init(Sender* channel,
35 base::OnceClosure quit_closure) {
36 DCHECK(!channel_);
37 channel_ = channel;
38 quit_closure_ = std::move(quit_closure);
39 }
40
OnMessageReceived(const Message & message)41 bool ChannelReflectorListener::OnMessageReceived(const Message& message) {
42 CHECK(channel_);
43 bool handled = true;
44 IPC_BEGIN_MESSAGE_MAP(ChannelReflectorListener, message)
45 IPC_MESSAGE_HANDLER(TestMsg_Hello, OnHello)
46 IPC_MESSAGE_HANDLER(TestMsg_Ping, OnPing)
47 IPC_MESSAGE_HANDLER(TestMsg_SyncPing, OnSyncPing)
48 IPC_MESSAGE_HANDLER(TestMsg_Quit, OnQuit)
49 IPC_MESSAGE_UNHANDLED(handled = false)
50 IPC_END_MESSAGE_MAP()
51 return handled;
52 }
53
OnHello()54 void ChannelReflectorListener::OnHello() {
55 channel_->Send(new TestMsg_Hello);
56 }
57
OnPing(const std::string & payload)58 void ChannelReflectorListener::OnPing(const std::string& payload) {
59 channel_->Send(new TestMsg_Ping(payload));
60 }
61
OnSyncPing(const std::string & payload,std::string * response)62 void ChannelReflectorListener::OnSyncPing(const std::string& payload,
63 std::string* response) {
64 *response = payload;
65 }
66
OnQuit()67 void ChannelReflectorListener::OnQuit() {
68 std::move(quit_closure_).Run();
69 }
70
Send(IPC::Message * message)71 void ChannelReflectorListener::Send(IPC::Message* message) {
72 channel_->Send(message);
73 }
74
LockThreadAffinity(int cpu_number)75 LockThreadAffinity::LockThreadAffinity(int cpu_number)
76 : affinity_set_ok_(false) {
77 #if BUILDFLAG(IS_WIN)
78 const DWORD_PTR thread_mask = static_cast<DWORD_PTR>(1) << cpu_number;
79 old_affinity_ = SetThreadAffinityMask(GetCurrentThread(), thread_mask);
80 affinity_set_ok_ = old_affinity_ != 0;
81 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
82 cpu_set_t cpuset;
83 CPU_ZERO(&cpuset);
84 CPU_SET(cpu_number, &cpuset);
85 auto get_result = sched_getaffinity(0, sizeof(old_cpuset_), &old_cpuset_);
86 DCHECK_EQ(0, get_result);
87 auto set_result = sched_setaffinity(0, sizeof(cpuset), &cpuset);
88 // Check for get_result failure, even though it should always succeed.
89 affinity_set_ok_ = (set_result == 0) && (get_result == 0);
90 #endif
91 if (!affinity_set_ok_)
92 LOG(WARNING) << "Failed to set thread affinity to CPU " << cpu_number;
93 }
94
~LockThreadAffinity()95 LockThreadAffinity::~LockThreadAffinity() {
96 if (!affinity_set_ok_)
97 return;
98 #if BUILDFLAG(IS_WIN)
99 auto set_result = SetThreadAffinityMask(GetCurrentThread(), old_affinity_);
100 DCHECK_NE(0u, set_result);
101 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
102 auto set_result = sched_setaffinity(0, sizeof(old_cpuset_), &old_cpuset_);
103 DCHECK_EQ(0, set_result);
104 #endif
105 }
106
MojoPerfTestClient()107 MojoPerfTestClient::MojoPerfTestClient()
108 : listener_(new ChannelReflectorListener()) {
109 mojo::core::test::MultiprocessTestHelper::ChildSetup();
110 }
111
112 MojoPerfTestClient::~MojoPerfTestClient() = default;
113
Run(MojoHandle handle)114 int MojoPerfTestClient::Run(MojoHandle handle) {
115 handle_ = mojo::MakeScopedHandle(mojo::MessagePipeHandle(handle));
116 LockThreadAffinity thread_locker(kSharedCore);
117
118 base::RunLoop run_loop;
119 std::unique_ptr<ChannelProxy> channel = IPC::ChannelProxy::Create(
120 handle_.release(), Channel::MODE_CLIENT, listener_.get(),
121 GetIOThreadTaskRunner(),
122 base::SingleThreadTaskRunner::GetCurrentDefault());
123 listener_->Init(channel.get(), run_loop.QuitWhenIdleClosure());
124 run_loop.Run();
125 return 0;
126 }
127
ReflectorImpl(mojo::ScopedMessagePipeHandle handle,base::OnceClosure quit_closure)128 ReflectorImpl::ReflectorImpl(mojo::ScopedMessagePipeHandle handle,
129 base::OnceClosure quit_closure)
130 : quit_closure_(std::move(quit_closure)),
131 receiver_(
132 this,
133 mojo::PendingReceiver<IPC::mojom::Reflector>(std::move(handle))) {}
134
~ReflectorImpl()135 ReflectorImpl::~ReflectorImpl() {
136 std::ignore = receiver_.Unbind().PassPipe().release();
137 }
138
Ping(const std::string & value,PingCallback callback)139 void ReflectorImpl::Ping(const std::string& value, PingCallback callback) {
140 std::move(callback).Run(value);
141 }
142
SyncPing(const std::string & value,PingCallback callback)143 void ReflectorImpl::SyncPing(const std::string& value, PingCallback callback) {
144 std::move(callback).Run(value);
145 }
146
Quit()147 void ReflectorImpl::Quit() {
148 if (quit_closure_)
149 std::move(quit_closure_).Run();
150 }
151
152 } // namespace IPC
153