1193323Sed//===-- llvm/Support/Timer.h - Interval Timing Support ----------*- C++ -*-===//
2193323Sed//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6193323Sed//
7193323Sed//===----------------------------------------------------------------------===//
8193323Sed
9193323Sed#ifndef LLVM_SUPPORT_TIMER_H
10193323Sed#define LLVM_SUPPORT_TIMER_H
11193323Sed
12341825Sdim#include "llvm/ADT/StringMap.h"
13249423Sdim#include "llvm/ADT/StringRef.h"
14218893Sdim#include "llvm/Support/DataTypes.h"
15206083Srdivacky#include <cassert>
16193323Sed#include <string>
17249423Sdim#include <utility>
18193323Sed#include <vector>
19193323Sed
20193323Sednamespace llvm {
21193323Sed
22206083Srdivackyclass Timer;
23193323Sedclass TimerGroup;
24198090Srdivackyclass raw_ostream;
25193323Sed
26206083Srdivackyclass TimeRecord {
27314564Sdim  double WallTime;       ///< Wall clock time elapsed in seconds.
28314564Sdim  double UserTime;       ///< User time elapsed.
29314564Sdim  double SystemTime;     ///< System time elapsed.
30314564Sdim  ssize_t MemUsed;       ///< Memory allocated (in bytes).
31206083Srdivackypublic:
32206083Srdivacky  TimeRecord() : WallTime(0), UserTime(0), SystemTime(0), MemUsed(0) {}
33296417Sdim
34314564Sdim  /// Get the current time and memory usage.  If Start is true we get the memory
35314564Sdim  /// usage before the time, otherwise we get time before memory usage.  This
36314564Sdim  /// matters if the time to get the memory usage is significant and shouldn't
37314564Sdim  /// be counted as part of a duration.
38206083Srdivacky  static TimeRecord getCurrentTime(bool Start = true);
39296417Sdim
40296417Sdim  double getProcessTime() const { return UserTime + SystemTime; }
41206083Srdivacky  double getUserTime() const { return UserTime; }
42206083Srdivacky  double getSystemTime() const { return SystemTime; }
43206083Srdivacky  double getWallTime() const { return WallTime; }
44206083Srdivacky  ssize_t getMemUsed() const { return MemUsed; }
45296417Sdim
46206083Srdivacky  bool operator<(const TimeRecord &T) const {
47206083Srdivacky    // Sort by Wall Time elapsed, as it is the only thing really accurate
48206083Srdivacky    return WallTime < T.WallTime;
49206083Srdivacky  }
50296417Sdim
51206083Srdivacky  void operator+=(const TimeRecord &RHS) {
52206083Srdivacky    WallTime   += RHS.WallTime;
53206083Srdivacky    UserTime   += RHS.UserTime;
54206083Srdivacky    SystemTime += RHS.SystemTime;
55206083Srdivacky    MemUsed    += RHS.MemUsed;
56206083Srdivacky  }
57206083Srdivacky  void operator-=(const TimeRecord &RHS) {
58206083Srdivacky    WallTime   -= RHS.WallTime;
59206083Srdivacky    UserTime   -= RHS.UserTime;
60206083Srdivacky    SystemTime -= RHS.SystemTime;
61206083Srdivacky    MemUsed    -= RHS.MemUsed;
62206083Srdivacky  }
63296417Sdim
64296417Sdim  /// Print the current time record to \p OS, with a breakdown showing
65296417Sdim  /// contributions to the \p Total time record.
66206083Srdivacky  void print(const TimeRecord &Total, raw_ostream &OS) const;
67206083Srdivacky};
68296417Sdim
69314564Sdim/// This class is used to track the amount of time spent between invocations of
70314564Sdim/// its startTimer()/stopTimer() methods.  Given appropriate OS support it can
71314564Sdim/// also keep track of the RSS of the program at various points.  By default,
72314564Sdim/// the Timer will print the amount of time it has captured to standard error
73314564Sdim/// when the last timer is destroyed, otherwise it is printed when its
74314564Sdim/// TimerGroup is destroyed.  Timers do not print their information if they are
75314564Sdim/// never started.
76193323Sedclass Timer {
77314564Sdim  TimeRecord Time;          ///< The total time captured.
78314564Sdim  TimeRecord StartTime;     ///< The time startTimer() was last called.
79314564Sdim  std::string Name;         ///< The name of this time variable.
80314564Sdim  std::string Description;  ///< Description of this time variable.
81360784Sdim  bool Running = false;     ///< Is the timer currently running?
82360784Sdim  bool Triggered = false;   ///< Has the timer ever been triggered?
83314564Sdim  TimerGroup *TG = nullptr; ///< The TimerGroup this Timer is in.
84296417Sdim
85360784Sdim  Timer **Prev = nullptr;   ///< Pointer to \p Next of previous timer in group.
86360784Sdim  Timer *Next = nullptr;    ///< Next timer in the group.
87193323Sedpublic:
88360784Sdim  explicit Timer(StringRef TimerName, StringRef TimerDescription) {
89360784Sdim    init(TimerName, TimerDescription);
90314564Sdim  }
91360784Sdim  Timer(StringRef TimerName, StringRef TimerDescription, TimerGroup &tg) {
92360784Sdim    init(TimerName, TimerDescription, tg);
93314564Sdim  }
94314564Sdim  Timer(const Timer &RHS) {
95276479Sdim    assert(!RHS.TG && "Can only copy uninitialized timers");
96206083Srdivacky  }
97193323Sed  const Timer &operator=(const Timer &T) {
98276479Sdim    assert(!TG && !T.TG && "Can only assign uninit timers");
99193323Sed    return *this;
100193323Sed  }
101206083Srdivacky  ~Timer();
102193323Sed
103314564Sdim  /// Create an uninitialized timer, client must use 'init'.
104314564Sdim  explicit Timer() {}
105360784Sdim  void init(StringRef TimerName, StringRef TimerDescription);
106360784Sdim  void init(StringRef TimerName, StringRef TimerDescription, TimerGroup &tg);
107296417Sdim
108206083Srdivacky  const std::string &getName() const { return Name; }
109314564Sdim  const std::string &getDescription() const { return Description; }
110276479Sdim  bool isInitialized() const { return TG != nullptr; }
111296417Sdim
112309124Sdim  /// Check if the timer is currently running.
113309124Sdim  bool isRunning() const { return Running; }
114309124Sdim
115296417Sdim  /// Check if startTimer() has ever been called on this timer.
116296417Sdim  bool hasTriggered() const { return Triggered; }
117296417Sdim
118296417Sdim  /// Start the timer running.  Time between calls to startTimer/stopTimer is
119296417Sdim  /// counted by the Timer class.  Note that these calls must be correctly
120296417Sdim  /// paired.
121193323Sed  void startTimer();
122193323Sed
123296417Sdim  /// Stop the timer.
124193323Sed  void stopTimer();
125193323Sed
126296417Sdim  /// Clear the timer state.
127296417Sdim  void clear();
128296417Sdim
129296417Sdim  /// Return the duration for which this timer has been running.
130296417Sdim  TimeRecord getTotalTime() const { return Time; }
131296417Sdim
132193323Sedprivate:
133193323Sed  friend class TimerGroup;
134193323Sed};
135193323Sed
136193323Sed/// The TimeRegion class is used as a helper class to call the startTimer() and
137193323Sed/// stopTimer() methods of the Timer class.  When the object is constructed, it
138249423Sdim/// starts the timer specified as its argument.  When it is destroyed, it stops
139193323Sed/// the relevant timer.  This makes it easy to time a region of code.
140193323Sedclass TimeRegion {
141193323Sed  Timer *T;
142288943Sdim  TimeRegion(const TimeRegion &) = delete;
143296417Sdim
144193323Sedpublic:
145193323Sed  explicit TimeRegion(Timer &t) : T(&t) {
146193323Sed    T->startTimer();
147193323Sed  }
148193323Sed  explicit TimeRegion(Timer *t) : T(t) {
149206083Srdivacky    if (T) T->startTimer();
150193323Sed  }
151193323Sed  ~TimeRegion() {
152206083Srdivacky    if (T) T->stopTimer();
153193323Sed  }
154193323Sed};
155193323Sed
156314564Sdim/// This class is basically a combination of TimeRegion and Timer.  It allows
157314564Sdim/// you to declare a new timer, AND specify the region to time, all in one
158314564Sdim/// statement.  All timers with the same name are merged.  This is primarily
159314564Sdim/// used for debugging and for hunting performance problems.
160193323Sedstruct NamedRegionTimer : public TimeRegion {
161314564Sdim  explicit NamedRegionTimer(StringRef Name, StringRef Description,
162314564Sdim                            StringRef GroupName,
163314564Sdim                            StringRef GroupDescription, bool Enabled = true);
164193323Sed};
165193323Sed
166193323Sed/// The TimerGroup class is used to group together related timers into a single
167193323Sed/// report that is printed when the TimerGroup is destroyed.  It is illegal to
168193323Sed/// destroy a TimerGroup object before all of the Timers in it are gone.  A
169193323Sed/// TimerGroup can be specified for a newly created timer in its constructor.
170193323Sedclass TimerGroup {
171314564Sdim  struct PrintRecord {
172314564Sdim    TimeRecord Time;
173314564Sdim    std::string Name;
174314564Sdim    std::string Description;
175314564Sdim
176314564Sdim    PrintRecord(const PrintRecord &Other) = default;
177360784Sdim    PrintRecord &operator=(const PrintRecord &Other) = default;
178314564Sdim    PrintRecord(const TimeRecord &Time, const std::string &Name,
179314564Sdim                const std::string &Description)
180314564Sdim      : Time(Time), Name(Name), Description(Description) {}
181314564Sdim
182314564Sdim    bool operator <(const PrintRecord &Other) const {
183314564Sdim      return Time < Other.Time;
184314564Sdim    }
185314564Sdim  };
186193323Sed  std::string Name;
187314564Sdim  std::string Description;
188314564Sdim  Timer *FirstTimer = nullptr; ///< First timer in the group.
189314564Sdim  std::vector<PrintRecord> TimersToPrint;
190296417Sdim
191314564Sdim  TimerGroup **Prev; ///< Pointer to Next field of previous timergroup in list.
192314564Sdim  TimerGroup *Next;  ///< Pointer to next timergroup in list.
193288943Sdim  TimerGroup(const TimerGroup &TG) = delete;
194288943Sdim  void operator=(const TimerGroup &TG) = delete;
195296417Sdim
196193323Sedpublic:
197314564Sdim  explicit TimerGroup(StringRef Name, StringRef Description);
198341825Sdim
199341825Sdim  explicit TimerGroup(StringRef Name, StringRef Description,
200341825Sdim                      const StringMap<TimeRecord> &Records);
201341825Sdim
202206083Srdivacky  ~TimerGroup();
203193323Sed
204314564Sdim  void setName(StringRef NewName, StringRef NewDescription) {
205314564Sdim    Name.assign(NewName.begin(), NewName.end());
206314564Sdim    Description.assign(NewDescription.begin(), NewDescription.end());
207314564Sdim  }
208206083Srdivacky
209353358Sdim  /// Print any started timers in this group, optionally resetting timers after
210353358Sdim  /// printing them.
211353358Sdim  void print(raw_ostream &OS, bool ResetAfterPrint = false);
212296417Sdim
213344779Sdim  /// Clear all timers in this group.
214344779Sdim  void clear();
215344779Sdim
216344779Sdim  /// This static method prints all timers.
217206083Srdivacky  static void printAll(raw_ostream &OS);
218296417Sdim
219344779Sdim  /// Clear out all timers. This is mostly used to disable automatic
220344779Sdim  /// printing on shutdown, when timers have already been printed explicitly
221344779Sdim  /// using \c printAll or \c printJSONValues.
222344779Sdim  static void clearAll();
223344779Sdim
224341825Sdim  const char *printJSONValues(raw_ostream &OS, const char *delim);
225341825Sdim
226344779Sdim  /// Prints all timers as JSON key/value pairs.
227321369Sdim  static const char *printAllJSONValues(raw_ostream &OS, const char *delim);
228321369Sdim
229314564Sdim  /// Ensure global timer group lists are initialized. This function is mostly
230314564Sdim  /// used by the Statistic code to influence the construction and destruction
231314564Sdim  /// order of the global timer lists.
232314564Sdim  static void ConstructTimerLists();
233360784Sdim
234360784Sdim  /// This makes the default group unmanaged, and lets the user manage the
235360784Sdim  /// group's lifetime.
236360784Sdim  static std::unique_ptr<TimerGroup> aquireDefaultGroup();
237360784Sdim
238193323Sedprivate:
239193323Sed  friend class Timer;
240314564Sdim  friend void PrintStatisticsJSON(raw_ostream &OS);
241206083Srdivacky  void addTimer(Timer &T);
242206083Srdivacky  void removeTimer(Timer &T);
243353358Sdim  void prepareToPrintList(bool reset_time = false);
244206083Srdivacky  void PrintQueuedTimers(raw_ostream &OS);
245314564Sdim  void printJSONValue(raw_ostream &OS, const PrintRecord &R,
246314564Sdim                      const char *suffix, double Value);
247193323Sed};
248193323Sed
249314564Sdim} // end namespace llvm
250193323Sed
251193323Sed#endif
252