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_addInts(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_addInts(benchmark::State& state)
109 sp<IServiceManager> sm = defaultServiceManager();
111 // If needed bind to client CPU
112 if (options.clientCPU != unbound) { bindCPU(options.clientCPU); }
116 for (int i = 0; i < 3; i++) {
117 binder = sm->getService(serviceName);
118 if (binder != 0) break;
119 cout << serviceName << " not published, waiting..." << endl;
120 usleep(500000); // 0.5 s
124 cout << serviceName << " failed to publish, aborting" << endl;
128 unsigned int iter = 0;
129 // Perform the IPC operations in the benchmark
130 while (state.KeepRunning()) {
133 // Create parcel to be sent. Will use the iteration cound
134 // and the iteration count + 3 as the two integer values
139 int expected = val1 + val2; // Expect to get the sum back
140 send.writeInt32(val1);
141 send.writeInt32(val2);
142 state.ResumeTiming();
143 // Send the parcel, while timing how long it takes for
144 // the answer to return.
145 if ((rv = binder->transact(AddIntsService::ADD_INTS,
146 send, &reply)) != 0) {
147 cerr << "binder->transact failed, rv: " << rv
148 << " errno: " << errno << endl;
153 int result = reply.readInt32();
154 if (result != (int) (iter + iter + 3)) {
155 cerr << "Unexpected result for iteration " << iter << endl;
156 cerr << " result: " << result << endl;
157 cerr << "expected: " << expected << endl;
160 if (options.iterDelay > 0.0) { testDelaySpin(options.iterDelay); }
161 state.ResumeTiming();
164 BENCHMARK(BM_addInts);
167 AddIntsService::AddIntsService(int cpu): cpu_(cpu) {
168 if (cpu != unbound) { bindCPU(cpu); }
171 // Server function that handles parcels received from the client
172 status_t AddIntsService::onTransact(uint32_t code, const Parcel &data,
173 Parcel* reply, uint32_t /* flags */) {
178 // If server bound to a particular CPU, check that
179 // were executing on that CPU.
180 if (cpu_ != unbound) {
181 cpu = sched_getcpu();
183 cerr << "server onTransact on CPU " << cpu << " expected CPU "
189 // Perform the requested operation
192 val1 = data.readInt32();
193 val2 = data.readInt32();
194 reply->writeInt32(val1 + val2);
198 cerr << "server onTransact unknown code, code: " << code << endl;
205 static void bindCPU(unsigned int cpu)
211 CPU_SET(cpu, &cpuset);
212 rv = sched_setaffinity(0, sizeof(cpuset), &cpuset);
215 cerr << "bindCPU failed, rv: " << rv << " errno: " << errno << endl;
221 static ostream &operator<<(ostream &stream, const String16& str)
223 for (unsigned int n1 = 0; n1 < str.size(); n1++) {
224 if ((str[n1] > 0x20) && (str[n1] < 0x80)) {
225 stream << (char) str[n1];
234 static ostream &operator<<(ostream &stream, const cpu_set_t& set)
236 for (unsigned int n1 = 0; n1 < CPU_SETSIZE; n1++) {
237 if (CPU_ISSET(n1, &set)) {
238 if (n1 != 0) { stream << ' '; }
246 int main(int argc, char *argv[])
249 ::benchmark::Initialize(&argc, argv);
250 // Determine CPUs available for use.
251 // This testcase limits its self to using CPUs that were
252 // available at the start of the benchmark.
254 if ((rv = sched_getaffinity(0, sizeof(availCPUs), &availCPUs)) != 0) {
255 cerr << "sched_getaffinity failure, rv: " << rv
256 << " errno: " << errno << endl;
260 // Parse command line arguments
262 while ((opt = getopt(argc, argv, "s:c:d:?")) != -1) {
263 char *chptr; // character pointer for command-line parsing
266 case 'c': // client CPU
267 case 's': { // server CPU
268 // Parse the CPU number
269 int cpu = strtoul(optarg, &chptr, 10);
270 if (*chptr != '\0') {
271 cerr << "Invalid cpu specified for -" << (char) opt
272 << " option of: " << optarg << endl;
276 // Is the CPU available?
277 if (!CPU_ISSET(cpu, &availCPUs)) {
278 cerr << "CPU " << optarg << " not currently available" << endl;
279 cerr << " Available CPUs: " << availCPUs << endl;
284 *((opt == 'c') ? &options.clientCPU : &options.serverCPU) = cpu;
288 case 'd': // delay between each iteration
289 options.iterDelay = strtod(optarg, &chptr);
290 if ((*chptr != '\0') || (options.iterDelay < 0.0)) {
291 cerr << "Invalid delay specified of: " << optarg << endl;
298 cerr << basename(argv[0]) << " [options]" << endl;
299 cerr << " options:" << endl;
300 cerr << " -s cpu - server CPU number" << endl;
301 cerr << " -c cpu - client CPU number" << endl;
302 cerr << " -d time - delay after operation in seconds" << endl;
303 exit(((optopt == 0) || (optopt == '?')) ? 0 : 7);
308 switch (pid_t pid = fork()) {
310 ::benchmark::RunSpecifiedBenchmarks();
314 if (!server()) { break; }
316 // Wait for all children to end
320 if ((rv == -1) && (errno == ECHILD)) { break; }
322 cerr << "wait failed, rv: " << rv << " errno: "