blob: a8a6701822d759ca5d187f583de63917ea0af073 [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"
21#include "base/macros.h"
22#include "base/mutex.h"
Nicolas Geoffray3d699222017-09-20 15:15:20 +010023#include "base/time_utils.h"
Sameer Abu Asala8439542013-02-14 16:06:42 -080024
Mathieu Chartier19b0a912013-11-20 14:07:54 -080025#include <set>
Sameer Abu Asala8439542013-02-14 16:06:42 -080026#include <string>
27#include <vector>
28
29namespace art {
Ian Rogers5fe9af72013-11-14 00:17:20 -080030class TimingLogger;
Ian Rogers1d54e732013-05-02 21:10:01 -070031
Sameer Abu Asala8439542013-02-14 16:06:42 -080032class CumulativeLogger {
Sameer Abu Asala8439542013-02-14 16:06:42 -080033 public:
Ian Rogers45357052013-04-18 20:49:43 -070034 explicit CumulativeLogger(const std::string& name);
Sameer Abu Asala8439542013-02-14 16:06:42 -080035 ~CumulativeLogger();
36 void Start();
Mathieu Chartier90443472015-07-16 20:32:27 -070037 void End() REQUIRES(!lock_);
38 void Reset() REQUIRES(!lock_);
39 void Dump(std::ostream& os) const REQUIRES(!lock_);
Mathieu Chartierafe49982014-03-27 10:55:04 -070040 uint64_t GetTotalNs() const {
41 return GetTotalTime() * kAdjust;
42 }
Ian Rogers45357052013-04-18 20:49:43 -070043 // 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.
Mathieu Chartier90443472015-07-16 20:32:27 -070045 void SetName(const std::string& name) REQUIRES(!lock_);
46 void AddLogger(const TimingLogger& logger) REQUIRES(!lock_);
47 size_t GetIterations() const REQUIRES(!lock_);
Sameer Abu Asala8439542013-02-14 16:06:42 -080048
49 private:
Mathieu Chartier19b0a912013-11-20 14:07:54 -080050 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.
Anwar Ghuloum67f99412013-08-12 14:19:48 -070060
Sameer Abu Asala8439542013-02-14 16:06:42 -080061 void AddPair(const std::string &label, uint64_t delta_time)
Mathieu Chartier90443472015-07-16 20:32:27 -070062 REQUIRES(lock_);
63 void DumpHistogram(std::ostream &os) const REQUIRES(lock_);
Mathieu Chartierafe49982014-03-27 10:55:04 -070064 uint64_t GetTotalTime() const {
65 return total_time_;
66 }
Sameer Abu Asala8439542013-02-14 16:06:42 -080067 static const uint64_t kAdjust = 1000;
Mathieu Chartier19b0a912013-11-20 14:07:54 -080068 std::set<Histogram<uint64_t>*, HistogramComparator> histograms_ GUARDED_BY(lock_);
Sameer Abu Asala8439542013-02-14 16:06:42 -080069 std::string name_;
Ian Rogers45357052013-04-18 20:49:43 -070070 const std::string lock_name_;
Sameer Abu Asala8439542013-02-14 16:06:42 -080071 mutable Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
Sameer Abu Asala8439542013-02-14 16:06:42 -080072 size_t iterations_ GUARDED_BY(lock_);
Mathieu Chartierafe49982014-03-27 10:55:04 -070073 uint64_t total_time_;
Sameer Abu Asala8439542013-02-14 16:06:42 -080074
75 DISALLOW_COPY_AND_ASSIGN(CumulativeLogger);
76};
77
Anwar Ghuloum4446ab92013-08-09 21:17:25 -070078// A timing logger that knows when a split starts for the purposes of logging tools, like systrace.
Anwar Ghuloum6f28d912013-07-24 15:02:53 -070079class TimingLogger {
Ian Rogers1d54e732013-05-02 21:10:01 -070080 public:
Mathieu Chartierf5997b42014-06-20 10:37:54 -070081 static constexpr size_t kIndexNotFound = static_cast<size_t>(-1);
82
Nicolas Geoffray3d699222017-09-20 15:15:20 +010083 // 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
Mathieu Chartierf5997b42014-06-20 10:37:54 -070089 class Timing {
90 public:
Nicolas Geoffray3d699222017-09-20 15:15:20 +010091 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 }
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700100 }
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 };
Anwar Ghuloum4446ab92013-08-09 21:17:25 -0700148
Nicolas Geoffray3d699222017-09-20 15:15:20 +0100149 TimingLogger(const char* name,
150 bool precise,
151 bool verbose,
152 TimingKind kind = TimingKind::kMonotonic);
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700153 ~TimingLogger();
154 // Verify that all open timings have related closed timings.
155 void Verify();
156 // Clears current timings and labels.
Ian Rogers1d54e732013-05-02 21:10:01 -0700157 void Reset();
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700158 // 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).
Ian Rogers1d54e732013-05-02 21:10:01 -0700168 uint64_t GetTotalNs() const;
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700169 // 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;
Ian Rogers1d54e732013-05-02 21:10:01 -0700172
Anwar Ghuloum4446ab92013-08-09 21:17:25 -0700173 // Scoped timing splits that can be nested and composed with the explicit split
174 // starts and ends.
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700175 class ScopedTiming {
176 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100177 ScopedTiming(const char* label, TimingLogger* logger) : logger_(logger) {
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700178 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 }
Anwar Ghuloum4446ab92013-08-09 21:17:25 -0700187
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700188 private:
189 TimingLogger* const logger_; // The timing logger which the scoped timing is associated with.
190 DISALLOW_COPY_AND_ASSIGN(ScopedTiming);
Anwar Ghuloum4446ab92013-08-09 21:17:25 -0700191 };
192
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700193 // Return the time points of when each start / end timings start and finish.
194 const std::vector<Timing>& GetTimings() const {
195 return timings_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700196 }
197
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700198 TimingData CalculateTimingData() const;
199
Ian Rogers1d54e732013-05-02 21:10:01 -0700200 protected:
201 // The name of the timing logger.
Ian Rogers5fe9af72013-11-14 00:17:20 -0800202 const char* const name_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700203 // 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_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700206 // Verbose logging.
207 const bool verbose_;
Nicolas Geoffray3d699222017-09-20 15:15:20 +0100208 // The kind of timing we want.
209 const TimingKind kind_;
Mathieu Chartierf5997b42014-06-20 10:37:54 -0700210 // 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_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700213
214 private:
Anwar Ghuloum6f28d912013-07-24 15:02:53 -0700215 DISALLOW_COPY_AND_ASSIGN(TimingLogger);
Ian Rogers1d54e732013-05-02 21:10:01 -0700216};
217
Sameer Abu Asala8439542013-02-14 16:06:42 -0800218} // namespace art
219
Brian Carlstromfc0e3212013-07-17 14:40:12 -0700220#endif // ART_RUNTIME_BASE_TIMING_LOGGER_H_