123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- /*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- /*
- * Binder add integers benchmark (Using google-benchmark library)
- *
- */
- #include <cerrno>
- #include <grp.h>
- #include <iostream>
- #include <iomanip>
- #include <libgen.h>
- #include <time.h>
- #include <unistd.h>
- #include <sys/syscall.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <binder/IPCThreadState.h>
- #include <binder/ProcessState.h>
- #include <binder/IServiceManager.h>
- #include <benchmark/benchmark.h>
- #include <utils/Log.h>
- #include <testUtil.h>
- using namespace android;
- using namespace std;
- const int unbound = -1; // Indicator for a thread not bound to a specific CPU
- String16 serviceName("test.binderAddInts");
- struct options {
- int serverCPU;
- int clientCPU;
- float iterDelay; // End of iteration delay in seconds
- } options = { // Set defaults
- unbound, // Server CPU
- unbound, // Client CPU
- 0.0, // End of iteration delay
- };
- class AddIntsService : public BBinder
- {
- public:
- explicit AddIntsService(int cpu = unbound);
- virtual ~AddIntsService() {}
- enum command {
- ADD_INTS = 0x120,
- };
- virtual status_t onTransact(uint32_t code,
- const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
- private:
- int cpu_;
- };
- // File scope function prototypes
- static bool server(void);
- static void BM_addInts(benchmark::State& state);
- static void bindCPU(unsigned int cpu);
- static ostream &operator<<(ostream &stream, const String16& str);
- static ostream &operator<<(ostream &stream, const cpu_set_t& set);
- static bool server(void)
- {
- int rv;
- // Add the service
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- if ((rv = sm->addService(serviceName,
- new AddIntsService(options.serverCPU))) != 0) {
- cerr << "addService " << serviceName << " failed, rv: " << rv
- << " errno: " << errno << endl;
- return false;
- }
- // Start threads to handle server work
- proc->startThreadPool();
- return true;
- }
- static void BM_addInts(benchmark::State& state)
- {
- int rv;
- sp<IServiceManager> sm = defaultServiceManager();
- // If needed bind to client CPU
- if (options.clientCPU != unbound) { bindCPU(options.clientCPU); }
- // Attach to service
- sp<IBinder> binder;
- for (int i = 0; i < 3; i++) {
- binder = sm->getService(serviceName);
- if (binder != 0) break;
- cout << serviceName << " not published, waiting..." << endl;
- usleep(500000); // 0.5 s
- }
- if (binder == 0) {
- cout << serviceName << " failed to publish, aborting" << endl;
- return;
- }
- unsigned int iter = 0;
- // Perform the IPC operations in the benchmark
- while (state.KeepRunning()) {
- Parcel send, reply;
- // Create parcel to be sent. Will use the iteration cound
- // and the iteration count + 3 as the two integer values
- // to be sent.
- state.PauseTiming();
- int val1 = iter;
- int val2 = iter + 3;
- int expected = val1 + val2; // Expect to get the sum back
- send.writeInt32(val1);
- send.writeInt32(val2);
- state.ResumeTiming();
- // Send the parcel, while timing how long it takes for
- // the answer to return.
- if ((rv = binder->transact(AddIntsService::ADD_INTS,
- send, &reply)) != 0) {
- cerr << "binder->transact failed, rv: " << rv
- << " errno: " << errno << endl;
- exit(10);
- }
- state.PauseTiming();
- int result = reply.readInt32();
- if (result != (int) (iter + iter + 3)) {
- cerr << "Unexpected result for iteration " << iter << endl;
- cerr << " result: " << result << endl;
- cerr << "expected: " << expected << endl;
- }
- if (options.iterDelay > 0.0) { testDelaySpin(options.iterDelay); }
- state.ResumeTiming();
- }
- }
- BENCHMARK(BM_addInts);
- AddIntsService::AddIntsService(int cpu): cpu_(cpu) {
- if (cpu != unbound) { bindCPU(cpu); }
- }
- // Server function that handles parcels received from the client
- status_t AddIntsService::onTransact(uint32_t code, const Parcel &data,
- Parcel* reply, uint32_t /* flags */) {
- int val1, val2;
- status_t rv(0);
- int cpu;
- // If server bound to a particular CPU, check that
- // were executing on that CPU.
- if (cpu_ != unbound) {
- cpu = sched_getcpu();
- if (cpu != cpu_) {
- cerr << "server onTransact on CPU " << cpu << " expected CPU "
- << cpu_ << endl;
- exit(20);
- }
- }
- // Perform the requested operation
- switch (code) {
- case ADD_INTS:
- val1 = data.readInt32();
- val2 = data.readInt32();
- reply->writeInt32(val1 + val2);
- break;
- default:
- cerr << "server onTransact unknown code, code: " << code << endl;
- exit(21);
- }
- return rv;
- }
- static void bindCPU(unsigned int cpu)
- {
- int rv;
- cpu_set_t cpuset;
- CPU_ZERO(&cpuset);
- CPU_SET(cpu, &cpuset);
- rv = sched_setaffinity(0, sizeof(cpuset), &cpuset);
- if (rv != 0) {
- cerr << "bindCPU failed, rv: " << rv << " errno: " << errno << endl;
- perror(NULL);
- exit(30);
- }
- }
- static ostream &operator<<(ostream &stream, const String16& str)
- {
- for (unsigned int n1 = 0; n1 < str.size(); n1++) {
- if ((str[n1] > 0x20) && (str[n1] < 0x80)) {
- stream << (char) str[n1];
- } else {
- stream << '~';
- }
- }
- return stream;
- }
- static ostream &operator<<(ostream &stream, const cpu_set_t& set)
- {
- for (unsigned int n1 = 0; n1 < CPU_SETSIZE; n1++) {
- if (CPU_ISSET(n1, &set)) {
- if (n1 != 0) { stream << ' '; }
- stream << n1;
- }
- }
- return stream;
- }
- int main(int argc, char *argv[])
- {
- int rv;
- ::benchmark::Initialize(&argc, argv);
- // Determine CPUs available for use.
- // This testcase limits its self to using CPUs that were
- // available at the start of the benchmark.
- cpu_set_t availCPUs;
- if ((rv = sched_getaffinity(0, sizeof(availCPUs), &availCPUs)) != 0) {
- cerr << "sched_getaffinity failure, rv: " << rv
- << " errno: " << errno << endl;
- exit(1);
- }
- // Parse command line arguments
- int opt;
- while ((opt = getopt(argc, argv, "s:c:d:?")) != -1) {
- char *chptr; // character pointer for command-line parsing
- switch (opt) {
- case 'c': // client CPU
- case 's': { // server CPU
- // Parse the CPU number
- int cpu = strtoul(optarg, &chptr, 10);
- if (*chptr != '\0') {
- cerr << "Invalid cpu specified for -" << (char) opt
- << " option of: " << optarg << endl;
- exit(2);
- }
- // Is the CPU available?
- if (!CPU_ISSET(cpu, &availCPUs)) {
- cerr << "CPU " << optarg << " not currently available" << endl;
- cerr << " Available CPUs: " << availCPUs << endl;
- exit(3);
- }
- // Record the choice
- *((opt == 'c') ? &options.clientCPU : &options.serverCPU) = cpu;
- break;
- }
- case 'd': // delay between each iteration
- options.iterDelay = strtod(optarg, &chptr);
- if ((*chptr != '\0') || (options.iterDelay < 0.0)) {
- cerr << "Invalid delay specified of: " << optarg << endl;
- exit(6);
- }
- break;
- case '?':
- default:
- cerr << basename(argv[0]) << " [options]" << endl;
- cerr << " options:" << endl;
- cerr << " -s cpu - server CPU number" << endl;
- cerr << " -c cpu - client CPU number" << endl;
- cerr << " -d time - delay after operation in seconds" << endl;
- exit(((optopt == 0) || (optopt == '?')) ? 0 : 7);
- }
- }
- fflush(stdout);
- switch (pid_t pid = fork()) {
- case 0: // Child
- ::benchmark::RunSpecifiedBenchmarks();
- return 0;
- default: // Parent
- if (!server()) { break; }
- // Wait for all children to end
- do {
- int stat;
- rv = wait(&stat);
- if ((rv == -1) && (errno == ECHILD)) { break; }
- if (rv == -1) {
- cerr << "wait failed, rv: " << rv << " errno: "
- << errno << endl;
- perror(NULL);
- exit(8);
- }
- } while (1);
- return 0;
- case -1: // Error
- exit(9);
- }
- }
|