OSDN Git Service

ANRdaemon: add README and a bash script to easily get trace. am: 9e90477a67
[android-x86/system-extras.git] / tests / binder / benchmarks / binderAddInts.cpp
1 /*
2  * Copyright (C) 2010 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
18 /*
19  * Binder add integers benchmark (Using google-benchmark library)
20  *
21  */
22
23 #include <cerrno>
24 #include <grp.h>
25 #include <iostream>
26 #include <iomanip>
27 #include <libgen.h>
28 #include <time.h>
29 #include <unistd.h>
30
31 #include <sys/syscall.h>
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/wait.h>
35
36 #include <binder/IPCThreadState.h>
37 #include <binder/ProcessState.h>
38 #include <binder/IServiceManager.h>
39
40 #include <benchmark/benchmark.h>
41
42 #include <utils/Log.h>
43 #include <testUtil.h>
44
45 using namespace android;
46 using namespace std;
47
48 const int unbound = -1; // Indicator for a thread not bound to a specific CPU
49
50 String16 serviceName("test.binderAddInts");
51
52 struct options {
53     int serverCPU;
54     int clientCPU;
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
60 };
61
62 class AddIntsService : public BBinder
63 {
64   public:
65     AddIntsService(int cpu = unbound);
66     virtual ~AddIntsService() {}
67
68     enum command {
69         ADD_INTS = 0x120,
70     };
71
72     virtual status_t onTransact(uint32_t code,
73                                 const Parcel& data, Parcel* reply,
74                                 uint32_t flags = 0);
75
76   private:
77     int cpu_;
78 };
79
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);
86
87 static bool server(void)
88 {
89     int rv;
90
91     // Add the service
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;
98         return false;
99     }
100
101     // Start threads to handle server work
102     proc->startThreadPool();
103     return true;
104 }
105
106 static void BM_client(benchmark::State& state)
107 {
108     server();
109     int rv;
110     sp<IServiceManager> sm = defaultServiceManager();
111
112     // If needed bind to client CPU
113     if (options.clientCPU != unbound) { bindCPU(options.clientCPU); }
114
115     // Attach to service
116     sp<IBinder> binder;
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
122     }
123
124     if (binder == 0) {
125         cout << serviceName << " failed to publish, aborting" << endl;
126         return;
127     }
128
129     unsigned int iter = 0;
130     // Perform the IPC operations in the benchmark
131     while (state.KeepRunning()) {
132         Parcel send, reply;
133
134         // Create parcel to be sent.  Will use the iteration cound
135         // and the iteration count + 3 as the two integer values
136         // to be sent.
137         state.PauseTiming();
138         int val1 = iter;
139         int val2 = iter + 3;
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;
150             exit(10);
151         }
152
153         state.PauseTiming();
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;
159         }
160
161         if (options.iterDelay > 0.0) { testDelaySpin(options.iterDelay); }
162         state.ResumeTiming();
163     }
164 }
165 BENCHMARK(BM_client);
166
167
168 AddIntsService::AddIntsService(int cpu): cpu_(cpu) {
169     if (cpu != unbound) { bindCPU(cpu); }
170 }
171
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 */) {
175     int val1, val2;
176     status_t rv(0);
177     int cpu;
178
179     // If server bound to a particular CPU, check that
180     // were executing on that CPU.
181     if (cpu_ != unbound) {
182         cpu = sched_getcpu();
183         if (cpu != cpu_) {
184             cerr << "server onTransact on CPU " << cpu << " expected CPU "
185                   << cpu_ << endl;
186             exit(20);
187         }
188     }
189
190     // Perform the requested operation
191     switch (code) {
192     case ADD_INTS:
193         val1 = data.readInt32();
194         val2 = data.readInt32();
195         reply->writeInt32(val1 + val2);
196         break;
197
198     default:
199       cerr << "server onTransact unknown code, code: " << code << endl;
200       exit(21);
201     }
202
203     return rv;
204 }
205
206 static void bindCPU(unsigned int cpu)
207 {
208     int rv;
209     cpu_set_t cpuset;
210
211     CPU_ZERO(&cpuset);
212     CPU_SET(cpu, &cpuset);
213     rv = sched_setaffinity(0, sizeof(cpuset), &cpuset);
214
215     if (rv != 0) {
216         cerr << "bindCPU failed, rv: " << rv << " errno: " << errno << endl;
217         perror(NULL);
218         exit(30);
219     }
220 }
221
222 static ostream &operator<<(ostream &stream, const String16& str)
223 {
224     for (unsigned int n1 = 0; n1 < str.size(); n1++) {
225         if ((str[n1] > 0x20) && (str[n1] < 0x80)) {
226             stream << (char) str[n1];
227         } else {
228             stream << '~';
229         }
230     }
231
232     return stream;
233 }
234
235 static ostream &operator<<(ostream &stream, const cpu_set_t& set)
236 {
237     for (unsigned int n1 = 0; n1 < CPU_SETSIZE; n1++) {
238         if (CPU_ISSET(n1, &set)) {
239             if (n1 != 0) { stream << ' '; }
240             stream << n1;
241         }
242     }
243
244     return stream;
245 }
246
247 int main(int argc, char *argv[])
248 {
249     int rv;
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.
254     cpu_set_t availCPUs;
255     if ((rv = sched_getaffinity(0, sizeof(availCPUs), &availCPUs)) != 0) {
256         cerr << "sched_getaffinity failure, rv: " << rv
257             << " errno: " << errno << endl;
258         exit(1);
259     }
260
261     // Parse command line arguments
262     int opt;
263     while ((opt = getopt(argc, argv, "s:c:d:?")) != -1) {
264         char *chptr; // character pointer for command-line parsing
265
266         switch (opt) {
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;
274                 exit(2);
275             }
276
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;
281                 exit(3);
282             }
283
284             // Record the choice
285             *((opt == 'c') ? &options.clientCPU : &options.serverCPU) = cpu;
286             break;
287         }
288
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;
293                 exit(6);
294             }
295             break;
296
297         case '?':
298         default:
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);
305         }
306     }
307
308     ::benchmark::RunSpecifiedBenchmarks();
309 }
310