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/DataTypes.h"
15 #include <cassert>
16 #include <string>
17 #include <utility>
18 #include <vector>
19 
20 namespace llvm {
21 
22 class Timer;
23 class TimerGroup;
24 class raw_ostream;
25 
26 class TimeRecord {
27   double WallTime;               ///< Wall clock time elapsed in seconds.
28   double UserTime;               ///< User time elapsed.
29   double SystemTime;             ///< System time elapsed.
30   ssize_t MemUsed;               ///< Memory allocated (in bytes).
31   uint64_t InstructionsExecuted; ///< Number of instructions executed
32 public:
33   TimeRecord()
34       : WallTime(0), UserTime(0), SystemTime(0), MemUsed(0),
35         InstructionsExecuted(0) {}
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   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   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   ~Timer();
108 
109   /// Create an uninitialized timer, client must use 'init'.
110   explicit Timer() {}
111   void init(StringRef TimerName, StringRef TimerDescription);
112   void init(StringRef TimerName, StringRef TimerDescription, TimerGroup &tg);
113 
114   const std::string &getName() const { return Name; }
115   const std::string &getDescription() const { return Description; }
116   bool isInitialized() const { return TG != nullptr; }
117 
118   /// Check if the timer is currently running.
119   bool isRunning() const { return Running; }
120 
121   /// Check if startTimer() has ever been called on this timer.
122   bool hasTriggered() const { return Triggered; }
123 
124   /// Start the timer running.  Time between calls to startTimer/stopTimer is
125   /// counted by the Timer class.  Note that these calls must be correctly
126   /// paired.
127   void startTimer();
128 
129   /// Stop the timer.
130   void stopTimer();
131 
132   /// Clear the timer state.
133   void clear();
134 
135   /// Return the duration for which this timer has been running.
136   TimeRecord getTotalTime() const { return Time; }
137 
138 private:
139   friend class TimerGroup;
140 };
141 
142 /// The TimeRegion class is used as a helper class to call the startTimer() and
143 /// stopTimer() methods of the Timer class.  When the object is constructed, it
144 /// starts the timer specified as its argument.  When it is destroyed, it stops
145 /// the relevant timer.  This makes it easy to time a region of code.
146 class TimeRegion {
147   Timer *T;
148   TimeRegion(const TimeRegion &) = delete;
149 
150 public:
151   explicit TimeRegion(Timer &t) : T(&t) {
152     T->startTimer();
153   }
154   explicit TimeRegion(Timer *t) : T(t) {
155     if (T) T->startTimer();
156   }
157   ~TimeRegion() {
158     if (T) T->stopTimer();
159   }
160 };
161 
162 /// This class is basically a combination of TimeRegion and Timer.  It allows
163 /// you to declare a new timer, AND specify the region to time, all in one
164 /// statement.  All timers with the same name are merged.  This is primarily
165 /// used for debugging and for hunting performance problems.
166 struct NamedRegionTimer : public TimeRegion {
167   explicit NamedRegionTimer(StringRef Name, StringRef Description,
168                             StringRef GroupName,
169                             StringRef GroupDescription, bool Enabled = true);
170 };
171 
172 /// The TimerGroup class is used to group together related timers into a single
173 /// report that is printed when the TimerGroup is destroyed.  It is illegal to
174 /// destroy a TimerGroup object before all of the Timers in it are gone.  A
175 /// TimerGroup can be specified for a newly created timer in its constructor.
176 class TimerGroup {
177   struct PrintRecord {
178     TimeRecord Time;
179     std::string Name;
180     std::string Description;
181 
182     PrintRecord(const PrintRecord &Other) = default;
183     PrintRecord &operator=(const PrintRecord &Other) = default;
184     PrintRecord(const TimeRecord &Time, const std::string &Name,
185                 const std::string &Description)
186       : Time(Time), Name(Name), Description(Description) {}
187 
188     bool operator <(const PrintRecord &Other) const {
189       return Time < Other.Time;
190     }
191   };
192   std::string Name;
193   std::string Description;
194   Timer *FirstTimer = nullptr; ///< First timer in the group.
195   std::vector<PrintRecord> TimersToPrint;
196 
197   TimerGroup **Prev; ///< Pointer to Next field of previous timergroup in list.
198   TimerGroup *Next;  ///< Pointer to next timergroup in list.
199   TimerGroup(const TimerGroup &TG) = delete;
200   void operator=(const TimerGroup &TG) = delete;
201 
202 public:
203   explicit TimerGroup(StringRef Name, StringRef Description);
204 
205   explicit TimerGroup(StringRef Name, StringRef Description,
206                       const StringMap<TimeRecord> &Records);
207 
208   ~TimerGroup();
209 
210   void setName(StringRef NewName, StringRef NewDescription) {
211     Name.assign(NewName.begin(), NewName.end());
212     Description.assign(NewDescription.begin(), NewDescription.end());
213   }
214 
215   /// Print any started timers in this group, optionally resetting timers after
216   /// printing them.
217   void print(raw_ostream &OS, bool ResetAfterPrint = false);
218 
219   /// Clear all timers in this group.
220   void clear();
221 
222   /// This static method prints all timers.
223   static void printAll(raw_ostream &OS);
224 
225   /// Clear out all timers. This is mostly used to disable automatic
226   /// printing on shutdown, when timers have already been printed explicitly
227   /// using \c printAll or \c printJSONValues.
228   static void clearAll();
229 
230   const char *printJSONValues(raw_ostream &OS, const char *delim);
231 
232   /// Prints all timers as JSON key/value pairs.
233   static const char *printAllJSONValues(raw_ostream &OS, const char *delim);
234 
235   /// Ensure global timer group lists are initialized. This function is mostly
236   /// used by the Statistic code to influence the construction and destruction
237   /// order of the global timer lists.
238   static void ConstructTimerLists();
239 
240   /// This makes the default group unmanaged, and lets the user manage the
241   /// group's lifetime.
242   static std::unique_ptr<TimerGroup> aquireDefaultGroup();
243 
244 private:
245   friend class Timer;
246   friend void PrintStatisticsJSON(raw_ostream &OS);
247   void addTimer(Timer &T);
248   void removeTimer(Timer &T);
249   void prepareToPrintList(bool reset_time = false);
250   void PrintQueuedTimers(raw_ostream &OS);
251   void printJSONValue(raw_ostream &OS, const PrintRecord &R,
252                       const char *suffix, double Value);
253 };
254 
255 } // end namespace llvm
256 
257 #endif
258