1*38e8c45fSAndroid Build Coastguard Worker #include <binder/Binder.h>
2*38e8c45fSAndroid Build Coastguard Worker #include <binder/IBinder.h>
3*38e8c45fSAndroid Build Coastguard Worker #include <binder/IPCThreadState.h>
4*38e8c45fSAndroid Build Coastguard Worker #include <binder/IServiceManager.h>
5*38e8c45fSAndroid Build Coastguard Worker #include <cstdio>
6*38e8c45fSAndroid Build Coastguard Worker #include <cstdlib>
7*38e8c45fSAndroid Build Coastguard Worker #include <cstring>
8*38e8c45fSAndroid Build Coastguard Worker #include <string>
9*38e8c45fSAndroid Build Coastguard Worker
10*38e8c45fSAndroid Build Coastguard Worker #include <iomanip>
11*38e8c45fSAndroid Build Coastguard Worker #include <iostream>
12*38e8c45fSAndroid Build Coastguard Worker #include <tuple>
13*38e8c45fSAndroid Build Coastguard Worker #include <vector>
14*38e8c45fSAndroid Build Coastguard Worker
15*38e8c45fSAndroid Build Coastguard Worker #include <pthread.h>
16*38e8c45fSAndroid Build Coastguard Worker #include <sys/wait.h>
17*38e8c45fSAndroid Build Coastguard Worker #include <unistd.h>
18*38e8c45fSAndroid Build Coastguard Worker #include <fstream>
19*38e8c45fSAndroid Build Coastguard Worker
20*38e8c45fSAndroid Build Coastguard Worker using namespace std;
21*38e8c45fSAndroid Build Coastguard Worker using namespace android;
22*38e8c45fSAndroid Build Coastguard Worker
23*38e8c45fSAndroid Build Coastguard Worker enum BinderWorkerServiceCode {
24*38e8c45fSAndroid Build Coastguard Worker BINDER_NOP = IBinder::FIRST_CALL_TRANSACTION,
25*38e8c45fSAndroid Build Coastguard Worker };
26*38e8c45fSAndroid Build Coastguard Worker
27*38e8c45fSAndroid Build Coastguard Worker #define ASSERT(cond) \
28*38e8c45fSAndroid Build Coastguard Worker do { \
29*38e8c45fSAndroid Build Coastguard Worker if (!(cond)) { \
30*38e8c45fSAndroid Build Coastguard Worker cerr << __func__ << ":" << __LINE__ << " condition:" << #cond \
31*38e8c45fSAndroid Build Coastguard Worker << " failed\n" \
32*38e8c45fSAndroid Build Coastguard Worker << endl; \
33*38e8c45fSAndroid Build Coastguard Worker exit(EXIT_FAILURE); \
34*38e8c45fSAndroid Build Coastguard Worker } \
35*38e8c45fSAndroid Build Coastguard Worker } while (0)
36*38e8c45fSAndroid Build Coastguard Worker
37*38e8c45fSAndroid Build Coastguard Worker vector<sp<IBinder> > workers;
38*38e8c45fSAndroid Build Coastguard Worker
39*38e8c45fSAndroid Build Coastguard Worker // the ratio that the service is synced on the same cpu beyond
40*38e8c45fSAndroid Build Coastguard Worker // GOOD_SYNC_MIN is considered as good
41*38e8c45fSAndroid Build Coastguard Worker #define GOOD_SYNC_MIN (0.6)
42*38e8c45fSAndroid Build Coastguard Worker
43*38e8c45fSAndroid Build Coastguard Worker #define DUMP_PRESICION 2
44*38e8c45fSAndroid Build Coastguard Worker
45*38e8c45fSAndroid Build Coastguard Worker string trace_path = "/sys/kernel/debug/tracing";
46*38e8c45fSAndroid Build Coastguard Worker
47*38e8c45fSAndroid Build Coastguard Worker // the default value
48*38e8c45fSAndroid Build Coastguard Worker int no_process = 2;
49*38e8c45fSAndroid Build Coastguard Worker int iterations = 100;
50*38e8c45fSAndroid Build Coastguard Worker int payload_size = 16;
51*38e8c45fSAndroid Build Coastguard Worker int no_inherent = 0;
52*38e8c45fSAndroid Build Coastguard Worker int no_sync = 0;
53*38e8c45fSAndroid Build Coastguard Worker int verbose = 0;
54*38e8c45fSAndroid Build Coastguard Worker int trace;
55*38e8c45fSAndroid Build Coastguard Worker
traceIsOn()56*38e8c45fSAndroid Build Coastguard Worker bool traceIsOn() {
57*38e8c45fSAndroid Build Coastguard Worker fstream file;
58*38e8c45fSAndroid Build Coastguard Worker file.open(trace_path + "/tracing_on", ios::in);
59*38e8c45fSAndroid Build Coastguard Worker char on;
60*38e8c45fSAndroid Build Coastguard Worker file >> on;
61*38e8c45fSAndroid Build Coastguard Worker file.close();
62*38e8c45fSAndroid Build Coastguard Worker return on == '1';
63*38e8c45fSAndroid Build Coastguard Worker }
64*38e8c45fSAndroid Build Coastguard Worker
traceStop()65*38e8c45fSAndroid Build Coastguard Worker void traceStop() {
66*38e8c45fSAndroid Build Coastguard Worker ofstream file;
67*38e8c45fSAndroid Build Coastguard Worker file.open(trace_path + "/tracing_on", ios::out | ios::trunc);
68*38e8c45fSAndroid Build Coastguard Worker file << '0' << endl;
69*38e8c45fSAndroid Build Coastguard Worker file.close();
70*38e8c45fSAndroid Build Coastguard Worker }
71*38e8c45fSAndroid Build Coastguard Worker
72*38e8c45fSAndroid Build Coastguard Worker // the deadline latency that we are interested in
73*38e8c45fSAndroid Build Coastguard Worker uint64_t deadline_us = 2500;
74*38e8c45fSAndroid Build Coastguard Worker
thread_pri()75*38e8c45fSAndroid Build Coastguard Worker int thread_pri() {
76*38e8c45fSAndroid Build Coastguard Worker struct sched_param param;
77*38e8c45fSAndroid Build Coastguard Worker int policy;
78*38e8c45fSAndroid Build Coastguard Worker ASSERT(!pthread_getschedparam(pthread_self(), &policy, ¶m));
79*38e8c45fSAndroid Build Coastguard Worker return param.sched_priority;
80*38e8c45fSAndroid Build Coastguard Worker }
81*38e8c45fSAndroid Build Coastguard Worker
thread_dump(const char * prefix)82*38e8c45fSAndroid Build Coastguard Worker void thread_dump(const char* prefix) {
83*38e8c45fSAndroid Build Coastguard Worker struct sched_param param;
84*38e8c45fSAndroid Build Coastguard Worker int policy;
85*38e8c45fSAndroid Build Coastguard Worker if (!verbose) return;
86*38e8c45fSAndroid Build Coastguard Worker cout << "--------------------------------------------------" << endl;
87*38e8c45fSAndroid Build Coastguard Worker cout << setw(12) << left << prefix << " pid: " << getpid()
88*38e8c45fSAndroid Build Coastguard Worker << " tid: " << gettid() << " cpu: " << sched_getcpu() << endl;
89*38e8c45fSAndroid Build Coastguard Worker ASSERT(!pthread_getschedparam(pthread_self(), &policy, ¶m));
90*38e8c45fSAndroid Build Coastguard Worker string s = (policy == SCHED_OTHER)
91*38e8c45fSAndroid Build Coastguard Worker ? "SCHED_OTHER"
92*38e8c45fSAndroid Build Coastguard Worker : (policy == SCHED_FIFO)
93*38e8c45fSAndroid Build Coastguard Worker ? "SCHED_FIFO"
94*38e8c45fSAndroid Build Coastguard Worker : (policy == SCHED_RR) ? "SCHED_RR" : "???";
95*38e8c45fSAndroid Build Coastguard Worker cout << setw(12) << left << s << param.sched_priority << endl;
96*38e8c45fSAndroid Build Coastguard Worker return;
97*38e8c45fSAndroid Build Coastguard Worker }
98*38e8c45fSAndroid Build Coastguard Worker
99*38e8c45fSAndroid Build Coastguard Worker class BinderWorkerService : public BBinder {
100*38e8c45fSAndroid Build Coastguard Worker public:
BinderWorkerService()101*38e8c45fSAndroid Build Coastguard Worker BinderWorkerService() {
102*38e8c45fSAndroid Build Coastguard Worker }
~BinderWorkerService()103*38e8c45fSAndroid Build Coastguard Worker ~BinderWorkerService() {
104*38e8c45fSAndroid Build Coastguard Worker }
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags=0)105*38e8c45fSAndroid Build Coastguard Worker virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
106*38e8c45fSAndroid Build Coastguard Worker uint32_t flags = 0) {
107*38e8c45fSAndroid Build Coastguard Worker (void)flags;
108*38e8c45fSAndroid Build Coastguard Worker (void)data;
109*38e8c45fSAndroid Build Coastguard Worker (void)reply;
110*38e8c45fSAndroid Build Coastguard Worker switch (code) {
111*38e8c45fSAndroid Build Coastguard Worker // The transaction format is like
112*38e8c45fSAndroid Build Coastguard Worker //
113*38e8c45fSAndroid Build Coastguard Worker // data[in]: int32: caller priority
114*38e8c45fSAndroid Build Coastguard Worker // int32: caller cpu
115*38e8c45fSAndroid Build Coastguard Worker //
116*38e8c45fSAndroid Build Coastguard Worker // reply[out]: int32: 1 if caller's priority != callee's priority
117*38e8c45fSAndroid Build Coastguard Worker // int32: 1 if caller's cpu != callee's cpu
118*38e8c45fSAndroid Build Coastguard Worker //
119*38e8c45fSAndroid Build Coastguard Worker // note the caller cpu read here is not always correct
120*38e8c45fSAndroid Build Coastguard Worker // there're still chances that the caller got switched out
121*38e8c45fSAndroid Build Coastguard Worker // right after it read the cpu number and still before the transaction.
122*38e8c45fSAndroid Build Coastguard Worker case BINDER_NOP: {
123*38e8c45fSAndroid Build Coastguard Worker thread_dump("binder");
124*38e8c45fSAndroid Build Coastguard Worker int priority = thread_pri();
125*38e8c45fSAndroid Build Coastguard Worker int priority_caller = data.readInt32();
126*38e8c45fSAndroid Build Coastguard Worker int h = 0, s = 0;
127*38e8c45fSAndroid Build Coastguard Worker if (priority_caller != priority) {
128*38e8c45fSAndroid Build Coastguard Worker h++;
129*38e8c45fSAndroid Build Coastguard Worker if (verbose) {
130*38e8c45fSAndroid Build Coastguard Worker cout << "err priority_caller:" << priority_caller
131*38e8c45fSAndroid Build Coastguard Worker << ", priority:" << priority << endl;
132*38e8c45fSAndroid Build Coastguard Worker }
133*38e8c45fSAndroid Build Coastguard Worker }
134*38e8c45fSAndroid Build Coastguard Worker if (priority == sched_get_priority_max(SCHED_FIFO)) {
135*38e8c45fSAndroid Build Coastguard Worker int cpu = sched_getcpu();
136*38e8c45fSAndroid Build Coastguard Worker int cpu_caller = data.readInt32();
137*38e8c45fSAndroid Build Coastguard Worker if (cpu != cpu_caller) {
138*38e8c45fSAndroid Build Coastguard Worker s++;
139*38e8c45fSAndroid Build Coastguard Worker }
140*38e8c45fSAndroid Build Coastguard Worker }
141*38e8c45fSAndroid Build Coastguard Worker reply->writeInt32(h);
142*38e8c45fSAndroid Build Coastguard Worker reply->writeInt32(s);
143*38e8c45fSAndroid Build Coastguard Worker return NO_ERROR;
144*38e8c45fSAndroid Build Coastguard Worker }
145*38e8c45fSAndroid Build Coastguard Worker default:
146*38e8c45fSAndroid Build Coastguard Worker return UNKNOWN_TRANSACTION;
147*38e8c45fSAndroid Build Coastguard Worker };
148*38e8c45fSAndroid Build Coastguard Worker }
149*38e8c45fSAndroid Build Coastguard Worker };
150*38e8c45fSAndroid Build Coastguard Worker
151*38e8c45fSAndroid Build Coastguard Worker class Pipe {
152*38e8c45fSAndroid Build Coastguard Worker int m_readFd;
153*38e8c45fSAndroid Build Coastguard Worker int m_writeFd;
Pipe(int readFd,int writeFd)154*38e8c45fSAndroid Build Coastguard Worker Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} {
155*38e8c45fSAndroid Build Coastguard Worker }
156*38e8c45fSAndroid Build Coastguard Worker Pipe(const Pipe&) = delete;
157*38e8c45fSAndroid Build Coastguard Worker Pipe& operator=(const Pipe&) = delete;
158*38e8c45fSAndroid Build Coastguard Worker Pipe& operator=(const Pipe&&) = delete;
159*38e8c45fSAndroid Build Coastguard Worker
160*38e8c45fSAndroid Build Coastguard Worker public:
Pipe(Pipe && rval)161*38e8c45fSAndroid Build Coastguard Worker Pipe(Pipe&& rval) noexcept {
162*38e8c45fSAndroid Build Coastguard Worker m_readFd = rval.m_readFd;
163*38e8c45fSAndroid Build Coastguard Worker m_writeFd = rval.m_writeFd;
164*38e8c45fSAndroid Build Coastguard Worker rval.m_readFd = 0;
165*38e8c45fSAndroid Build Coastguard Worker rval.m_writeFd = 0;
166*38e8c45fSAndroid Build Coastguard Worker }
~Pipe()167*38e8c45fSAndroid Build Coastguard Worker ~Pipe() {
168*38e8c45fSAndroid Build Coastguard Worker if (m_readFd) close(m_readFd);
169*38e8c45fSAndroid Build Coastguard Worker if (m_writeFd) close(m_writeFd);
170*38e8c45fSAndroid Build Coastguard Worker }
signal()171*38e8c45fSAndroid Build Coastguard Worker void signal() {
172*38e8c45fSAndroid Build Coastguard Worker bool val = true;
173*38e8c45fSAndroid Build Coastguard Worker int error = write(m_writeFd, &val, sizeof(val));
174*38e8c45fSAndroid Build Coastguard Worker ASSERT(error >= 0);
175*38e8c45fSAndroid Build Coastguard Worker };
wait()176*38e8c45fSAndroid Build Coastguard Worker void wait() {
177*38e8c45fSAndroid Build Coastguard Worker bool val = false;
178*38e8c45fSAndroid Build Coastguard Worker int error = read(m_readFd, &val, sizeof(val));
179*38e8c45fSAndroid Build Coastguard Worker ASSERT(error >= 0);
180*38e8c45fSAndroid Build Coastguard Worker }
181*38e8c45fSAndroid Build Coastguard Worker template <typename T>
send(const T & v)182*38e8c45fSAndroid Build Coastguard Worker void send(const T& v) {
183*38e8c45fSAndroid Build Coastguard Worker int error = write(m_writeFd, &v, sizeof(T));
184*38e8c45fSAndroid Build Coastguard Worker ASSERT(error >= 0);
185*38e8c45fSAndroid Build Coastguard Worker }
186*38e8c45fSAndroid Build Coastguard Worker template <typename T>
recv(T & v)187*38e8c45fSAndroid Build Coastguard Worker void recv(T& v) {
188*38e8c45fSAndroid Build Coastguard Worker int error = read(m_readFd, &v, sizeof(T));
189*38e8c45fSAndroid Build Coastguard Worker ASSERT(error >= 0);
190*38e8c45fSAndroid Build Coastguard Worker }
createPipePair()191*38e8c45fSAndroid Build Coastguard Worker static tuple<Pipe, Pipe> createPipePair() {
192*38e8c45fSAndroid Build Coastguard Worker int a[2];
193*38e8c45fSAndroid Build Coastguard Worker int b[2];
194*38e8c45fSAndroid Build Coastguard Worker
195*38e8c45fSAndroid Build Coastguard Worker int error1 = pipe(a);
196*38e8c45fSAndroid Build Coastguard Worker int error2 = pipe(b);
197*38e8c45fSAndroid Build Coastguard Worker ASSERT(error1 >= 0);
198*38e8c45fSAndroid Build Coastguard Worker ASSERT(error2 >= 0);
199*38e8c45fSAndroid Build Coastguard Worker
200*38e8c45fSAndroid Build Coastguard Worker return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
201*38e8c45fSAndroid Build Coastguard Worker }
202*38e8c45fSAndroid Build Coastguard Worker };
203*38e8c45fSAndroid Build Coastguard Worker
204*38e8c45fSAndroid Build Coastguard Worker typedef chrono::time_point<chrono::high_resolution_clock> Tick;
205*38e8c45fSAndroid Build Coastguard Worker
tickNow()206*38e8c45fSAndroid Build Coastguard Worker static inline Tick tickNow() {
207*38e8c45fSAndroid Build Coastguard Worker return chrono::high_resolution_clock::now();
208*38e8c45fSAndroid Build Coastguard Worker }
209*38e8c45fSAndroid Build Coastguard Worker
tickNano(Tick & sta,Tick & end)210*38e8c45fSAndroid Build Coastguard Worker static inline uint64_t tickNano(Tick& sta, Tick& end) {
211*38e8c45fSAndroid Build Coastguard Worker return uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - sta).count());
212*38e8c45fSAndroid Build Coastguard Worker }
213*38e8c45fSAndroid Build Coastguard Worker
214*38e8c45fSAndroid Build Coastguard Worker struct Results {
215*38e8c45fSAndroid Build Coastguard Worker uint64_t m_best = 0xffffffffffffffffULL;
216*38e8c45fSAndroid Build Coastguard Worker uint64_t m_worst = 0;
217*38e8c45fSAndroid Build Coastguard Worker uint64_t m_transactions = 0;
218*38e8c45fSAndroid Build Coastguard Worker uint64_t m_total_time = 0;
219*38e8c45fSAndroid Build Coastguard Worker uint64_t m_miss = 0;
220*38e8c45fSAndroid Build Coastguard Worker bool tracing;
ResultsResults221*38e8c45fSAndroid Build Coastguard Worker explicit Results(bool _tracing) : tracing(_tracing) {
222*38e8c45fSAndroid Build Coastguard Worker }
miss_deadlineResults223*38e8c45fSAndroid Build Coastguard Worker inline bool miss_deadline(uint64_t nano) {
224*38e8c45fSAndroid Build Coastguard Worker return nano > deadline_us * 1000;
225*38e8c45fSAndroid Build Coastguard Worker }
add_timeResults226*38e8c45fSAndroid Build Coastguard Worker void add_time(uint64_t nano) {
227*38e8c45fSAndroid Build Coastguard Worker m_best = min(nano, m_best);
228*38e8c45fSAndroid Build Coastguard Worker m_worst = max(nano, m_worst);
229*38e8c45fSAndroid Build Coastguard Worker m_transactions += 1;
230*38e8c45fSAndroid Build Coastguard Worker m_total_time += nano;
231*38e8c45fSAndroid Build Coastguard Worker if (miss_deadline(nano)) m_miss++;
232*38e8c45fSAndroid Build Coastguard Worker if (miss_deadline(nano) && tracing) {
233*38e8c45fSAndroid Build Coastguard Worker // There might be multiple process pair running the test concurrently
234*38e8c45fSAndroid Build Coastguard Worker // each may execute following statements and only the first one actually
235*38e8c45fSAndroid Build Coastguard Worker // stop the trace and any traceStop() afterthen has no effect.
236*38e8c45fSAndroid Build Coastguard Worker traceStop();
237*38e8c45fSAndroid Build Coastguard Worker cout << endl;
238*38e8c45fSAndroid Build Coastguard Worker cout << "deadline triggered: halt & stop trace" << endl;
239*38e8c45fSAndroid Build Coastguard Worker cout << "log:" + trace_path + "/trace" << endl;
240*38e8c45fSAndroid Build Coastguard Worker cout << endl;
241*38e8c45fSAndroid Build Coastguard Worker exit(1);
242*38e8c45fSAndroid Build Coastguard Worker }
243*38e8c45fSAndroid Build Coastguard Worker }
dumpResults244*38e8c45fSAndroid Build Coastguard Worker void dump() {
245*38e8c45fSAndroid Build Coastguard Worker double best = (double)m_best / 1.0E6;
246*38e8c45fSAndroid Build Coastguard Worker double worst = (double)m_worst / 1.0E6;
247*38e8c45fSAndroid Build Coastguard Worker double average = (double)m_total_time / m_transactions / 1.0E6;
248*38e8c45fSAndroid Build Coastguard Worker // TODO: libjson?
249*38e8c45fSAndroid Build Coastguard Worker int W = DUMP_PRESICION + 2;
250*38e8c45fSAndroid Build Coastguard Worker cout << setprecision(DUMP_PRESICION) << "{ \"avg\":" << setw(W) << left
251*38e8c45fSAndroid Build Coastguard Worker << average << ",\"wst\":" << setw(W) << left << worst
252*38e8c45fSAndroid Build Coastguard Worker << ",\"bst\":" << setw(W) << left << best << ",\"miss\":" << left
253*38e8c45fSAndroid Build Coastguard Worker << m_miss << ",\"meetR\":" << left << setprecision(DUMP_PRESICION + 3)
254*38e8c45fSAndroid Build Coastguard Worker << (1.0 - (double)m_miss / m_transactions) << "}";
255*38e8c45fSAndroid Build Coastguard Worker }
256*38e8c45fSAndroid Build Coastguard Worker };
257*38e8c45fSAndroid Build Coastguard Worker
generateServiceName(int num)258*38e8c45fSAndroid Build Coastguard Worker String16 generateServiceName(int num) {
259*38e8c45fSAndroid Build Coastguard Worker char num_str[32];
260*38e8c45fSAndroid Build Coastguard Worker snprintf(num_str, sizeof(num_str), "%d", num);
261*38e8c45fSAndroid Build Coastguard Worker String16 serviceName = String16("binderWorker") + String16(num_str);
262*38e8c45fSAndroid Build Coastguard Worker return serviceName;
263*38e8c45fSAndroid Build Coastguard Worker }
264*38e8c45fSAndroid Build Coastguard Worker
parcel_fill(Parcel & data,int sz,int priority,int cpu)265*38e8c45fSAndroid Build Coastguard Worker static void parcel_fill(Parcel& data, int sz, int priority, int cpu) {
266*38e8c45fSAndroid Build Coastguard Worker ASSERT(sz >= (int)sizeof(uint32_t) * 2);
267*38e8c45fSAndroid Build Coastguard Worker data.writeInt32(priority);
268*38e8c45fSAndroid Build Coastguard Worker data.writeInt32(cpu);
269*38e8c45fSAndroid Build Coastguard Worker sz -= sizeof(uint32_t);
270*38e8c45fSAndroid Build Coastguard Worker while (sz > (int)sizeof(uint32_t)) {
271*38e8c45fSAndroid Build Coastguard Worker data.writeInt32(0);
272*38e8c45fSAndroid Build Coastguard Worker sz -= sizeof(uint32_t);
273*38e8c45fSAndroid Build Coastguard Worker }
274*38e8c45fSAndroid Build Coastguard Worker }
275*38e8c45fSAndroid Build Coastguard Worker
276*38e8c45fSAndroid Build Coastguard Worker typedef struct {
277*38e8c45fSAndroid Build Coastguard Worker void* result;
278*38e8c45fSAndroid Build Coastguard Worker int target;
279*38e8c45fSAndroid Build Coastguard Worker } thread_priv_t;
280*38e8c45fSAndroid Build Coastguard Worker
thread_start(void * p)281*38e8c45fSAndroid Build Coastguard Worker static void* thread_start(void* p) {
282*38e8c45fSAndroid Build Coastguard Worker thread_priv_t* priv = (thread_priv_t*)p;
283*38e8c45fSAndroid Build Coastguard Worker int target = priv->target;
284*38e8c45fSAndroid Build Coastguard Worker Results* results_fifo = (Results*)priv->result;
285*38e8c45fSAndroid Build Coastguard Worker Parcel data, reply;
286*38e8c45fSAndroid Build Coastguard Worker Tick sta, end;
287*38e8c45fSAndroid Build Coastguard Worker
288*38e8c45fSAndroid Build Coastguard Worker parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
289*38e8c45fSAndroid Build Coastguard Worker thread_dump("fifo-caller");
290*38e8c45fSAndroid Build Coastguard Worker
291*38e8c45fSAndroid Build Coastguard Worker sta = tickNow();
292*38e8c45fSAndroid Build Coastguard Worker status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
293*38e8c45fSAndroid Build Coastguard Worker ASSERT(ret == NO_ERROR);
294*38e8c45fSAndroid Build Coastguard Worker end = tickNow();
295*38e8c45fSAndroid Build Coastguard Worker results_fifo->add_time(tickNano(sta, end));
296*38e8c45fSAndroid Build Coastguard Worker
297*38e8c45fSAndroid Build Coastguard Worker no_inherent += reply.readInt32();
298*38e8c45fSAndroid Build Coastguard Worker no_sync += reply.readInt32();
299*38e8c45fSAndroid Build Coastguard Worker return nullptr;
300*38e8c45fSAndroid Build Coastguard Worker }
301*38e8c45fSAndroid Build Coastguard Worker
302*38e8c45fSAndroid Build Coastguard Worker // create a fifo thread to transact and wait it to finished
thread_transaction(int target,Results * results_fifo)303*38e8c45fSAndroid Build Coastguard Worker static void thread_transaction(int target, Results* results_fifo) {
304*38e8c45fSAndroid Build Coastguard Worker thread_priv_t thread_priv;
305*38e8c45fSAndroid Build Coastguard Worker void* dummy;
306*38e8c45fSAndroid Build Coastguard Worker pthread_t thread;
307*38e8c45fSAndroid Build Coastguard Worker pthread_attr_t attr;
308*38e8c45fSAndroid Build Coastguard Worker struct sched_param param;
309*38e8c45fSAndroid Build Coastguard Worker thread_priv.target = target;
310*38e8c45fSAndroid Build Coastguard Worker thread_priv.result = results_fifo;
311*38e8c45fSAndroid Build Coastguard Worker ASSERT(!pthread_attr_init(&attr));
312*38e8c45fSAndroid Build Coastguard Worker ASSERT(!pthread_attr_setschedpolicy(&attr, SCHED_FIFO));
313*38e8c45fSAndroid Build Coastguard Worker param.sched_priority = sched_get_priority_max(SCHED_FIFO);
314*38e8c45fSAndroid Build Coastguard Worker ASSERT(!pthread_attr_setschedparam(&attr, ¶m));
315*38e8c45fSAndroid Build Coastguard Worker ASSERT(!pthread_create(&thread, &attr, &thread_start, &thread_priv));
316*38e8c45fSAndroid Build Coastguard Worker ASSERT(!pthread_join(thread, &dummy));
317*38e8c45fSAndroid Build Coastguard Worker }
318*38e8c45fSAndroid Build Coastguard Worker
319*38e8c45fSAndroid Build Coastguard Worker #define is_client(_num) ((_num) >= (no_process / 2))
320*38e8c45fSAndroid Build Coastguard Worker
worker_fx(int num,int no_process,int iterations,int payload_size,Pipe p)321*38e8c45fSAndroid Build Coastguard Worker void worker_fx(int num, int no_process, int iterations, int payload_size,
322*38e8c45fSAndroid Build Coastguard Worker Pipe p) {
323*38e8c45fSAndroid Build Coastguard Worker int dummy;
324*38e8c45fSAndroid Build Coastguard Worker Results results_other(false), results_fifo(trace);
325*38e8c45fSAndroid Build Coastguard Worker
326*38e8c45fSAndroid Build Coastguard Worker // Create BinderWorkerService and for go.
327*38e8c45fSAndroid Build Coastguard Worker ProcessState::self()->startThreadPool();
328*38e8c45fSAndroid Build Coastguard Worker sp<IServiceManager> serviceMgr = defaultServiceManager();
329*38e8c45fSAndroid Build Coastguard Worker sp<BinderWorkerService> service = new BinderWorkerService;
330*38e8c45fSAndroid Build Coastguard Worker serviceMgr->addService(generateServiceName(num), service);
331*38e8c45fSAndroid Build Coastguard Worker // init done
332*38e8c45fSAndroid Build Coastguard Worker p.signal();
333*38e8c45fSAndroid Build Coastguard Worker // wait for kick-off
334*38e8c45fSAndroid Build Coastguard Worker p.wait();
335*38e8c45fSAndroid Build Coastguard Worker
336*38e8c45fSAndroid Build Coastguard Worker // If client/server pairs, then half the workers are
337*38e8c45fSAndroid Build Coastguard Worker // servers and half are clients
338*38e8c45fSAndroid Build Coastguard Worker int server_count = no_process / 2;
339*38e8c45fSAndroid Build Coastguard Worker
340*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < server_count; i++) {
341*38e8c45fSAndroid Build Coastguard Worker // self service is in-process so just skip
342*38e8c45fSAndroid Build Coastguard Worker if (num == i) continue;
343*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic push
344*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wdeprecated-declarations"
345*38e8c45fSAndroid Build Coastguard Worker workers.push_back(serviceMgr->getService(generateServiceName(i)));
346*38e8c45fSAndroid Build Coastguard Worker #pragma clang diagnostic pop
347*38e8c45fSAndroid Build Coastguard Worker }
348*38e8c45fSAndroid Build Coastguard Worker
349*38e8c45fSAndroid Build Coastguard Worker // Client for each pair iterates here
350*38e8c45fSAndroid Build Coastguard Worker // each iterations contains exatcly 2 transactions
351*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; is_client(num) && i < iterations; i++) {
352*38e8c45fSAndroid Build Coastguard Worker Parcel data, reply;
353*38e8c45fSAndroid Build Coastguard Worker Tick sta, end;
354*38e8c45fSAndroid Build Coastguard Worker // the target is paired to make it easier to diagnose
355*38e8c45fSAndroid Build Coastguard Worker int target = num % server_count;
356*38e8c45fSAndroid Build Coastguard Worker
357*38e8c45fSAndroid Build Coastguard Worker // 1. transaction by fifo thread
358*38e8c45fSAndroid Build Coastguard Worker thread_transaction(target, &results_fifo);
359*38e8c45fSAndroid Build Coastguard Worker parcel_fill(data, payload_size, thread_pri(), sched_getcpu());
360*38e8c45fSAndroid Build Coastguard Worker thread_dump("other-caller");
361*38e8c45fSAndroid Build Coastguard Worker
362*38e8c45fSAndroid Build Coastguard Worker // 2. transaction by other thread
363*38e8c45fSAndroid Build Coastguard Worker sta = tickNow();
364*38e8c45fSAndroid Build Coastguard Worker ASSERT(NO_ERROR == workers[target]->transact(BINDER_NOP, data, &reply));
365*38e8c45fSAndroid Build Coastguard Worker end = tickNow();
366*38e8c45fSAndroid Build Coastguard Worker results_other.add_time(tickNano(sta, end));
367*38e8c45fSAndroid Build Coastguard Worker
368*38e8c45fSAndroid Build Coastguard Worker no_inherent += reply.readInt32();
369*38e8c45fSAndroid Build Coastguard Worker no_sync += reply.readInt32();
370*38e8c45fSAndroid Build Coastguard Worker }
371*38e8c45fSAndroid Build Coastguard Worker // Signal completion to master and wait.
372*38e8c45fSAndroid Build Coastguard Worker p.signal();
373*38e8c45fSAndroid Build Coastguard Worker p.wait();
374*38e8c45fSAndroid Build Coastguard Worker
375*38e8c45fSAndroid Build Coastguard Worker p.send(&dummy);
376*38e8c45fSAndroid Build Coastguard Worker // wait for kill
377*38e8c45fSAndroid Build Coastguard Worker p.wait();
378*38e8c45fSAndroid Build Coastguard Worker // Client for each pair dump here
379*38e8c45fSAndroid Build Coastguard Worker if (is_client(num)) {
380*38e8c45fSAndroid Build Coastguard Worker int no_trans = iterations * 2;
381*38e8c45fSAndroid Build Coastguard Worker double sync_ratio = (1.0 - (double)no_sync / no_trans);
382*38e8c45fSAndroid Build Coastguard Worker // TODO: libjson?
383*38e8c45fSAndroid Build Coastguard Worker cout << "\"P" << (num - server_count) << "\":{\"SYNC\":\""
384*38e8c45fSAndroid Build Coastguard Worker << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
385*38e8c45fSAndroid Build Coastguard Worker << "\"S\":" << (no_trans - no_sync) << ",\"I\":" << no_trans << ","
386*38e8c45fSAndroid Build Coastguard Worker << "\"R\":" << sync_ratio << "," << endl;
387*38e8c45fSAndroid Build Coastguard Worker
388*38e8c45fSAndroid Build Coastguard Worker cout << " \"other_ms\":";
389*38e8c45fSAndroid Build Coastguard Worker results_other.dump();
390*38e8c45fSAndroid Build Coastguard Worker cout << "," << endl;
391*38e8c45fSAndroid Build Coastguard Worker cout << " \"fifo_ms\": ";
392*38e8c45fSAndroid Build Coastguard Worker results_fifo.dump();
393*38e8c45fSAndroid Build Coastguard Worker cout << endl;
394*38e8c45fSAndroid Build Coastguard Worker cout << "}," << endl;
395*38e8c45fSAndroid Build Coastguard Worker }
396*38e8c45fSAndroid Build Coastguard Worker exit(no_inherent);
397*38e8c45fSAndroid Build Coastguard Worker }
398*38e8c45fSAndroid Build Coastguard Worker
make_process(int num,int iterations,int no_process,int payload_size)399*38e8c45fSAndroid Build Coastguard Worker Pipe make_process(int num, int iterations, int no_process, int payload_size) {
400*38e8c45fSAndroid Build Coastguard Worker auto pipe_pair = Pipe::createPipePair();
401*38e8c45fSAndroid Build Coastguard Worker pid_t pid = fork();
402*38e8c45fSAndroid Build Coastguard Worker if (pid) {
403*38e8c45fSAndroid Build Coastguard Worker // parent
404*38e8c45fSAndroid Build Coastguard Worker return std::move(get<0>(pipe_pair));
405*38e8c45fSAndroid Build Coastguard Worker } else {
406*38e8c45fSAndroid Build Coastguard Worker // child
407*38e8c45fSAndroid Build Coastguard Worker thread_dump(is_client(num) ? "client" : "server");
408*38e8c45fSAndroid Build Coastguard Worker worker_fx(num, no_process, iterations, payload_size, std::move(get<1>(pipe_pair)));
409*38e8c45fSAndroid Build Coastguard Worker // never get here
410*38e8c45fSAndroid Build Coastguard Worker return std::move(get<0>(pipe_pair));
411*38e8c45fSAndroid Build Coastguard Worker }
412*38e8c45fSAndroid Build Coastguard Worker }
413*38e8c45fSAndroid Build Coastguard Worker
wait_all(vector<Pipe> & v)414*38e8c45fSAndroid Build Coastguard Worker void wait_all(vector<Pipe>& v) {
415*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < v.size(); i++) {
416*38e8c45fSAndroid Build Coastguard Worker v[i].wait();
417*38e8c45fSAndroid Build Coastguard Worker }
418*38e8c45fSAndroid Build Coastguard Worker }
419*38e8c45fSAndroid Build Coastguard Worker
signal_all(vector<Pipe> & v)420*38e8c45fSAndroid Build Coastguard Worker void signal_all(vector<Pipe>& v) {
421*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < v.size(); i++) {
422*38e8c45fSAndroid Build Coastguard Worker v[i].signal();
423*38e8c45fSAndroid Build Coastguard Worker }
424*38e8c45fSAndroid Build Coastguard Worker }
425*38e8c45fSAndroid Build Coastguard Worker
426*38e8c45fSAndroid Build Coastguard Worker // This test is modified from binderThroughputTest.cpp
main(int argc,char ** argv)427*38e8c45fSAndroid Build Coastguard Worker int main(int argc, char** argv) {
428*38e8c45fSAndroid Build Coastguard Worker for (int i = 1; i < argc; i++) {
429*38e8c45fSAndroid Build Coastguard Worker if (string(argv[i]) == "-i") {
430*38e8c45fSAndroid Build Coastguard Worker iterations = atoi(argv[i + 1]);
431*38e8c45fSAndroid Build Coastguard Worker i++;
432*38e8c45fSAndroid Build Coastguard Worker continue;
433*38e8c45fSAndroid Build Coastguard Worker }
434*38e8c45fSAndroid Build Coastguard Worker if (string(argv[i]) == "-pair") {
435*38e8c45fSAndroid Build Coastguard Worker no_process = 2 * atoi(argv[i + 1]);
436*38e8c45fSAndroid Build Coastguard Worker i++;
437*38e8c45fSAndroid Build Coastguard Worker continue;
438*38e8c45fSAndroid Build Coastguard Worker }
439*38e8c45fSAndroid Build Coastguard Worker if (string(argv[i]) == "-deadline_us") {
440*38e8c45fSAndroid Build Coastguard Worker deadline_us = atoi(argv[i + 1]);
441*38e8c45fSAndroid Build Coastguard Worker i++;
442*38e8c45fSAndroid Build Coastguard Worker continue;
443*38e8c45fSAndroid Build Coastguard Worker }
444*38e8c45fSAndroid Build Coastguard Worker if (string(argv[i]) == "-v") {
445*38e8c45fSAndroid Build Coastguard Worker verbose = 1;
446*38e8c45fSAndroid Build Coastguard Worker }
447*38e8c45fSAndroid Build Coastguard Worker // The -trace argument is used like that:
448*38e8c45fSAndroid Build Coastguard Worker //
449*38e8c45fSAndroid Build Coastguard Worker // First start trace with atrace command as usual
450*38e8c45fSAndroid Build Coastguard Worker // >atrace --async_start sched freq
451*38e8c45fSAndroid Build Coastguard Worker //
452*38e8c45fSAndroid Build Coastguard Worker // then use schd-dbg with -trace arguments
453*38e8c45fSAndroid Build Coastguard Worker //./schd-dbg -trace -deadline_us 2500
454*38e8c45fSAndroid Build Coastguard Worker //
455*38e8c45fSAndroid Build Coastguard Worker // This makes schd-dbg to stop trace once it detects a transaction
456*38e8c45fSAndroid Build Coastguard Worker // duration over the deadline. By writing '0' to
457*38e8c45fSAndroid Build Coastguard Worker // /sys/kernel/debug/tracing and halt the process. The tracelog is
458*38e8c45fSAndroid Build Coastguard Worker // then available on /sys/kernel/debug/trace
459*38e8c45fSAndroid Build Coastguard Worker if (string(argv[i]) == "-trace") {
460*38e8c45fSAndroid Build Coastguard Worker trace = 1;
461*38e8c45fSAndroid Build Coastguard Worker }
462*38e8c45fSAndroid Build Coastguard Worker }
463*38e8c45fSAndroid Build Coastguard Worker if (trace && !traceIsOn()) {
464*38e8c45fSAndroid Build Coastguard Worker cout << "trace is not running" << endl;
465*38e8c45fSAndroid Build Coastguard Worker cout << "check " << trace_path + "/tracing_on" << endl;
466*38e8c45fSAndroid Build Coastguard Worker cout << "use atrace --async_start first" << endl;
467*38e8c45fSAndroid Build Coastguard Worker exit(-1);
468*38e8c45fSAndroid Build Coastguard Worker }
469*38e8c45fSAndroid Build Coastguard Worker vector<Pipe> pipes;
470*38e8c45fSAndroid Build Coastguard Worker thread_dump("main");
471*38e8c45fSAndroid Build Coastguard Worker // TODO: libjson?
472*38e8c45fSAndroid Build Coastguard Worker cout << "{" << endl;
473*38e8c45fSAndroid Build Coastguard Worker cout << "\"cfg\":{\"pair\":" << (no_process / 2)
474*38e8c45fSAndroid Build Coastguard Worker << ",\"iterations\":" << iterations << ",\"deadline_us\":" << deadline_us
475*38e8c45fSAndroid Build Coastguard Worker << "}," << endl;
476*38e8c45fSAndroid Build Coastguard Worker
477*38e8c45fSAndroid Build Coastguard Worker // the main process fork 2 processes for each pairs
478*38e8c45fSAndroid Build Coastguard Worker // 1 server + 1 client
479*38e8c45fSAndroid Build Coastguard Worker // each has a pipe to communicate with
480*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < no_process; i++) {
481*38e8c45fSAndroid Build Coastguard Worker pipes.push_back(make_process(i, iterations, no_process, payload_size));
482*38e8c45fSAndroid Build Coastguard Worker }
483*38e8c45fSAndroid Build Coastguard Worker // wait for init done
484*38e8c45fSAndroid Build Coastguard Worker wait_all(pipes);
485*38e8c45fSAndroid Build Coastguard Worker // kick-off iterations
486*38e8c45fSAndroid Build Coastguard Worker signal_all(pipes);
487*38e8c45fSAndroid Build Coastguard Worker // wait for completion
488*38e8c45fSAndroid Build Coastguard Worker wait_all(pipes);
489*38e8c45fSAndroid Build Coastguard Worker // start to send result
490*38e8c45fSAndroid Build Coastguard Worker signal_all(pipes);
491*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < no_process; i++) {
492*38e8c45fSAndroid Build Coastguard Worker int status;
493*38e8c45fSAndroid Build Coastguard Worker // kill
494*38e8c45fSAndroid Build Coastguard Worker pipes[i].signal();
495*38e8c45fSAndroid Build Coastguard Worker wait(&status);
496*38e8c45fSAndroid Build Coastguard Worker // the exit status is number of transactions without priority inheritance
497*38e8c45fSAndroid Build Coastguard Worker // detected in the child process
498*38e8c45fSAndroid Build Coastguard Worker no_inherent += status;
499*38e8c45fSAndroid Build Coastguard Worker }
500*38e8c45fSAndroid Build Coastguard Worker // TODO: libjson?
501*38e8c45fSAndroid Build Coastguard Worker cout << "\"inheritance\": " << (no_inherent == 0 ? "\"PASS\"" : "\"FAIL\"")
502*38e8c45fSAndroid Build Coastguard Worker << endl;
503*38e8c45fSAndroid Build Coastguard Worker cout << "}" << endl;
504*38e8c45fSAndroid Build Coastguard Worker return -no_inherent;
505*38e8c45fSAndroid Build Coastguard Worker }
506