2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * Binder add integers benchmark (Using google-benchmark library)
31 #include <sys/syscall.h>
33 #include <sys/types.h>
36 #include <binder/IPCThreadState.h>
37 #include <binder/ProcessState.h>
38 #include <binder/IServiceManager.h>
40 #include <benchmark/benchmark.h>
42 #include <utils/Log.h>
45 using namespace android;
48 const int unbound = -1; // Indicator for a thread not bound to a specific CPU
50 String16 serviceName("test.binderAddInts");
55 float iterDelay; // End of iteration delay in seconds
56 } options = { // Set defaults
57 unbound, // Server CPU
58 unbound, // Client CPU
59 0.0, // End of iteration delay
62 class AddIntsService : public BBinder
65 AddIntsService(int cpu = unbound);
66 virtual ~AddIntsService() {}
72 virtual status_t onTransact(uint32_t code,
73 const Parcel& data, Parcel* reply,
80 // File scope function prototypes
81 static bool server(void);
82 static void BM_client(benchmark::State& state);
83 static void bindCPU(unsigned int cpu);
84 static ostream &operator<<(ostream &stream, const String16& str);
85 static ostream &operator<<(ostream &stream, const cpu_set_t& set);
87 static bool server(void)
92 sp<ProcessState> proc(ProcessState::self());
93 sp<IServiceManager> sm = defaultServiceManager();
94 if ((rv = sm->addService(serviceName,
95 new AddIntsService(options.serverCPU))) != 0) {
96 cerr << "addService " << serviceName << " failed, rv: " << rv
97 << " errno: " << errno << endl;
101 // Start threads to handle server work
102 proc->startThreadPool();
106 static void BM_client(benchmark::State& state)
110 sp<IServiceManager> sm = defaultServiceManager();
112 // If needed bind to client CPU
113 if (options.clientCPU != unbound) { bindCPU(options.clientCPU); }
117 for (int i = 0; i < 3; i++) {
118 binder = sm->getService(serviceName);
119 if (binder != 0) break;
120 cout << serviceName << " not published, waiting..." << endl;
121 usleep(500000); // 0.5 s
125 cout << serviceName << " failed to publish, aborting" << endl;
129 unsigned int iter = 0;
130 // Perform the IPC operations in the benchmark
131 while (state.KeepRunning()) {
134 // Create parcel to be sent. Will use the iteration cound
135 // and the iteration count + 3 as the two integer values
140 int expected = val1 + val2; // Expect to get the sum back
141 send.writeInt32(val1);
142 send.writeInt32(val2);
143 state.ResumeTiming();
144 // Send the parcel, while timing how long it takes for
145 // the answer to return.
146 if ((rv = binder->transact(AddIntsService::ADD_INTS,
147 send, &reply)) != 0) {
148 cerr << "binder->transact failed, rv: " << rv
149 << " errno: " << errno << endl;
154 int result = reply.readInt32();
155 if (result != (int) (iter + iter + 3)) {
156 cerr << "Unexpected result for iteration " << iter << endl;
157 cerr << " result: " << result << endl;
158 cerr << "expected: " << expected << endl;
161 if (options.iterDelay > 0.0) { testDelaySpin(options.iterDelay); }
162 state.ResumeTiming();
165 BENCHMARK(BM_client);
168 AddIntsService::AddIntsService(int cpu): cpu_(cpu) {
169 if (cpu != unbound) { bindCPU(cpu); }
172 // Server function that handles parcels received from the client
173 status_t AddIntsService::onTransact(uint32_t code, const Parcel &data,
174 Parcel* reply, uint32_t /* flags */) {
179 // If server bound to a particular CPU, check that
180 // were executing on that CPU.
181 if (cpu_ != unbound) {
182 cpu = sched_getcpu();
184 cerr << "server onTransact on CPU " << cpu << " expected CPU "
190 // Perform the requested operation
193 val1 = data.readInt32();
194 val2 = data.readInt32();
195 reply->writeInt32(val1 + val2);
199 cerr << "server onTransact unknown code, code: " << code << endl;
206 static void bindCPU(unsigned int cpu)
212 CPU_SET(cpu, &cpuset);
213 rv = sched_setaffinity(0, sizeof(cpuset), &cpuset);
216 cerr << "bindCPU failed, rv: " << rv << " errno: " << errno << endl;
222 static ostream &operator<<(ostream &stream, const String16& str)
224 for (unsigned int n1 = 0; n1 < str.size(); n1++) {
225 if ((str[n1] > 0x20) && (str[n1] < 0x80)) {
226 stream << (char) str[n1];
235 static ostream &operator<<(ostream &stream, const cpu_set_t& set)
237 for (unsigned int n1 = 0; n1 < CPU_SETSIZE; n1++) {
238 if (CPU_ISSET(n1, &set)) {
239 if (n1 != 0) { stream << ' '; }
247 int main(int argc, char *argv[])
250 ::benchmark::Initialize(&argc, argv);
251 // Determine CPUs available for use.
252 // This testcase limits its self to using CPUs that were
253 // available at the start of the benchmark.
255 if ((rv = sched_getaffinity(0, sizeof(availCPUs), &availCPUs)) != 0) {
256 cerr << "sched_getaffinity failure, rv: " << rv
257 << " errno: " << errno << endl;
261 // Parse command line arguments
263 while ((opt = getopt(argc, argv, "s:c:d:?")) != -1) {
264 char *chptr; // character pointer for command-line parsing
267 case 'c': // client CPU
268 case 's': { // server CPU
269 // Parse the CPU number
270 int cpu = strtoul(optarg, &chptr, 10);
271 if (*chptr != '\0') {
272 cerr << "Invalid cpu specified for -" << (char) opt
273 << " option of: " << optarg << endl;
277 // Is the CPU available?
278 if (!CPU_ISSET(cpu, &availCPUs)) {
279 cerr << "CPU " << optarg << " not currently available" << endl;
280 cerr << " Available CPUs: " << availCPUs << endl;
285 *((opt == 'c') ? &options.clientCPU : &options.serverCPU) = cpu;
289 case 'd': // delay between each iteration
290 options.iterDelay = strtod(optarg, &chptr);
291 if ((*chptr != '\0') || (options.iterDelay < 0.0)) {
292 cerr << "Invalid delay specified of: " << optarg << endl;
299 cerr << basename(argv[0]) << " [options]" << endl;
300 cerr << " options:" << endl;
301 cerr << " -s cpu - server CPU number" << endl;
302 cerr << " -c cpu - client CPU number" << endl;
303 cerr << " -d time - delay after operation in seconds" << endl;
304 exit(((optopt == 0) || (optopt == '?')) ? 0 : 7);
308 ::benchmark::RunSpecifiedBenchmarks();