• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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