• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) noexcept;
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