1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <BnBinderRpcBenchmark.h>
18 #include <android-base/logging.h>
19 #include <benchmark/benchmark.h>
20 #include <binder/Binder.h>
21 #include <binder/IPCThreadState.h>
22 #include <binder/IServiceManager.h>
23 #include <binder/ProcessState.h>
24 #include <binder/RpcCertificateFormat.h>
25 #include <binder/RpcCertificateVerifier.h>
26 #include <binder/RpcServer.h>
27 #include <binder/RpcSession.h>
28 #include <binder/RpcTlsTestUtils.h>
29 #include <binder/RpcTlsUtils.h>
30 #include <binder/RpcTransportRaw.h>
31 #include <binder/RpcTransportTls.h>
32 #include <openssl/ssl.h>
33
34 #include <thread>
35
36 #include <signal.h>
37 #include <sys/prctl.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40
41 using android::BBinder;
42 using android::defaultServiceManager;
43 using android::IBinder;
44 using android::interface_cast;
45 using android::IPCThreadState;
46 using android::IServiceManager;
47 using android::OK;
48 using android::ProcessState;
49 using android::RpcAuthPreSigned;
50 using android::RpcCertificateFormat;
51 using android::RpcCertificateVerifier;
52 using android::RpcCertificateVerifierNoOp;
53 using android::RpcServer;
54 using android::RpcSession;
55 using android::RpcTransportCtxFactory;
56 using android::RpcTransportCtxFactoryRaw;
57 using android::RpcTransportCtxFactoryTls;
58 using android::sp;
59 using android::status_t;
60 using android::statusToString;
61 using android::String16;
62 using android::binder::Status;
63
64 class MyBinderRpcBenchmark : public BnBinderRpcBenchmark {
repeatString(const std::string & str,std::string * out)65 Status repeatString(const std::string& str, std::string* out) override {
66 *out = str;
67 return Status::ok();
68 }
repeatBinder(const sp<IBinder> & binder,sp<IBinder> * out)69 Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
70 *out = binder;
71 return Status::ok();
72 }
repeatBytes(const std::vector<uint8_t> & bytes,std::vector<uint8_t> * out)73 Status repeatBytes(const std::vector<uint8_t>& bytes, std::vector<uint8_t>* out) override {
74 *out = bytes;
75 return Status::ok();
76 }
77
78 class CountedBinder : public BBinder {
79 public:
CountedBinder(const sp<MyBinderRpcBenchmark> & parent)80 CountedBinder(const sp<MyBinderRpcBenchmark>& parent) : mParent(parent) {
81 std::lock_guard<std::mutex> l(mParent->mCountMutex);
82 mParent->mBinderCount++;
83 // std::cout << "Count + is now " << mParent->mBinderCount << std::endl;
84 }
~CountedBinder()85 ~CountedBinder() {
86 {
87 std::lock_guard<std::mutex> l(mParent->mCountMutex);
88 mParent->mBinderCount--;
89 // std::cout << "Count - is now " << mParent->mBinderCount << std::endl;
90
91 // skip notify
92 if (mParent->mBinderCount != 0) return;
93 }
94 mParent->mCountCv.notify_one();
95 }
96
97 private:
98 sp<MyBinderRpcBenchmark> mParent;
99 };
100
gimmeBinder(sp<IBinder> * out)101 Status gimmeBinder(sp<IBinder>* out) override {
102 *out = sp<CountedBinder>::make(sp<MyBinderRpcBenchmark>::fromExisting(this));
103 return Status::ok();
104 }
waitGimmesDestroyed()105 Status waitGimmesDestroyed() override {
106 std::unique_lock<std::mutex> l(mCountMutex);
107 mCountCv.wait(l, [&] { return mBinderCount == 0; });
108 return Status::ok();
109 }
110
111 friend class CountedBinder;
112 std::mutex mCountMutex;
113 std::condition_variable mCountCv;
114 size_t mBinderCount;
115 };
116
117 enum Transport {
118 KERNEL,
119 RPC,
120 RPC_TLS,
121 };
122
123 static const std::initializer_list<int64_t> kTransportList = {
124 #ifdef __BIONIC__
125 Transport::KERNEL,
126 #endif
127 Transport::RPC,
128 Transport::RPC_TLS,
129 };
130
makeFactoryTls()131 std::unique_ptr<RpcTransportCtxFactory> makeFactoryTls() {
132 auto pkey = android::makeKeyPairForSelfSignedCert();
133 CHECK_NE(pkey.get(), nullptr);
134 auto cert = android::makeSelfSignedCert(pkey.get(), android::kCertValidSeconds);
135 CHECK_NE(cert.get(), nullptr);
136
137 auto verifier = std::make_shared<RpcCertificateVerifierNoOp>(OK);
138 auto auth = std::make_unique<RpcAuthPreSigned>(std::move(pkey), std::move(cert));
139 return RpcTransportCtxFactoryTls::make(verifier, std::move(auth));
140 }
141
142 static sp<RpcSession> gSession = RpcSession::make();
143 static sp<IBinder> gRpcBinder;
144 // Certificate validation happens during handshake and does not affect the result of benchmarks.
145 // Skip certificate validation to simplify the setup process.
146 static sp<RpcSession> gSessionTls = RpcSession::make(makeFactoryTls());
147 static sp<IBinder> gRpcTlsBinder;
148 #ifdef __BIONIC__
149 static const String16 kKernelBinderInstance = String16(u"binderRpcBenchmark-control");
150 static sp<IBinder> gKernelBinder;
151 #endif
152
getBinderForOptions(benchmark::State & state)153 static sp<IBinder> getBinderForOptions(benchmark::State& state) {
154 Transport transport = static_cast<Transport>(state.range(0));
155 switch (transport) {
156 #ifdef __BIONIC__
157 case KERNEL:
158 return gKernelBinder;
159 #endif
160 case RPC:
161 return gRpcBinder;
162 case RPC_TLS:
163 return gRpcTlsBinder;
164 default:
165 LOG(FATAL) << "Unknown transport value: " << transport;
166 return nullptr;
167 }
168 }
169
SetLabel(benchmark::State & state)170 static void SetLabel(benchmark::State& state) {
171 Transport transport = static_cast<Transport>(state.range(0));
172 switch (transport) {
173 #ifdef __BIONIC__
174 case KERNEL:
175 state.SetLabel("kernel");
176 break;
177 #endif
178 case RPC:
179 state.SetLabel("rpc");
180 break;
181 case RPC_TLS:
182 state.SetLabel("rpc_tls");
183 break;
184 default:
185 LOG(FATAL) << "Unknown transport value: " << transport;
186 }
187 }
188
BM_pingTransaction(benchmark::State & state)189 void BM_pingTransaction(benchmark::State& state) {
190 sp<IBinder> binder = getBinderForOptions(state);
191
192 while (state.KeepRunning()) {
193 CHECK_EQ(OK, binder->pingBinder());
194 }
195
196 SetLabel(state);
197 }
198 BENCHMARK(BM_pingTransaction)->ArgsProduct({kTransportList});
199
BM_repeatTwoPageString(benchmark::State & state)200 void BM_repeatTwoPageString(benchmark::State& state) {
201 sp<IBinder> binder = getBinderForOptions(state);
202
203 sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
204 CHECK(iface != nullptr);
205
206 // Googlers might see go/another-look-at-aidl-hidl-perf
207 //
208 // When I checked in July 2019, 99.5% of AIDL transactions and 99.99% of HIDL
209 // transactions were less than one page in size (system wide during a test
210 // involving media and camera). This is why this diverges from
211 // binderThroughputTest and hwbinderThroughputTest. Future consideration - get
212 // this data on continuous integration. Here we are testing sending a
213 // transaction of twice this size. In other cases, we should focus on
214 // benchmarks of particular usecases. If individual binder transactions like
215 // the ones tested here are fast, then Android performance will be dominated
216 // by how many binder calls work together (and by factors like the scheduler,
217 // thermal throttling, core choice, etc..).
218 std::string str = std::string(getpagesize() * 2, 'a');
219 CHECK_EQ(static_cast<ssize_t>(str.size()), getpagesize() * 2);
220
221 while (state.KeepRunning()) {
222 std::string out;
223 Status ret = iface->repeatString(str, &out);
224 CHECK(ret.isOk()) << ret;
225 }
226
227 SetLabel(state);
228 }
229 BENCHMARK(BM_repeatTwoPageString)->ArgsProduct({kTransportList});
230
BM_throughputForTransportAndBytes(benchmark::State & state)231 void BM_throughputForTransportAndBytes(benchmark::State& state) {
232 sp<IBinder> binder = getBinderForOptions(state);
233 sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
234 CHECK(iface != nullptr);
235
236 std::vector<uint8_t> bytes = std::vector<uint8_t>(state.range(1));
237 for (size_t i = 0; i < bytes.size(); i++) {
238 bytes[i] = i % 256;
239 }
240
241 while (state.KeepRunning()) {
242 std::vector<uint8_t> out;
243 Status ret = iface->repeatBytes(bytes, &out);
244 CHECK(ret.isOk()) << ret;
245 }
246
247 SetLabel(state);
248 }
249 BENCHMARK(BM_throughputForTransportAndBytes)
250 ->ArgsProduct({kTransportList,
251 {64, 1024, 2048, 4096, 8182, 16364, 32728, 65535, 65536, 65537}});
252
BM_collectProxies(benchmark::State & state)253 void BM_collectProxies(benchmark::State& state) {
254 sp<IBinder> binder = getBinderForOptions(state);
255 sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
256 CHECK(iface != nullptr);
257
258 const size_t kNumIters = state.range(1);
259
260 while (state.KeepRunning()) {
261 std::vector<sp<IBinder>> out;
262 out.resize(kNumIters);
263
264 for (size_t i = 0; i < kNumIters; i++) {
265 Status ret = iface->gimmeBinder(&out[i]);
266 CHECK(ret.isOk()) << ret;
267 }
268
269 out.clear();
270
271 // we are using a thread up to wait, so make a call to
272 // force all refcounts to be updated first - current
273 // binder behavior means we really don't need to wait,
274 // so code which is waiting is really there to protect
275 // against any future changes that could delay destruction
276 android::IInterface::asBinder(iface)->pingBinder();
277
278 iface->waitGimmesDestroyed();
279 }
280
281 SetLabel(state);
282 }
283 BENCHMARK(BM_collectProxies)->ArgsProduct({kTransportList, {10, 100, 1000, 5000, 10000, 20000}});
284
BM_repeatBinder(benchmark::State & state)285 void BM_repeatBinder(benchmark::State& state) {
286 sp<IBinder> binder = getBinderForOptions(state);
287 CHECK(binder != nullptr);
288 sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
289 CHECK(iface != nullptr);
290
291 while (state.KeepRunning()) {
292 // force creation of a new address
293 sp<IBinder> binder = sp<BBinder>::make();
294
295 sp<IBinder> out;
296 Status ret = iface->repeatBinder(binder, &out);
297 CHECK(ret.isOk()) << ret;
298 }
299
300 SetLabel(state);
301 }
302 BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList});
303
forkRpcServer(const char * addr,const sp<RpcServer> & server)304 void forkRpcServer(const char* addr, const sp<RpcServer>& server) {
305 if (0 == fork()) {
306 prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
307 server->setRootObject(sp<MyBinderRpcBenchmark>::make());
308 CHECK_EQ(OK, server->setupUnixDomainServer(addr));
309 server->join();
310 exit(1);
311 }
312 }
313
setupClient(const sp<RpcSession> & session,const char * addr)314 void setupClient(const sp<RpcSession>& session, const char* addr) {
315 status_t status;
316 for (size_t tries = 0; tries < 5; tries++) {
317 usleep(10000);
318 status = session->setupUnixDomainClient(addr);
319 if (status == OK) break;
320 }
321 CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
322 }
323
main(int argc,char ** argv)324 int main(int argc, char** argv) {
325 ::benchmark::Initialize(&argc, argv);
326 if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
327
328 #ifdef __BIONIC__
329 if (0 == fork()) {
330 prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
331 CHECK_EQ(OK,
332 defaultServiceManager()->addService(kKernelBinderInstance,
333 sp<MyBinderRpcBenchmark>::make()));
334 IPCThreadState::self()->joinThreadPool();
335 exit(1);
336 }
337
338 ProcessState::self()->setThreadPoolMaxThreadCount(1);
339 ProcessState::self()->startThreadPool();
340
341 gKernelBinder = defaultServiceManager()->waitForService(kKernelBinderInstance);
342 CHECK_NE(nullptr, gKernelBinder.get());
343 #endif
344
345 std::string tmp = getenv("TMPDIR") ?: "/tmp";
346
347 std::string addr = tmp + "/binderRpcBenchmark";
348 (void)unlink(addr.c_str());
349 forkRpcServer(addr.c_str(), RpcServer::make(RpcTransportCtxFactoryRaw::make()));
350 setupClient(gSession, addr.c_str());
351 gRpcBinder = gSession->getRootObject();
352
353 std::string tlsAddr = tmp + "/binderRpcTlsBenchmark";
354 (void)unlink(tlsAddr.c_str());
355 forkRpcServer(tlsAddr.c_str(), RpcServer::make(makeFactoryTls()));
356 setupClient(gSessionTls, tlsAddr.c_str());
357 gRpcTlsBinder = gSessionTls->getRootObject();
358
359 ::benchmark::RunSpecifiedBenchmarks();
360 return 0;
361 }
362