xref: /aosp_15_r20/frameworks/native/libs/binder/tests/schd-dbg.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
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, &param));
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, &param));
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, &param));
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