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