Home | History | Annotate | Download | only in performance
      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