1 | //===-- llvm/Support/Timer.h - Interval Timing Support ----------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef LLVM_SUPPORT_TIMER_H |
10 | #define LLVM_SUPPORT_TIMER_H |
11 | |
12 | #include "llvm/ADT/StringMap.h" |
13 | #include "llvm/ADT/StringRef.h" |
14 | #include "llvm/Support/Compiler.h" |
15 | #include "llvm/Support/DataTypes.h" |
16 | #include "llvm/Support/Mutex.h" |
17 | #include <cassert> |
18 | #include <memory> |
19 | #include <string> |
20 | #include <vector> |
21 | |
22 | namespace llvm { |
23 | |
24 | class TimerGlobals; |
25 | class TimerGroup; |
26 | class raw_ostream; |
27 | |
28 | class TimeRecord { |
29 | double WallTime = 0.0; ///< Wall clock time elapsed in seconds. |
30 | double UserTime = 0.0; ///< User time elapsed. |
31 | double SystemTime = 0.0; ///< System time elapsed. |
32 | ssize_t MemUsed = 0; ///< Memory allocated (in bytes). |
33 | uint64_t InstructionsExecuted = 0; ///< Number of instructions executed |
34 | public: |
35 | TimeRecord() = default; |
36 | |
37 | /// Get the current time and memory usage. If Start is true we get the memory |
38 | /// usage before the time, otherwise we get time before memory usage. This |
39 | /// matters if the time to get the memory usage is significant and shouldn't |
40 | /// be counted as part of a duration. |
41 | LLVM_ABI static TimeRecord getCurrentTime(bool Start = true); |
42 | |
43 | double getProcessTime() const { return UserTime + SystemTime; } |
44 | double getUserTime() const { return UserTime; } |
45 | double getSystemTime() const { return SystemTime; } |
46 | double getWallTime() const { return WallTime; } |
47 | ssize_t getMemUsed() const { return MemUsed; } |
48 | uint64_t getInstructionsExecuted() const { return InstructionsExecuted; } |
49 | |
50 | bool operator<(const TimeRecord &T) const { |
51 | // Sort by Wall Time elapsed, as it is the only thing really accurate |
52 | return WallTime < T.WallTime; |
53 | } |
54 | |
55 | void operator+=(const TimeRecord &RHS) { |
56 | WallTime += RHS.WallTime; |
57 | UserTime += RHS.UserTime; |
58 | SystemTime += RHS.SystemTime; |
59 | MemUsed += RHS.MemUsed; |
60 | InstructionsExecuted += RHS.InstructionsExecuted; |
61 | } |
62 | void operator-=(const TimeRecord &RHS) { |
63 | WallTime -= RHS.WallTime; |
64 | UserTime -= RHS.UserTime; |
65 | SystemTime -= RHS.SystemTime; |
66 | MemUsed -= RHS.MemUsed; |
67 | InstructionsExecuted -= RHS.InstructionsExecuted; |
68 | } |
69 | |
70 | /// Print the current time record to \p OS, with a breakdown showing |
71 | /// contributions to the \p Total time record. |
72 | LLVM_ABI void print(const TimeRecord &Total, raw_ostream &OS) const; |
73 | }; |
74 | |
75 | /// This class is used to track the amount of time spent between invocations of |
76 | /// its startTimer()/stopTimer() methods. Given appropriate OS support it can |
77 | /// also keep track of the RSS of the program at various points. By default, |
78 | /// the Timer will print the amount of time it has captured to standard error |
79 | /// when the last timer is destroyed, otherwise it is printed when its |
80 | /// TimerGroup is destroyed. Timers do not print their information if they are |
81 | /// never started. |
82 | class Timer { |
83 | TimeRecord Time; ///< The total time captured. |
84 | TimeRecord StartTime; ///< The time startTimer() was last called. |
85 | std::string Name; ///< The name of this time variable. |
86 | std::string Description; ///< Description of this time variable. |
87 | bool Running = false; ///< Is the timer currently running? |
88 | bool Triggered = false; ///< Has the timer ever been triggered? |
89 | TimerGroup *TG = nullptr; ///< The TimerGroup this Timer is in. |
90 | |
91 | Timer **Prev = nullptr; ///< Pointer to \p Next of previous timer in group. |
92 | Timer *Next = nullptr; ///< Next timer in the group. |
93 | public: |
94 | explicit Timer(StringRef TimerName, StringRef TimerDescription) { |
95 | init(TimerName, TimerDescription); |
96 | } |
97 | Timer(StringRef TimerName, StringRef TimerDescription, TimerGroup &tg) { |
98 | init(TimerName, TimerDescription, tg); |
99 | } |
100 | Timer(const Timer &RHS) { |
101 | assert(!RHS.TG && "Can only copy uninitialized timers" ); |
102 | } |
103 | const Timer &operator=(const Timer &T) { |
104 | assert(!TG && !T.TG && "Can only assign uninit timers" ); |
105 | return *this; |
106 | } |
107 | LLVM_ABI ~Timer(); |
108 | |
109 | /// Create an uninitialized timer, client must use 'init'. |
110 | explicit Timer() = default; |
111 | LLVM_ABI void init(StringRef TimerName, StringRef TimerDescription); |
112 | LLVM_ABI void init(StringRef TimerName, StringRef TimerDescription, |
113 | TimerGroup &tg); |
114 | |
115 | const std::string &getName() const { return Name; } |
116 | const std::string &getDescription() const { return Description; } |
117 | bool isInitialized() const { return TG != nullptr; } |
118 | |
119 | /// Check if the timer is currently running. |
120 | bool isRunning() const { return Running; } |
121 | |
122 | /// Check if startTimer() has ever been called on this timer. |
123 | bool hasTriggered() const { return Triggered; } |
124 | |
125 | /// Start the timer running. Time between calls to startTimer/stopTimer is |
126 | /// counted by the Timer class. Note that these calls must be correctly |
127 | /// paired. |
128 | LLVM_ABI void startTimer(); |
129 | |
130 | /// Stop the timer. |
131 | LLVM_ABI void stopTimer(); |
132 | |
133 | /// Clear the timer state. |
134 | LLVM_ABI void clear(); |
135 | |
136 | /// Stop the timer and start another timer. |
137 | LLVM_ABI void yieldTo(Timer &); |
138 | |
139 | /// Return the duration for which this timer has been running. |
140 | TimeRecord getTotalTime() const { return Time; } |
141 | |
142 | private: |
143 | friend class TimerGroup; |
144 | }; |
145 | |
146 | /// The TimeRegion class is used as a helper class to call the startTimer() and |
147 | /// stopTimer() methods of the Timer class. When the object is constructed, it |
148 | /// starts the timer specified as its argument. When it is destroyed, it stops |
149 | /// the relevant timer. This makes it easy to time a region of code. |
150 | class TimeRegion { |
151 | Timer *T; |
152 | TimeRegion(const TimeRegion &) = delete; |
153 | |
154 | public: |
155 | explicit TimeRegion(Timer &t) : T(&t) { |
156 | T->startTimer(); |
157 | } |
158 | explicit TimeRegion(Timer *t) : T(t) { |
159 | if (T) T->startTimer(); |
160 | } |
161 | ~TimeRegion() { |
162 | if (T) T->stopTimer(); |
163 | } |
164 | }; |
165 | |
166 | /// This class is basically a combination of TimeRegion and Timer. It allows |
167 | /// you to declare a new timer, AND specify the region to time, all in one |
168 | /// statement. All timers with the same name are merged. This is primarily |
169 | /// used for debugging and for hunting performance problems. |
170 | struct NamedRegionTimer : public TimeRegion { |
171 | LLVM_ABI explicit NamedRegionTimer(StringRef Name, StringRef Description, |
172 | StringRef GroupName, |
173 | StringRef GroupDescription, |
174 | bool Enabled = true); |
175 | |
176 | // Create or get a TimerGroup stored in the same global map owned by |
177 | // NamedRegionTimer. |
178 | LLVM_ABI static TimerGroup &getNamedTimerGroup(StringRef GroupName, |
179 | StringRef GroupDescription); |
180 | }; |
181 | |
182 | /// The TimerGroup class is used to group together related timers into a single |
183 | /// report that is printed when the TimerGroup is destroyed. It is illegal to |
184 | /// destroy a TimerGroup object before all of the Timers in it are gone. A |
185 | /// TimerGroup can be specified for a newly created timer in its constructor. |
186 | class TimerGroup { |
187 | struct PrintRecord { |
188 | TimeRecord Time; |
189 | std::string Name; |
190 | std::string Description; |
191 | |
192 | PrintRecord(const PrintRecord &Other) = default; |
193 | PrintRecord &operator=(const PrintRecord &Other) = default; |
194 | PrintRecord(const TimeRecord &Time, const std::string &Name, |
195 | const std::string &Description) |
196 | : Time(Time), Name(Name), Description(Description) {} |
197 | |
198 | bool operator <(const PrintRecord &Other) const { |
199 | return Time < Other.Time; |
200 | } |
201 | }; |
202 | std::string Name; |
203 | std::string Description; |
204 | Timer *FirstTimer = nullptr; ///< First timer in the group. |
205 | std::vector<PrintRecord> TimersToPrint; |
206 | |
207 | TimerGroup **Prev; ///< Pointer to Next field of previous timergroup in list. |
208 | TimerGroup *Next; ///< Pointer to next timergroup in list. |
209 | TimerGroup(const TimerGroup &TG) = delete; |
210 | void operator=(const TimerGroup &TG) = delete; |
211 | |
212 | friend class TimerGlobals; |
213 | explicit TimerGroup(StringRef Name, StringRef Description, |
214 | sys::SmartMutex<true> &lock); |
215 | |
216 | public: |
217 | LLVM_ABI explicit TimerGroup(StringRef Name, StringRef Description); |
218 | |
219 | LLVM_ABI explicit TimerGroup(StringRef Name, StringRef Description, |
220 | const StringMap<TimeRecord> &Records); |
221 | |
222 | LLVM_ABI ~TimerGroup(); |
223 | |
224 | void setName(StringRef NewName, StringRef NewDescription) { |
225 | Name.assign(first: NewName.begin(), last: NewName.end()); |
226 | Description.assign(first: NewDescription.begin(), last: NewDescription.end()); |
227 | } |
228 | |
229 | /// Print any started timers in this group, optionally resetting timers after |
230 | /// printing them. |
231 | LLVM_ABI void print(raw_ostream &OS, bool ResetAfterPrint = false); |
232 | |
233 | /// Clear all timers in this group. |
234 | LLVM_ABI void clear(); |
235 | |
236 | /// This static method prints all timers. |
237 | LLVM_ABI static void printAll(raw_ostream &OS); |
238 | |
239 | /// Clear out all timers. This is mostly used to disable automatic |
240 | /// printing on shutdown, when timers have already been printed explicitly |
241 | /// using \c printAll or \c printJSONValues. |
242 | LLVM_ABI static void clearAll(); |
243 | |
244 | LLVM_ABI const char *printJSONValues(raw_ostream &OS, const char *delim); |
245 | |
246 | /// Prints all timers as JSON key/value pairs. |
247 | LLVM_ABI static const char *printAllJSONValues(raw_ostream &OS, |
248 | const char *delim); |
249 | |
250 | /// Ensure global objects required for statistics printing are initialized. |
251 | /// This function is used by the Statistic code to ensure correct order of |
252 | /// global constructors and destructors. |
253 | LLVM_ABI static void constructForStatistics(); |
254 | |
255 | /// This makes the timer globals unmanaged, and lets the user manage the |
256 | /// lifetime. |
257 | LLVM_ABI static void *acquireTimerGlobals(); |
258 | |
259 | private: |
260 | friend class Timer; |
261 | LLVM_ABI friend void PrintStatisticsJSON(raw_ostream &OS); |
262 | void addTimer(Timer &T); |
263 | void removeTimer(Timer &T); |
264 | void prepareToPrintList(bool reset_time = false); |
265 | void PrintQueuedTimers(raw_ostream &OS); |
266 | void printJSONValue(raw_ostream &OS, const PrintRecord &R, |
267 | const char *suffix, double Value); |
268 | }; |
269 | |
270 | } // end namespace llvm |
271 | |
272 | #endif |
273 | |