1 /*
2 * Copyright (C) 2016 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 #ifndef HWBINDER_PERF_TEST_H
17 #define HWBINDER_PERF_TEST_H
18
19 #include <unistd.h>
20 #include <chrono>
21 #include <list>
22 #include <tuple>
23
24 #define TRACE_PATH "/sys/kernel/debug/tracing"
25
26 using std::list;
27 using std::tuple;
28
29 // Pipe is a object used for IPC between parent process and child process.
30 // This IPC class is widely used in binder/hwbinder tests.
31 // The common usage is the main process to create the Pipe and forks.
32 // Both parent and child hold a object. Each recv() on one side requires
33 // a send() on the other side to unblock.
34 class Pipe {
35 public:
36 static tuple<Pipe, Pipe> createPipePair();
37 Pipe(Pipe&& rval);
38 ~Pipe();
signal()39 inline void signal() {
40 bool val = true;
41 send(val);
42 }
wait()43 inline void wait() {
44 bool val = false;
45 recv(val);
46 }
47
48 // write a data struct
49 template <typename T>
send(const T & v)50 int send(const T& v) {
51 return write(fd_write_, &v, sizeof(T));
52 }
53 // read a data struct
54 template <typename T>
recv(T & v)55 int recv(T& v) {
56 return read(fd_read_, &v, sizeof(T));
57 }
58
59 private:
60 int fd_read_; // file descriptor to read
61 int fd_write_; // file descriptor to write
Pipe(int read_fd,int write_fd)62 Pipe(int read_fd, int write_fd) : fd_read_{read_fd}, fd_write_{write_fd} {}
63 Pipe(const Pipe&) = delete;
64 Pipe& operator=(const Pipe&) = delete;
65 Pipe& operator=(const Pipe&&) = delete;
66 };
67
68 // statistics of latency
69 // common usage:
70 //
71 // Results r;
72 // Tick sta, end;
73 // TICK_NOW(sta);
74 // ... do something ...
75 // TICK_NOW(end);
76 // r.addTime(tickDiffNS(sta, end));
77 //
78 // r.dump();
79 // r.dumpDistribution();
80 //
81 class Results {
82 public:
83 // enable the deadline miss detection which stops the trace recording after
84 // a transaction latency > deadline_us_ is detected.
setTracingMode(bool tracing,uint64_t deadline_us)85 void setTracingMode(bool tracing, uint64_t deadline_us) {
86 tracing_ = tracing;
87 deadline_us_ = deadline_us;
88 }
getTransactions()89 inline uint64_t getTransactions() const { return transactions_; }
missDeadline(uint64_t nano)90 inline bool missDeadline(uint64_t nano) const { return nano > deadline_us_ * 1000; }
91 // Combine two sets of latency data points and update the aggregation info.
92 static Results combine(const Results& a, const Results& b);
93 // add a new transaction latency record
94 void addTime(uint64_t nano);
95 // prepare for raw data recording, it may allocate resources which requires
96 // a flushRawData() to release
97 void setupRawData();
98 // dump the raw data and release the resource
99 void flushRawData();
100 // dump average, best, worst latency in json
101 void dump() const;
102 // dump latency distribution in json
103 void dumpDistribution() const;
104
105 private:
106 static const uint32_t kNumBuckets = 128;
107 static const uint64_t kMaxTimeBucket = 50ull * 1000000;
108 static const uint64_t kTimePerBucket = kMaxTimeBucket / kNumBuckets;
109 static constexpr float kTimePerBucketMS = kTimePerBucket / 1.0E6;
110 uint64_t best_ = 0xffffffffffffffffULL; // best transaction latency in ns.
111 uint64_t worst_ = 0; // worst transaction latency in ns.
112 uint64_t transactions_ = 0; // number of transactions
113 uint64_t total_time_ = 0; // total transaction time
114 uint64_t miss_ = 0; // number of transactions whose latency > deadline
115 uint32_t buckets_[kNumBuckets] = {0}; // statistics for the distribution
116 list<uint64_t>* raw_data_ = nullptr; // list for raw-data
117 bool tracing_ = false; // halt the trace log on a deadline miss
118 bool raw_dump_ = false; // record the raw data for the dump after
119 uint64_t deadline_us_ = 2500; // latency deadline in us.
120 };
121
122 // statistics of a process pair
123 class PResults {
124 public:
125 static PResults combine(const PResults& a, const PResults& b);
126 int nNotInherent = 0; ///< #transactions that does not inherit priority
127 int nNotSync = 0; ///< #transactions that are not synced
128 Results other; ///< statistics of CFS-other transactions
129 Results fifo; ///< statistics of RT-fifo transactions
130 // dump and flush the raw data
flushRawData()131 inline void flushRawData() { fifo.flushRawData(); }
132 // dump in json
133 void dump() const;
134 };
135
136 // Tick keeps timestamp
137 typedef std::chrono::time_point<std::chrono::high_resolution_clock> Tick;
138
139 // get current timestamp as a Tick
tickNow()140 static inline Tick tickNow() {
141 return std::chrono::high_resolution_clock::now();
142 }
143
144 #define TICK_NOW(_tick) \
145 do { \
146 asm volatile("" ::: "memory"); \
147 _tick = tickNow(); \
148 asm volatile("" ::: "memory"); \
149 } while (0)
150
151 // get nano seconds between sta & end
tickDiffNS(Tick & sta,Tick & end)152 static inline uint64_t tickDiffNS(Tick& sta, Tick& end) {
153 return uint64_t(std::chrono::duration_cast<std::chrono::nanoseconds>(end - sta).count());
154 }
155 #endif
156