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