LLVM  3.7.0
Timer.cpp
Go to the documentation of this file.
1 //===-- Timer.cpp - Interval Timing Support -------------------------------===//
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 // Interval Timing implementation.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/Support/Timer.h"
15 #include "llvm/ADT/StringMap.h"
18 #include "llvm/Support/Format.h"
20 #include "llvm/Support/Mutex.h"
21 #include "llvm/Support/Process.h"
23 using namespace llvm;
24 
25 // CreateInfoOutputFile - Return a file stream to print our output on.
26 namespace llvm { extern raw_ostream *CreateInfoOutputFile(); }
27 
28 // getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy
29 // of constructor/destructor ordering being unspecified by C++. Basically the
30 // problem is that a Statistic object gets destroyed, which ends up calling
31 // 'GetLibSupportInfoOutputFile()' (below), which calls this function.
32 // LibSupportInfoOutputFilename used to be a global variable, but sometimes it
33 // would get destroyed before the Statistic, causing havoc to ensue. We "fix"
34 // this by creating the string the first time it is needed and never destroying
35 // it.
37 static std::string &getLibSupportInfoOutputFilename() {
39 }
40 
42 
43 namespace {
44  static cl::opt<bool>
45  TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
46  "tracking (this may be slow)"),
47  cl::Hidden);
48 
50  InfoOutputFilename("info-output-file", cl::value_desc("filename"),
51  cl::desc("File to append -stats and -timer output to"),
53 }
54 
55 // CreateInfoOutputFile - Return a file stream to print our output on.
57  const std::string &OutputFilename = getLibSupportInfoOutputFilename();
58  if (OutputFilename.empty())
59  return new raw_fd_ostream(2, false); // stderr.
60  if (OutputFilename == "-")
61  return new raw_fd_ostream(1, false); // stdout.
62 
63  // Append mode is used because the info output file is opened and closed
64  // each time -stats or -time-passes wants to print output to it. To
65  // compensate for this, the test-suite Makefiles have code to delete the
66  // info output file before running commands which write to it.
67  std::error_code EC;
68  raw_ostream *Result = new raw_fd_ostream(OutputFilename, EC,
70  if (!EC)
71  return Result;
72 
73  errs() << "Error opening info-output-file '"
74  << OutputFilename << " for appending!\n";
75  delete Result;
76  return new raw_fd_ostream(2, false); // stderr.
77 }
78 
79 
80 static TimerGroup *DefaultTimerGroup = nullptr;
84  if (tmp) return tmp;
85 
87  tmp = DefaultTimerGroup;
88  if (!tmp) {
89  tmp = new TimerGroup("Miscellaneous Ungrouped Timers");
91  DefaultTimerGroup = tmp;
92  }
93 
94  return tmp;
95 }
96 
97 //===----------------------------------------------------------------------===//
98 // Timer Implementation
99 //===----------------------------------------------------------------------===//
100 
102  assert(!TG && "Timer already initialized");
103  Name.assign(N.begin(), N.end());
104  Started = false;
105  TG = getDefaultTimerGroup();
106  TG->addTimer(*this);
107 }
108 
110  assert(!TG && "Timer already initialized");
111  Name.assign(N.begin(), N.end());
112  Started = false;
113  TG = &tg;
114  TG->addTimer(*this);
115 }
116 
118  if (!TG) return; // Never initialized, or already cleared.
119  TG->removeTimer(*this);
120 }
121 
122 static inline size_t getMemUsage() {
123  if (!TrackSpace) return 0;
125 }
126 
128  TimeRecord Result;
129  sys::TimeValue now(0,0), user(0,0), sys(0,0);
130 
131  if (Start) {
132  Result.MemUsed = getMemUsage();
133  sys::Process::GetTimeUsage(now, user, sys);
134  } else {
135  sys::Process::GetTimeUsage(now, user, sys);
136  Result.MemUsed = getMemUsage();
137  }
138 
139  Result.WallTime = now.seconds() + now.microseconds() / 1000000.0;
140  Result.UserTime = user.seconds() + user.microseconds() / 1000000.0;
141  Result.SystemTime = sys.seconds() + sys.microseconds() / 1000000.0;
142  return Result;
143 }
144 
146 
148  Started = true;
149  ActiveTimers->push_back(this);
150  Time -= TimeRecord::getCurrentTime(true);
151 }
152 
154  Time += TimeRecord::getCurrentTime(false);
155 
156  if (ActiveTimers->back() == this) {
157  ActiveTimers->pop_back();
158  } else {
159  std::vector<Timer*>::iterator I =
160  std::find(ActiveTimers->begin(), ActiveTimers->end(), this);
161  assert(I != ActiveTimers->end() && "stop but no startTimer?");
162  ActiveTimers->erase(I);
163  }
164 }
165 
166 static void printVal(double Val, double Total, raw_ostream &OS) {
167  if (Total < 1e-7) // Avoid dividing by zero.
168  OS << " ----- ";
169  else
170  OS << format(" %7.4f (%5.1f%%)", Val, Val*100/Total);
171 }
172 
173 void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const {
174  if (Total.getUserTime())
175  printVal(getUserTime(), Total.getUserTime(), OS);
176  if (Total.getSystemTime())
177  printVal(getSystemTime(), Total.getSystemTime(), OS);
178  if (Total.getProcessTime())
179  printVal(getProcessTime(), Total.getProcessTime(), OS);
180  printVal(getWallTime(), Total.getWallTime(), OS);
181 
182  OS << " ";
183 
184  if (Total.getMemUsed())
185  OS << format("%9" PRId64 " ", (int64_t)getMemUsed());
186 }
187 
188 
189 //===----------------------------------------------------------------------===//
190 // NamedRegionTimer Implementation
191 //===----------------------------------------------------------------------===//
192 
193 namespace {
194 
195 typedef StringMap<Timer> Name2TimerMap;
196 
197 class Name2PairMap {
199 public:
200  ~Name2PairMap() {
201  for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator
202  I = Map.begin(), E = Map.end(); I != E; ++I)
203  delete I->second.first;
204  }
205 
206  Timer &get(StringRef Name, StringRef GroupName) {
208 
209  std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName];
210 
211  if (!GroupEntry.first)
212  GroupEntry.first = new TimerGroup(GroupName);
213 
214  Timer &T = GroupEntry.second[Name];
215  if (!T.isInitialized())
216  T.init(Name, *GroupEntry.first);
217  return T;
218  }
219 };
220 
221 }
222 
225 
228 
229  Timer &T = (*NamedTimers)[Name];
230  if (!T.isInitialized())
231  T.init(Name);
232  return T;
233 }
234 
236  bool Enabled)
237  : TimeRegion(!Enabled ? nullptr : &getNamedRegionTimer(Name)) {}
238 
240  bool Enabled)
241  : TimeRegion(!Enabled ? nullptr : &NamedGroupedTimers->get(Name, GroupName)){}
242 
243 //===----------------------------------------------------------------------===//
244 // TimerGroup Implementation
245 //===----------------------------------------------------------------------===//
246 
247 /// TimerGroupList - This is the global list of TimerGroups, maintained by the
248 /// TimerGroup ctor/dtor and is protected by the TimerLock lock.
249 static TimerGroup *TimerGroupList = nullptr;
250 
251 TimerGroup::TimerGroup(StringRef name)
252  : Name(name.begin(), name.end()), FirstTimer(nullptr) {
253 
254  // Add the group to TimerGroupList.
256  if (TimerGroupList)
257  TimerGroupList->Prev = &Next;
258  Next = TimerGroupList;
259  Prev = &TimerGroupList;
260  TimerGroupList = this;
261 }
262 
264  // If the timer group is destroyed before the timers it owns, accumulate and
265  // print the timing data.
266  while (FirstTimer)
267  removeTimer(*FirstTimer);
268 
269  // Remove the group from the TimerGroupList.
271  *Prev = Next;
272  if (Next)
273  Next->Prev = Prev;
274 }
275 
276 
277 void TimerGroup::removeTimer(Timer &T) {
279 
280  // If the timer was started, move its data to TimersToPrint.
281  if (T.Started)
282  TimersToPrint.push_back(std::make_pair(T.Time, T.Name));
283 
284  T.TG = nullptr;
285 
286  // Unlink the timer from our list.
287  *T.Prev = T.Next;
288  if (T.Next)
289  T.Next->Prev = T.Prev;
290 
291  // Print the report when all timers in this group are destroyed if some of
292  // them were started.
293  if (FirstTimer || TimersToPrint.empty())
294  return;
295 
296  raw_ostream *OutStream = CreateInfoOutputFile();
297  PrintQueuedTimers(*OutStream);
298  delete OutStream; // Close the file.
299 }
300 
301 void TimerGroup::addTimer(Timer &T) {
303 
304  // Add the timer to our list.
305  if (FirstTimer)
306  FirstTimer->Prev = &T.Next;
307  T.Next = FirstTimer;
308  T.Prev = &FirstTimer;
309  FirstTimer = &T;
310 }
311 
312 void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
313  // Sort the timers in descending order by amount of time taken.
314  std::sort(TimersToPrint.begin(), TimersToPrint.end());
315 
316  TimeRecord Total;
317  for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i)
318  Total += TimersToPrint[i].first;
319 
320  // Print out timing header.
321  OS << "===" << std::string(73, '-') << "===\n";
322  // Figure out how many spaces to indent TimerGroup name.
323  unsigned Padding = (80-Name.length())/2;
324  if (Padding > 80) Padding = 0; // Don't allow "negative" numbers
325  OS.indent(Padding) << Name << '\n';
326  OS << "===" << std::string(73, '-') << "===\n";
327 
328  // If this is not an collection of ungrouped times, print the total time.
329  // Ungrouped timers don't really make sense to add up. We still print the
330  // TOTAL line to make the percentages make sense.
331  if (this != DefaultTimerGroup)
332  OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
333  Total.getProcessTime(), Total.getWallTime());
334  OS << '\n';
335 
336  if (Total.getUserTime())
337  OS << " ---User Time---";
338  if (Total.getSystemTime())
339  OS << " --System Time--";
340  if (Total.getProcessTime())
341  OS << " --User+System--";
342  OS << " ---Wall Time---";
343  if (Total.getMemUsed())
344  OS << " ---Mem---";
345  OS << " --- Name ---\n";
346 
347  // Loop through all of the timing data, printing it out.
348  for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i) {
349  const std::pair<TimeRecord, std::string> &Entry = TimersToPrint[e-i-1];
350  Entry.first.print(Total, OS);
351  OS << Entry.second << '\n';
352  }
353 
354  Total.print(Total, OS);
355  OS << "Total\n\n";
356  OS.flush();
357 
358  TimersToPrint.clear();
359 }
360 
361 /// print - Print any started timers in this group and zero them.
364 
365  // See if any of our timers were started, if so add them to TimersToPrint and
366  // reset them.
367  for (Timer *T = FirstTimer; T; T = T->Next) {
368  if (!T->Started) continue;
369  TimersToPrint.push_back(std::make_pair(T->Time, T->Name));
370 
371  // Clear out the time.
372  T->Started = 0;
373  T->Time = TimeRecord();
374  }
375 
376  // If any timers were started, print the group.
377  if (!TimersToPrint.empty())
378  PrintQueuedTimers(OS);
379 }
380 
381 /// printAll - This static method prints all timers and clears them all out.
384 
385  for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
386  TG->print(OS);
387 }
bool isInitialized() const
Definition: Timer.h:104
const_iterator end(StringRef path)
Get end iterator over path.
Definition: Path.cpp:240
F_Append - When opening a file, if it already exists append to the existing file instead of returning...
Definition: FileSystem.h:588
void print(const TimeRecord &Total, raw_ostream &OS) const
print - Print the current timer to standard error, and reset the "Started" flag.
Definition: Timer.cpp:173
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
static TimeRecord getCurrentTime(bool Start=true)
getCurrentTime - Get the current time and memory usage.
Definition: Timer.cpp:127
void stopTimer()
stopTimer - Stop the timer.
Definition: Timer.cpp:153
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
const_iterator begin(StringRef path)
Get begin iterator over path.
Definition: Path.cpp:232
NamedRegionTimer(StringRef Name, bool Enabled=true)
Definition: Timer.cpp:235
static sys::Mutex Lock
The TimeRegion class is used as a helper class to call the startTimer() and stopTimer() methods of th...
Definition: Timer.h:126
SecondsType seconds() const
Returns only the seconds component of the TimeValue.
Definition: TimeValue.h:207
double getProcessTime() const
Definition: Timer.h:40
static cl::opt< bool > Enabled("stats", cl::desc("Enable statistics output from program (available with Asserts)"))
-stats - Command line option to cause transformations to emit stats about what they did...
double getWallTime() const
Definition: Timer.h:43
static cl::opt< std::string > OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"), cl::init("-"))
Timer - This class is used to track the amount of time spent between invocations of its startTimer()/...
Definition: Timer.h:79
static ManagedStatic< Name2TimerMap > NamedTimers
Definition: Timer.cpp:223
#define T
double getUserTime() const
Definition: Timer.h:41
void init(StringRef N)
Definition: Timer.cpp:101
static void printVal(double Val, double Total, raw_ostream &OS)
Definition: Timer.cpp:166
static TimerGroup * DefaultTimerGroup
Definition: Timer.cpp:80
iterator begin() const
Definition: StringRef.h:90
format_object< Ts...> format(const char *Fmt, const Ts &...Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:111
static TimerGroup * TimerGroupList
TimerGroupList - This is the global list of TimerGroups, maintained by the TimerGroup ctor/dtor and i...
Definition: Timer.cpp:249
static void GetTimeUsage(TimeValue &elapsed, TimeValue &user_time, TimeValue &sys_time)
This static function will set user_time to the amount of CPU time spent in user (non-kernel) mode and...
ssize_t getMemUsed() const
Definition: Timer.h:44
static ManagedStatic< std::string > LibSupportInfoOutputFilename
Definition: Timer.cpp:36
static ManagedStatic< Name2PairMap > NamedGroupedTimers
Definition: Timer.cpp:224
static ManagedStatic< std::vector< Timer * > > ActiveTimers
Definition: Timer.cpp:145
void MemoryFence()
Definition: Atomic.cpp:29
static size_t GetMallocUsage()
Return process memory usage.
void print(raw_ostream &OS)
print - Print any started timers in this group and zero them.
Definition: Timer.cpp:362
static TimerGroup * getDefaultTimerGroup()
Definition: Timer.cpp:81
double getSystemTime() const
Definition: Timer.h:42
void startTimer()
startTimer - Start the timer running.
Definition: Timer.cpp:147
StringMap - This is an unconventional map that is specialized for handling keys that are "strings"...
Definition: StringMap.h:214
static std::string & getLibSupportInfoOutputFilename()
Definition: Timer.cpp:37
The file should be opened in text mode on platforms that make this distinction.
Definition: FileSystem.h:592
Provides a library for accessing information about this process and other processes on the operating ...
raw_ostream * CreateInfoOutputFile()
Definition: Timer.cpp:56
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:345
#define I(x, y, z)
Definition: MD5.cpp:54
#define N
The TimerGroup class is used to group together related timers into a single report that is printed wh...
Definition: Timer.h:160
static const char * name
This class is used where a precise fixed point in time is required.
Definition: TimeValue.h:31
static void printAll(raw_ostream &OS)
printAll - This static method prints all timers and clears them all out.
Definition: Timer.cpp:382
iterator end() const
Definition: StringRef.h:92
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:38
static size_t getMemUsage()
Definition: Timer.cpp:122
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:40
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
Definition: ManagedStatic.h:61
uint32_t microseconds() const
Returns only the fractional portion of the TimeValue rounded down to the nearest microsecond (divide ...
Definition: TimeValue.h:217
static Timer & getNamedRegionTimer(StringRef Name)
Definition: Timer.cpp:226
LocationClass< Ty > location(Ty &L)
Definition: CommandLine.h:340
static ManagedStatic< sys::SmartMutex< true > > TimerLock
Definition: Timer.cpp:41
static sys::TimeValue now(bool Deterministic)