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
22namespace llvm {
23
24class TimerGlobals;
25class TimerGroup;
26class raw_ostream;
27
28class 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
34public:
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.
82class 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.
93public:
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
142private:
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.
150class TimeRegion {
151 Timer *T;
152 TimeRegion(const TimeRegion &) = delete;
153
154public:
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.
170struct 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.
186class 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
216public:
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
259private:
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