Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2011 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 
     17 #ifndef ART_RUNTIME_BASE_TIMING_LOGGER_H_
     18 #define ART_RUNTIME_BASE_TIMING_LOGGER_H_
     19 
     20 #include "base/histogram.h"
     21 #include "base/macros.h"
     22 #include "base/mutex.h"
     23 #include "base/time_utils.h"
     24 
     25 #include <set>
     26 #include <string>
     27 #include <vector>
     28 
     29 namespace art {
     30 class TimingLogger;
     31 
     32 class CumulativeLogger {
     33  public:
     34   explicit CumulativeLogger(const std::string& name);
     35   ~CumulativeLogger();
     36   void Start();
     37   void End() REQUIRES(!lock_);
     38   void Reset() REQUIRES(!lock_);
     39   void Dump(std::ostream& os) const REQUIRES(!lock_);
     40   uint64_t GetTotalNs() const {
     41     return GetTotalTime() * kAdjust;
     42   }
     43   // Allow the name to be modified, particularly when the cumulative logger is a field within a
     44   // parent class that is unable to determine the "name" of a sub-class.
     45   void SetName(const std::string& name) REQUIRES(!lock_);
     46   void AddLogger(const TimingLogger& logger) REQUIRES(!lock_);
     47   size_t GetIterations() const REQUIRES(!lock_);
     48 
     49  private:
     50   class HistogramComparator {
     51    public:
     52     bool operator()(const Histogram<uint64_t>* a, const Histogram<uint64_t>* b) const {
     53       return a->Name() < b->Name();
     54     }
     55   };
     56 
     57   static constexpr size_t kLowMemoryBucketCount = 16;
     58   static constexpr size_t kDefaultBucketCount = 100;
     59   static constexpr size_t kInitialBucketSize = 50;  // 50 microseconds.
     60 
     61   void AddPair(const std::string &label, uint64_t delta_time)
     62       REQUIRES(lock_);
     63   void DumpHistogram(std::ostream &os) const REQUIRES(lock_);
     64   uint64_t GetTotalTime() const {
     65     return total_time_;
     66   }
     67   static const uint64_t kAdjust = 1000;
     68   std::set<Histogram<uint64_t>*, HistogramComparator> histograms_ GUARDED_BY(lock_);
     69   std::string name_;
     70   const std::string lock_name_;
     71   mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
     72   size_t iterations_ GUARDED_BY(lock_);
     73   uint64_t total_time_;
     74 
     75   DISALLOW_COPY_AND_ASSIGN(CumulativeLogger);
     76 };
     77 
     78 // A timing logger that knows when a split starts for the purposes of logging tools, like systrace.
     79 class TimingLogger {
     80  public:
     81   static constexpr size_t kIndexNotFound = static_cast<size_t>(-1);
     82 
     83   // Kind of timing we are going to do. We collect time at the nano second.
     84   enum class TimingKind {
     85     kMonotonic,
     86     kThreadCpu,
     87   };
     88 
     89   class Timing {
     90    public:
     91     Timing(TimingKind kind, const char* name) : name_(name) {
     92        switch (kind) {
     93         case TimingKind::kMonotonic:
     94           time_ = NanoTime();
     95           break;
     96         case TimingKind::kThreadCpu:
     97           time_ = ThreadCpuNanoTime();
     98           break;
     99        }
    100     }
    101     bool IsStartTiming() const {
    102       return !IsEndTiming();
    103     }
    104     bool IsEndTiming() const {
    105       return name_ == nullptr;
    106     }
    107     uint64_t GetTime() const {
    108       return time_;
    109     }
    110     const char* GetName() const {
    111       return name_;
    112     }
    113 
    114    private:
    115     uint64_t time_;
    116     const char* name_;
    117   };
    118 
    119   // Extra data that is only calculated when you call dump to prevent excess allocation.
    120   class TimingData {
    121    public:
    122     TimingData() = default;
    123     TimingData(TimingData&& other) {
    124       std::swap(data_, other.data_);
    125     }
    126     TimingData& operator=(TimingData&& other) {
    127       std::swap(data_, other.data_);
    128       return *this;
    129     }
    130     uint64_t GetTotalTime(size_t idx) {
    131       return data_[idx].total_time;
    132     }
    133     uint64_t GetExclusiveTime(size_t idx) {
    134       return data_[idx].exclusive_time;
    135     }
    136 
    137    private:
    138     // Each begin split has a total time and exclusive time. Exclusive time is total time - total
    139     // time of children nodes.
    140     struct CalculatedDataPoint {
    141       CalculatedDataPoint() : total_time(0), exclusive_time(0) {}
    142       uint64_t total_time;
    143       uint64_t exclusive_time;
    144     };
    145     std::vector<CalculatedDataPoint> data_;
    146     friend class TimingLogger;
    147   };
    148 
    149   TimingLogger(const char* name,
    150                bool precise,
    151                bool verbose,
    152                TimingKind kind = TimingKind::kMonotonic);
    153   ~TimingLogger();
    154   // Verify that all open timings have related closed timings.
    155   void Verify();
    156   // Clears current timings and labels.
    157   void Reset();
    158   // Starts a timing.
    159   void StartTiming(const char* new_split_label);
    160   // Ends the current timing.
    161   void EndTiming();
    162   // End the current timing and start a new timing. Usage not recommended.
    163   void NewTiming(const char* new_split_label) {
    164     EndTiming();
    165     StartTiming(new_split_label);
    166   }
    167   // Returns the total duration of the timings (sum of total times).
    168   uint64_t GetTotalNs() const;
    169   // Find the index of a timing by name.
    170   size_t FindTimingIndex(const char* name, size_t start_idx) const;
    171   void Dump(std::ostream& os, const char* indent_string = "  ") const;
    172 
    173   // Scoped timing splits that can be nested and composed with the explicit split
    174   // starts and ends.
    175   class ScopedTiming {
    176    public:
    177     ScopedTiming(const char* label, TimingLogger* logger) : logger_(logger) {
    178       logger_->StartTiming(label);
    179     }
    180     ~ScopedTiming() {
    181       logger_->EndTiming();
    182     }
    183     // Closes the current timing and opens a new timing.
    184     void NewTiming(const char* label) {
    185       logger_->NewTiming(label);
    186     }
    187 
    188    private:
    189     TimingLogger* const logger_;  // The timing logger which the scoped timing is associated with.
    190     DISALLOW_COPY_AND_ASSIGN(ScopedTiming);
    191   };
    192 
    193   // Return the time points of when each start / end timings start and finish.
    194   const std::vector<Timing>& GetTimings() const {
    195     return timings_;
    196   }
    197 
    198   TimingData CalculateTimingData() const;
    199 
    200  protected:
    201   // The name of the timing logger.
    202   const char* const name_;
    203   // Do we want to print the exactly recorded split (true) or round down to the time unit being
    204   // used (false).
    205   const bool precise_;
    206   // Verbose logging.
    207   const bool verbose_;
    208   // The kind of timing we want.
    209   const TimingKind kind_;
    210   // Timing points that are either start or end points. For each starting point ret[i] = location
    211   // of end split associated with i. If it is and end split ret[i] = i.
    212   std::vector<Timing> timings_;
    213 
    214  private:
    215   DISALLOW_COPY_AND_ASSIGN(TimingLogger);
    216 };
    217 
    218 }  // namespace art
    219 
    220 #endif  // ART_RUNTIME_BASE_TIMING_LOGGER_H_
    221