summaryrefslogtreecommitdiffstats
path: root/runtime/base/timing_logger.h
blob: f1f78557aae145311a2e2c16964023b454f5eafb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_RUNTIME_BASE_TIMING_LOGGER_H_
#define ART_RUNTIME_BASE_TIMING_LOGGER_H_

#include "base/histogram.h"
#include "base/macros.h"
#include "base/mutex.h"

#include <string>
#include <vector>
#include <map>

namespace art {
class TimingLogger;

class CumulativeLogger {
 public:
  explicit CumulativeLogger(const std::string& name);
  void prepare_stats();
  ~CumulativeLogger();
  void Start();
  void End();
  void Reset();
  void Dump(std::ostream& os) LOCKS_EXCLUDED(lock_);
  uint64_t GetTotalNs() const;
  // Allow the name to be modified, particularly when the cumulative logger is a field within a
  // parent class that is unable to determine the "name" of a sub-class.
  void SetName(const std::string& name);
  void AddLogger(const TimingLogger& logger) LOCKS_EXCLUDED(lock_);
  size_t GetIterations() const;

 private:
  typedef std::map<std::string, Histogram<uint64_t> *> Histograms;
  typedef std::map<std::string, Histogram<uint64_t> *>::const_iterator HistogramsIterator;

  void AddPair(const std::string &label, uint64_t delta_time)
      EXCLUSIVE_LOCKS_REQUIRED(lock_);
  void DumpHistogram(std::ostream &os) EXCLUSIVE_LOCKS_REQUIRED(lock_);
  uint64_t GetTotalTime() const;
  static const uint64_t kAdjust = 1000;
  Histograms histograms_ GUARDED_BY(lock_);
  std::string name_;
  const std::string lock_name_;
  mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
  size_t iterations_ GUARDED_BY(lock_);

  DISALLOW_COPY_AND_ASSIGN(CumulativeLogger);
};

// A timing logger that knows when a split starts for the purposes of logging tools, like systrace.
class TimingLogger {
 public:
  // Splits are nanosecond times and split names.
  typedef std::pair<uint64_t, const char*> SplitTiming;
  typedef std::vector<SplitTiming> SplitTimings;

  explicit TimingLogger(const char* name, bool precise, bool verbose);
  ~TimingLogger() {
    // TODO: DCHECK(current_split_ == nullptr) << "Forgot to end split: " << current_split_->label_;
  }
  // Clears current splits and labels.
  void Reset();

  // Starts a split
  void StartSplit(const char* new_split_label);

  // Ends the current split and starts the one given by the label.
  void NewSplit(const char* new_split_label);

  // Ends the current split and records the end time.
  void EndSplit();

  uint64_t GetTotalNs() const;

  void Dump(std::ostream& os) const;

  // Scoped timing splits that can be nested and composed with the explicit split
  // starts and ends.
  class ScopedSplit {
    public:
      explicit ScopedSplit(const char* label, TimingLogger* timing_logger);

      ~ScopedSplit();

      friend class TimingLogger;

    private:
      // Pauses timing of the split, usually due to nesting of another split.
      void Pause();

      // Resumes timing of the split, usually because a nested split has ended.
      void Resume();

      // Used by new split to swap splits in place in a ScopedSplit instance.
      void TailInsertSplit(const char* label);

      // The scoped split immediately enclosing this split. Essentially, we get a
      // stack of nested splits through this field.
      ScopedSplit* enclosing_split_;

      // Was this created via TimingLogger's StartSplit?
      bool explicit_;

      // The split's name.
      const char* label_;

      // The current split's latest start time. (It may have been paused and restarted.)
      uint64_t start_ns_;

      // The running time, outside of pauses.
      uint64_t running_ns_;

      // The timing logger holding this split.
      TimingLogger* timing_logger_;

      DISALLOW_COPY_AND_ASSIGN(ScopedSplit);
  };

  const SplitTimings& GetSplits() const {
    return splits_;
  }

  friend class ScopedSplit;
 protected:
  // The name of the timing logger.
  const char* const name_;

  // Do we want to print the exactly recorded split (true) or round down to the time unit being
  // used (false).
  const bool precise_;

  // Verbose logging.
  const bool verbose_;

  // The current scoped split is also the 'top' of the stack of splits in progress.
  ScopedSplit* current_split_;

  // Splits that have ended.
  SplitTimings splits_;

 private:
  DISALLOW_COPY_AND_ASSIGN(TimingLogger);
};

}  // namespace art

#endif  // ART_RUNTIME_BASE_TIMING_LOGGER_H_