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_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); 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_addInts(benchmark::State& state) 107 { 108 int rv; 109 sp<IServiceManager> sm = defaultServiceManager(); 110 111 // If needed bind to client CPU 112 if (options.clientCPU != unbound) { bindCPU(options.clientCPU); } 113 114 // Attach to service 115 sp<IBinder> binder; 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 121 } 122 123 if (binder == 0) { 124 cout << serviceName << " failed to publish, aborting" << endl; 125 return; 126 } 127 128 unsigned int iter = 0; 129 // Perform the IPC operations in the benchmark 130 while (state.KeepRunning()) { 131 Parcel send, reply; 132 133 // Create parcel to be sent. Will use the iteration cound 134 // and the iteration count + 3 as the two integer values 135 // to be sent. 136 state.PauseTiming(); 137 int val1 = iter; 138 int val2 = iter + 3; 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; 149 exit(10); 150 } 151 152 state.PauseTiming(); 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; 158 } 159 160 if (options.iterDelay > 0.0) { testDelaySpin(options.iterDelay); } 161 state.ResumeTiming(); 162 } 163 } 164 BENCHMARK(BM_addInts); 165 166 167 AddIntsService::AddIntsService(int cpu): cpu_(cpu) { 168 if (cpu != unbound) { bindCPU(cpu); } 169 } 170 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 */) { 174 int val1, val2; 175 status_t rv(0); 176 int cpu; 177 178 // If server bound to a particular CPU, check that 179 // were executing on that CPU. 180 if (cpu_ != unbound) { 181 cpu = sched_getcpu(); 182 if (cpu != cpu_) { 183 cerr << "server onTransact on CPU " << cpu << " expected CPU " 184 << cpu_ << endl; 185 exit(20); 186 } 187 } 188 189 // Perform the requested operation 190 switch (code) { 191 case ADD_INTS: 192 val1 = data.readInt32(); 193 val2 = data.readInt32(); 194 reply->writeInt32(val1 + val2); 195 break; 196 197 default: 198 cerr << "server onTransact unknown code, code: " << code << endl; 199 exit(21); 200 } 201 202 return rv; 203 } 204 205 static void bindCPU(unsigned int cpu) 206 { 207 int rv; 208 cpu_set_t cpuset; 209 210 CPU_ZERO(&cpuset); 211 CPU_SET(cpu, &cpuset); 212 rv = sched_setaffinity(0, sizeof(cpuset), &cpuset); 213 214 if (rv != 0) { 215 cerr << "bindCPU failed, rv: " << rv << " errno: " << errno << endl; 216 perror(NULL); 217 exit(30); 218 } 219 } 220 221 static ostream &operator<<(ostream &stream, const String16& str) 222 { 223 for (unsigned int n1 = 0; n1 < str.size(); n1++) { 224 if ((str[n1] > 0x20) && (str[n1] < 0x80)) { 225 stream << (char) str[n1]; 226 } else { 227 stream << '~'; 228 } 229 } 230 231 return stream; 232 } 233 234 static ostream &operator<<(ostream &stream, const cpu_set_t& set) 235 { 236 for (unsigned int n1 = 0; n1 < CPU_SETSIZE; n1++) { 237 if (CPU_ISSET(n1, &set)) { 238 if (n1 != 0) { stream << ' '; } 239 stream << n1; 240 } 241 } 242 243 return stream; 244 } 245 246 int main(int argc, char *argv[]) 247 { 248 int rv; 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. 253 cpu_set_t availCPUs; 254 if ((rv = sched_getaffinity(0, sizeof(availCPUs), &availCPUs)) != 0) { 255 cerr << "sched_getaffinity failure, rv: " << rv 256 << " errno: " << errno << endl; 257 exit(1); 258 } 259 260 // Parse command line arguments 261 int opt; 262 while ((opt = getopt(argc, argv, "s:c:d:?")) != -1) { 263 char *chptr; // character pointer for command-line parsing 264 265 switch (opt) { 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; 273 exit(2); 274 } 275 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; 280 exit(3); 281 } 282 283 // Record the choice 284 *((opt == 'c') ? &options.clientCPU : &options.serverCPU) = cpu; 285 break; 286 } 287 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; 292 exit(6); 293 } 294 break; 295 296 case '?': 297 default: 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); 304 } 305 } 306 307 fflush(stdout); 308 switch (pid_t pid = fork()) { 309 case 0: // Child 310 ::benchmark::RunSpecifiedBenchmarks(); 311 return 0; 312 313 default: // Parent 314 if (!server()) { break; } 315 316 // Wait for all children to end 317 do { 318 int stat; 319 rv = wait(&stat); 320 if ((rv == -1) && (errno == ECHILD)) { break; } 321 if (rv == -1) { 322 cerr << "wait failed, rv: " << rv << " errno: " 323 << errno << endl; 324 perror(NULL); 325 exit(8); 326 } 327 } while (1); 328 return 0; 329 330 case -1: // Error 331 exit(9); 332 } 333 } 334