xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/Timer.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
getProcessTime()43   double getProcessTime() const { return UserTime + SystemTime; }
getUserTime()44   double getUserTime() const { return UserTime; }
getSystemTime()45   double getSystemTime() const { return SystemTime; }
getWallTime()46   double getWallTime() const { return WallTime; }
getMemUsed()47   ssize_t getMemUsed() const { return MemUsed; }
getInstructionsExecuted()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:
Timer(StringRef TimerName,StringRef TimerDescription)94   explicit Timer(StringRef TimerName, StringRef TimerDescription) {
95     init(TimerName, TimerDescription);
96   }
Timer(StringRef TimerName,StringRef TimerDescription,TimerGroup & tg)97   Timer(StringRef TimerName, StringRef TimerDescription, TimerGroup &tg) {
98     init(TimerName, TimerDescription, tg);
99   }
Timer(const Timer & RHS)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 
getName()115   const std::string &getName() const { return Name; }
getDescription()116   const std::string &getDescription() const { return Description; }
isInitialized()117   bool isInitialized() const { return TG != nullptr; }
118 
119   /// Check if the timer is currently running.
isRunning()120   bool isRunning() const { return Running; }
121 
122   /// Check if startTimer() has ever been called on this timer.
hasTriggered()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.
getTotalTime()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:
TimeRegion(Timer & t)155   explicit TimeRegion(Timer &t) : T(&t) {
156     T->startTimer();
157   }
TimeRegion(Timer * t)158   explicit TimeRegion(Timer *t) : T(t) {
159     if (T) T->startTimer();
160   }
~TimeRegion()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;
PrintRecordPrintRecord194     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 
setName(StringRef NewName,StringRef NewDescription)224   void setName(StringRef NewName, StringRef NewDescription) {
225     Name.assign(NewName.begin(), NewName.end());
226     Description.assign(NewDescription.begin(), 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