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(); 39 inline void signal() { 40 bool val = true; 41 send(val); 42 } 43 inline void wait() { 44 bool val = false; 45 recv(val); 46 } 47 48 // write a data struct 49 template <typename T> 50 int send(const T& v) { 51 return write(fd_write_, &v, sizeof(T)); 52 } 53 // read a data struct 54 template <typename T> 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 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. 85 void setTracingMode(bool tracing, uint64_t deadline_us) { 86 tracing_ = tracing; 87 deadline_us_ = deadline_us; 88 } 89 inline uint64_t getTransactions() const { return transactions_; } 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 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 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 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