blob: 974a14dd1442511407ccf9f36da639889e0e1898 [file] [log] [blame]
Sameer Abu Asala8439542013-02-14 16:06:42 -08001/*
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
Brian Carlstromfc0e3212013-07-17 14:40:12 -070017#ifndef ART_RUNTIME_BASE_TIMING_LOGGER_H_
18#define ART_RUNTIME_BASE_TIMING_LOGGER_H_
Sameer Abu Asala8439542013-02-14 16:06:42 -080019
20#include "base/histogram.h"
Andreas Gampe0bbac302018-11-30 09:44:12 -080021#include "base/locks.h"
Sameer Abu Asala8439542013-02-14 16:06:42 -080022#include "base/macros.h"
Nicolas Geoffray3d699222017-09-20 15:15:20 +010023#include "base/time_utils.h"
Sameer Abu Asala8439542013-02-14 16:06:42 -080024
Andreas Gampe0bbac302018-11-30 09:44:12 -080025#include <memory>
Mathieu Chartier19b0a912013-11-20 14:07:54 -080026#include <set>
Sameer Abu Asala8439542013-02-14 16:06:42 -080027#include <string>
28#include <vector>
29
30namespace art {
Ian Rogers5fe9af72013-11-14 00:17:20 -080031class TimingLogger;
Ian Rogers1d54e732013-05-02 21:10:01 -070032
Sameer Abu Asala8439542013-02-14 16:06:42 -080033class CumulativeLogger {
Sameer Abu Asala8439542013-02-14 16:06:42 -080034 public:
Ian Rogers45357052013-04-18 20:49:43 -070035 explicit CumulativeLogger(const std::string& name);
Sameer Abu Asala8439542013-02-14 16:06:42 -080036 ~CumulativeLogger();
37 void Start();
Andreas Gampe0bbac302018-11-30 09:44:12 -080038 void End() REQUIRES(!GetLock());
39 void Reset() REQUIRES(!GetLock());
40 void Dump(std::ostream& os) const REQUIRES(!GetLock());
Mathieu Chartierafe49982014-03-27 10:55:04 -070041 uint64_t GetTotalNs() const {
42 return GetTotalTime() * kAdjust;
43 }
Ian Rogers45357052013-04-18 20:49:43 -070044 // Allow the name to be modified, particularly when the cumulative logger is a field within a
45 // parent class that is unable to determine the "name" of a sub-class.
Andreas Gampe0bbac302018-11-30 09:44:12 -080046 void SetName(const std::string& name) REQUIRES(!GetLock());
47 void AddLogger(const TimingLogger& logger) REQUIRES(!GetLock());
48 size_t GetIterations() const REQUIRES(!GetLock());
Sameer Abu Asala8439542013-02-14 16:06:42 -080049
50 private:
Mathieu Chartier19b0a912013-11-20 14:07:54 -080051 class HistogramComparator {
52 public:
53 bool operator()(const Histogram<uint64_t>* a, const Histogram<uint64_t>* b) const {
54 return a->Name() < b->Name();
55 }
56 };
57
58 static constexpr size_t kLowMemoryBucketCount = 16;
59 static constexpr size_t kDefaultBucketCount = 100;
60 static constexpr size_t kInitialBucketSize = 50; // 50 microseconds.
Anwar Ghuloum67f99412013-08-12 14:19:48 -070061
Andreas Gampe0bbac302018-11-30 09:44:12 -080062 void AddPair(const std::string &label, uint64_t delta_time) REQUIRES(GetLock());
63 void DumpHistogram(std::ostream &os) const REQUIRES(GetLock());
Mathieu Chartierafe49982014-03-27 10:55:04 -070064 uint64_t GetTotalTime() const {
65 return total_time_;
66 }
Andreas Gampe0bbac302018-11-30 09:44:12 -080067
68 Mutex* GetLock() const {
69 return lock_.get();
70 }
71
Sameer Abu Asala8439542013-02-14 16:06:42 -080072 static const uint64_t kAdjust = 1000;
Andreas Gampe0bbac302018-11-30 09:44:12 -080073 std::set<Histogram<uint64_t>*, HistogramComparator> histograms_ GUARDED_BY(GetLock());
Sameer Abu Asala8439542013-02-14 16:06:42 -080074 std::string name_;
Ian Rogers45357052013-04-18 20:49:43 -070075 const std::string lock_name_;
Andreas Gampe0bbac302018-11-30 09:44:12 -080076 mutable std::unique_ptr<Mutex> lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
77 size_t iterations_ GUARDED_BY(GetLock());
Mathieu Chartierafe49982014-03-27 10:55:04 -070078 uint64_t total_time_;
Sameer Abu Asala8439542013-02-14 16:06:42 -080079
80 DISALLOW_COPY_AND_ASSIGN(CumulativeLogger);
81};
82
Anwar Ghuloum4446ab92013-08-09 21:17:25 -070083// A timing logger that knows when a split starts for the purposes of logging tools, like systrace.
Anwar Ghuloum6f28d912013-07-24 15:02:53 -070084class TimingLogger {
Ian Rogers1d54e732013-05-02 21:10:01 -070085 public:
Mathieu Chartierf5997b42014-06-20 10:37:54 -070086 static constexpr size_t kIndexNotFound = static_cast<size_t>(-1);
87
Nicolas Geoffray3d699222017-09-20 15:15:20 +010088 // Kind of timing we are going to do. We collect time at the nano second.
89 enum class TimingKind {
90 kMonotonic,
91 kThreadCpu,
92 };
93
Mathieu Chartierf5997b42014-06-20 10:37:54 -070094 class Timing {
95 public:
Nicolas Geoffray3d699222017-09-20 15:15:20 +010096 Timing(TimingKind kind, const char* name) : name_(name) {
97 switch (kind) {
98 case TimingKind::kMonotonic:
99 time_ = NanoTime();
100 break;
101 case TimingKind::kThreadCpu:
102 time_ = ThreadCpuNanoTime();
103 break;
104 }
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700105 }
106 bool IsStartTiming() const {
107 return !IsEndTiming();
108 }
109 bool IsEndTiming() const {
110 return name_ == nullptr;
111 }
112 uint64_t GetTime() const {
113 return time_;
114 }
115 const char* GetName() const {
116 return name_;
117 }
118
119 private:
120 uint64_t time_;
121 const char* name_;
122 };
123
124 // Extra data that is only calculated when you call dump to prevent excess allocation.
125 class TimingData {
126 public:
127 TimingData() = default;
128 TimingData(TimingData&& other) {
129 std::swap(data_, other.data_);
130 }
131 TimingData& operator=(TimingData&& other) {
132 std::swap(data_, other.data_);
133 return *this;
134 }
135 uint64_t GetTotalTime(size_t idx) {
136 return data_[idx].total_time;
137 }
138 uint64_t GetExclusiveTime(size_t idx) {
139 return data_[idx].exclusive_time;
140 }
141
142 private:
143 // Each begin split has a total time and exclusive time. Exclusive time is total time - total
144 // time of children nodes.
145 struct CalculatedDataPoint {
146 CalculatedDataPoint() : total_time(0), exclusive_time(0) {}
147 uint64_t total_time;
148 uint64_t exclusive_time;
149 };
150 std::vector<CalculatedDataPoint> data_;
151 friend class TimingLogger;
152 };
Anwar Ghuloum4446ab92013-08-09 21:17:25 -0700153
Nicolas Geoffray3d699222017-09-20 15:15:20 +0100154 TimingLogger(const char* name,
155 bool precise,
156 bool verbose,
157 TimingKind kind = TimingKind::kMonotonic);
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700158 ~TimingLogger();
159 // Verify that all open timings have related closed timings.
160 void Verify();
161 // Clears current timings and labels.
Ian Rogers1d54e732013-05-02 21:10:01 -0700162 void Reset();
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700163 // Starts a timing.
164 void StartTiming(const char* new_split_label);
165 // Ends the current timing.
166 void EndTiming();
167 // End the current timing and start a new timing. Usage not recommended.
168 void NewTiming(const char* new_split_label) {
169 EndTiming();
170 StartTiming(new_split_label);
171 }
172 // Returns the total duration of the timings (sum of total times).
Ian Rogers1d54e732013-05-02 21:10:01 -0700173 uint64_t GetTotalNs() const;
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700174 // Find the index of a timing by name.
175 size_t FindTimingIndex(const char* name, size_t start_idx) const;
176 void Dump(std::ostream& os, const char* indent_string = " ") const;
Ian Rogers1d54e732013-05-02 21:10:01 -0700177
Anwar Ghuloum4446ab92013-08-09 21:17:25 -0700178 // Scoped timing splits that can be nested and composed with the explicit split
179 // starts and ends.
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700180 class ScopedTiming {
181 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100182 ScopedTiming(const char* label, TimingLogger* logger) : logger_(logger) {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700183 logger_->StartTiming(label);
184 }
185 ~ScopedTiming() {
186 logger_->EndTiming();
187 }
188 // Closes the current timing and opens a new timing.
189 void NewTiming(const char* label) {
190 logger_->NewTiming(label);
191 }
Anwar Ghuloum4446ab92013-08-09 21:17:25 -0700192
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700193 private:
194 TimingLogger* const logger_; // The timing logger which the scoped timing is associated with.
195 DISALLOW_COPY_AND_ASSIGN(ScopedTiming);
Anwar Ghuloum4446ab92013-08-09 21:17:25 -0700196 };
197
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700198 // Return the time points of when each start / end timings start and finish.
199 const std::vector<Timing>& GetTimings() const {
200 return timings_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700201 }
202
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700203 TimingData CalculateTimingData() const;
204
Ian Rogers1d54e732013-05-02 21:10:01 -0700205 protected:
206 // The name of the timing logger.
Ian Rogers5fe9af72013-11-14 00:17:20 -0800207 const char* const name_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700208 // Do we want to print the exactly recorded split (true) or round down to the time unit being
209 // used (false).
210 const bool precise_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700211 // Verbose logging.
212 const bool verbose_;
Nicolas Geoffray3d699222017-09-20 15:15:20 +0100213 // The kind of timing we want.
214 const TimingKind kind_;
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700215 // Timing points that are either start or end points. For each starting point ret[i] = location
216 // of end split associated with i. If it is and end split ret[i] = i.
217 std::vector<Timing> timings_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700218
219 private:
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700220 DISALLOW_COPY_AND_ASSIGN(TimingLogger);
Ian Rogers1d54e732013-05-02 21:10:01 -0700221};
222
Sameer Abu Asala8439542013-02-14 16:06:42 -0800223} // namespace art
224
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700225#endif // ART_RUNTIME_BASE_TIMING_LOGGER_H_