1f4a2713aSLionel Sambuc //===-- Timer.cpp - Interval Timing Support -------------------------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc // Interval Timing implementation.
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
13f4a2713aSLionel Sambuc 
14f4a2713aSLionel Sambuc #include "llvm/Support/Timer.h"
15f4a2713aSLionel Sambuc #include "llvm/ADT/StringMap.h"
16f4a2713aSLionel Sambuc #include "llvm/Support/CommandLine.h"
17f4a2713aSLionel Sambuc #include "llvm/Support/Debug.h"
18*0a6a1f1dSLionel Sambuc #include "llvm/Support/FileSystem.h"
19f4a2713aSLionel Sambuc #include "llvm/Support/Format.h"
20f4a2713aSLionel Sambuc #include "llvm/Support/ManagedStatic.h"
21f4a2713aSLionel Sambuc #include "llvm/Support/Mutex.h"
22*0a6a1f1dSLionel Sambuc #include "llvm/Support/MutexGuard.h"
23f4a2713aSLionel Sambuc #include "llvm/Support/Process.h"
24f4a2713aSLionel Sambuc #include "llvm/Support/raw_ostream.h"
25f4a2713aSLionel Sambuc using namespace llvm;
26f4a2713aSLionel Sambuc 
27f4a2713aSLionel Sambuc // CreateInfoOutputFile - Return a file stream to print our output on.
28f4a2713aSLionel Sambuc namespace llvm { extern raw_ostream *CreateInfoOutputFile(); }
29f4a2713aSLionel Sambuc 
30f4a2713aSLionel Sambuc // getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy
31f4a2713aSLionel Sambuc // of constructor/destructor ordering being unspecified by C++.  Basically the
32f4a2713aSLionel Sambuc // problem is that a Statistic object gets destroyed, which ends up calling
33f4a2713aSLionel Sambuc // 'GetLibSupportInfoOutputFile()' (below), which calls this function.
34f4a2713aSLionel Sambuc // LibSupportInfoOutputFilename used to be a global variable, but sometimes it
35f4a2713aSLionel Sambuc // would get destroyed before the Statistic, causing havoc to ensue.  We "fix"
36f4a2713aSLionel Sambuc // this by creating the string the first time it is needed and never destroying
37f4a2713aSLionel Sambuc // it.
38f4a2713aSLionel Sambuc static ManagedStatic<std::string> LibSupportInfoOutputFilename;
getLibSupportInfoOutputFilename()39f4a2713aSLionel Sambuc static std::string &getLibSupportInfoOutputFilename() {
40f4a2713aSLionel Sambuc   return *LibSupportInfoOutputFilename;
41f4a2713aSLionel Sambuc }
42f4a2713aSLionel Sambuc 
43f4a2713aSLionel Sambuc static ManagedStatic<sys::SmartMutex<true> > TimerLock;
44f4a2713aSLionel Sambuc 
45f4a2713aSLionel Sambuc namespace {
46f4a2713aSLionel Sambuc   static cl::opt<bool>
47f4a2713aSLionel Sambuc   TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
48f4a2713aSLionel Sambuc                                       "tracking (this may be slow)"),
49f4a2713aSLionel Sambuc              cl::Hidden);
50f4a2713aSLionel Sambuc 
51f4a2713aSLionel Sambuc   static cl::opt<std::string, true>
52f4a2713aSLionel Sambuc   InfoOutputFilename("info-output-file", cl::value_desc("filename"),
53f4a2713aSLionel Sambuc                      cl::desc("File to append -stats and -timer output to"),
54f4a2713aSLionel Sambuc                    cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
55f4a2713aSLionel Sambuc }
56f4a2713aSLionel Sambuc 
57f4a2713aSLionel Sambuc // CreateInfoOutputFile - Return a file stream to print our output on.
CreateInfoOutputFile()58f4a2713aSLionel Sambuc raw_ostream *llvm::CreateInfoOutputFile() {
59f4a2713aSLionel Sambuc   const std::string &OutputFilename = getLibSupportInfoOutputFilename();
60f4a2713aSLionel Sambuc   if (OutputFilename.empty())
61f4a2713aSLionel Sambuc     return new raw_fd_ostream(2, false); // stderr.
62f4a2713aSLionel Sambuc   if (OutputFilename == "-")
63f4a2713aSLionel Sambuc     return new raw_fd_ostream(1, false); // stdout.
64f4a2713aSLionel Sambuc 
65f4a2713aSLionel Sambuc   // Append mode is used because the info output file is opened and closed
66f4a2713aSLionel Sambuc   // each time -stats or -time-passes wants to print output to it. To
67f4a2713aSLionel Sambuc   // compensate for this, the test-suite Makefiles have code to delete the
68f4a2713aSLionel Sambuc   // info output file before running commands which write to it.
69*0a6a1f1dSLionel Sambuc   std::error_code EC;
70*0a6a1f1dSLionel Sambuc   raw_ostream *Result = new raw_fd_ostream(OutputFilename, EC,
71*0a6a1f1dSLionel Sambuc                                            sys::fs::F_Append | sys::fs::F_Text);
72*0a6a1f1dSLionel Sambuc   if (!EC)
73f4a2713aSLionel Sambuc     return Result;
74f4a2713aSLionel Sambuc 
75f4a2713aSLionel Sambuc   errs() << "Error opening info-output-file '"
76f4a2713aSLionel Sambuc     << OutputFilename << " for appending!\n";
77f4a2713aSLionel Sambuc   delete Result;
78f4a2713aSLionel Sambuc   return new raw_fd_ostream(2, false); // stderr.
79f4a2713aSLionel Sambuc }
80f4a2713aSLionel Sambuc 
81f4a2713aSLionel Sambuc 
82*0a6a1f1dSLionel Sambuc static TimerGroup *DefaultTimerGroup = nullptr;
getDefaultTimerGroup()83f4a2713aSLionel Sambuc static TimerGroup *getDefaultTimerGroup() {
84f4a2713aSLionel Sambuc   TimerGroup *tmp = DefaultTimerGroup;
85f4a2713aSLionel Sambuc   sys::MemoryFence();
86f4a2713aSLionel Sambuc   if (tmp) return tmp;
87f4a2713aSLionel Sambuc 
88*0a6a1f1dSLionel Sambuc   sys::SmartScopedLock<true> Lock(*TimerLock);
89f4a2713aSLionel Sambuc   tmp = DefaultTimerGroup;
90f4a2713aSLionel Sambuc   if (!tmp) {
91f4a2713aSLionel Sambuc     tmp = new TimerGroup("Miscellaneous Ungrouped Timers");
92f4a2713aSLionel Sambuc     sys::MemoryFence();
93f4a2713aSLionel Sambuc     DefaultTimerGroup = tmp;
94f4a2713aSLionel Sambuc   }
95f4a2713aSLionel Sambuc 
96f4a2713aSLionel Sambuc   return tmp;
97f4a2713aSLionel Sambuc }
98f4a2713aSLionel Sambuc 
99f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
100f4a2713aSLionel Sambuc // Timer Implementation
101f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
102f4a2713aSLionel Sambuc 
init(StringRef N)103f4a2713aSLionel Sambuc void Timer::init(StringRef N) {
104*0a6a1f1dSLionel Sambuc   assert(!TG && "Timer already initialized");
105f4a2713aSLionel Sambuc   Name.assign(N.begin(), N.end());
106f4a2713aSLionel Sambuc   Started = false;
107f4a2713aSLionel Sambuc   TG = getDefaultTimerGroup();
108f4a2713aSLionel Sambuc   TG->addTimer(*this);
109f4a2713aSLionel Sambuc }
110f4a2713aSLionel Sambuc 
init(StringRef N,TimerGroup & tg)111f4a2713aSLionel Sambuc void Timer::init(StringRef N, TimerGroup &tg) {
112*0a6a1f1dSLionel Sambuc   assert(!TG && "Timer already initialized");
113f4a2713aSLionel Sambuc   Name.assign(N.begin(), N.end());
114f4a2713aSLionel Sambuc   Started = false;
115f4a2713aSLionel Sambuc   TG = &tg;
116f4a2713aSLionel Sambuc   TG->addTimer(*this);
117f4a2713aSLionel Sambuc }
118f4a2713aSLionel Sambuc 
~Timer()119f4a2713aSLionel Sambuc Timer::~Timer() {
120f4a2713aSLionel Sambuc   if (!TG) return;  // Never initialized, or already cleared.
121f4a2713aSLionel Sambuc   TG->removeTimer(*this);
122f4a2713aSLionel Sambuc }
123f4a2713aSLionel Sambuc 
getMemUsage()124f4a2713aSLionel Sambuc static inline size_t getMemUsage() {
125f4a2713aSLionel Sambuc   if (!TrackSpace) return 0;
126f4a2713aSLionel Sambuc   return sys::Process::GetMallocUsage();
127f4a2713aSLionel Sambuc }
128f4a2713aSLionel Sambuc 
getCurrentTime(bool Start)129f4a2713aSLionel Sambuc TimeRecord TimeRecord::getCurrentTime(bool Start) {
130f4a2713aSLionel Sambuc   TimeRecord Result;
131f4a2713aSLionel Sambuc   sys::TimeValue now(0,0), user(0,0), sys(0,0);
132f4a2713aSLionel Sambuc 
133f4a2713aSLionel Sambuc   if (Start) {
134f4a2713aSLionel Sambuc     Result.MemUsed = getMemUsage();
135f4a2713aSLionel Sambuc     sys::Process::GetTimeUsage(now, user, sys);
136f4a2713aSLionel Sambuc   } else {
137f4a2713aSLionel Sambuc     sys::Process::GetTimeUsage(now, user, sys);
138f4a2713aSLionel Sambuc     Result.MemUsed = getMemUsage();
139f4a2713aSLionel Sambuc   }
140f4a2713aSLionel Sambuc 
141f4a2713aSLionel Sambuc   Result.WallTime   =  now.seconds() +  now.microseconds() / 1000000.0;
142f4a2713aSLionel Sambuc   Result.UserTime   = user.seconds() + user.microseconds() / 1000000.0;
143f4a2713aSLionel Sambuc   Result.SystemTime =  sys.seconds() +  sys.microseconds() / 1000000.0;
144f4a2713aSLionel Sambuc   return Result;
145f4a2713aSLionel Sambuc }
146f4a2713aSLionel Sambuc 
147f4a2713aSLionel Sambuc static ManagedStatic<std::vector<Timer*> > ActiveTimers;
148f4a2713aSLionel Sambuc 
startTimer()149f4a2713aSLionel Sambuc void Timer::startTimer() {
150f4a2713aSLionel Sambuc   Started = true;
151f4a2713aSLionel Sambuc   ActiveTimers->push_back(this);
152f4a2713aSLionel Sambuc   Time -= TimeRecord::getCurrentTime(true);
153f4a2713aSLionel Sambuc }
154f4a2713aSLionel Sambuc 
stopTimer()155f4a2713aSLionel Sambuc void Timer::stopTimer() {
156f4a2713aSLionel Sambuc   Time += TimeRecord::getCurrentTime(false);
157f4a2713aSLionel Sambuc 
158f4a2713aSLionel Sambuc   if (ActiveTimers->back() == this) {
159f4a2713aSLionel Sambuc     ActiveTimers->pop_back();
160f4a2713aSLionel Sambuc   } else {
161f4a2713aSLionel Sambuc     std::vector<Timer*>::iterator I =
162f4a2713aSLionel Sambuc       std::find(ActiveTimers->begin(), ActiveTimers->end(), this);
163f4a2713aSLionel Sambuc     assert(I != ActiveTimers->end() && "stop but no startTimer?");
164f4a2713aSLionel Sambuc     ActiveTimers->erase(I);
165f4a2713aSLionel Sambuc   }
166f4a2713aSLionel Sambuc }
167f4a2713aSLionel Sambuc 
printVal(double Val,double Total,raw_ostream & OS)168f4a2713aSLionel Sambuc static void printVal(double Val, double Total, raw_ostream &OS) {
169f4a2713aSLionel Sambuc   if (Total < 1e-7)   // Avoid dividing by zero.
170f4a2713aSLionel Sambuc     OS << "        -----     ";
171f4a2713aSLionel Sambuc   else
172f4a2713aSLionel Sambuc     OS << format("  %7.4f (%5.1f%%)", Val, Val*100/Total);
173f4a2713aSLionel Sambuc }
174f4a2713aSLionel Sambuc 
print(const TimeRecord & Total,raw_ostream & OS) const175f4a2713aSLionel Sambuc void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const {
176f4a2713aSLionel Sambuc   if (Total.getUserTime())
177f4a2713aSLionel Sambuc     printVal(getUserTime(), Total.getUserTime(), OS);
178f4a2713aSLionel Sambuc   if (Total.getSystemTime())
179f4a2713aSLionel Sambuc     printVal(getSystemTime(), Total.getSystemTime(), OS);
180f4a2713aSLionel Sambuc   if (Total.getProcessTime())
181f4a2713aSLionel Sambuc     printVal(getProcessTime(), Total.getProcessTime(), OS);
182f4a2713aSLionel Sambuc   printVal(getWallTime(), Total.getWallTime(), OS);
183f4a2713aSLionel Sambuc 
184f4a2713aSLionel Sambuc   OS << "  ";
185f4a2713aSLionel Sambuc 
186f4a2713aSLionel Sambuc   if (Total.getMemUsed())
187f4a2713aSLionel Sambuc     OS << format("%9" PRId64 "  ", (int64_t)getMemUsed());
188f4a2713aSLionel Sambuc }
189f4a2713aSLionel Sambuc 
190f4a2713aSLionel Sambuc 
191f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
192f4a2713aSLionel Sambuc //   NamedRegionTimer Implementation
193f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
194f4a2713aSLionel Sambuc 
195f4a2713aSLionel Sambuc namespace {
196f4a2713aSLionel Sambuc 
197f4a2713aSLionel Sambuc typedef StringMap<Timer> Name2TimerMap;
198f4a2713aSLionel Sambuc 
199f4a2713aSLionel Sambuc class Name2PairMap {
200f4a2713aSLionel Sambuc   StringMap<std::pair<TimerGroup*, Name2TimerMap> > Map;
201f4a2713aSLionel Sambuc public:
~Name2PairMap()202f4a2713aSLionel Sambuc   ~Name2PairMap() {
203f4a2713aSLionel Sambuc     for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator
204f4a2713aSLionel Sambuc          I = Map.begin(), E = Map.end(); I != E; ++I)
205f4a2713aSLionel Sambuc       delete I->second.first;
206f4a2713aSLionel Sambuc   }
207f4a2713aSLionel Sambuc 
get(StringRef Name,StringRef GroupName)208f4a2713aSLionel Sambuc   Timer &get(StringRef Name, StringRef GroupName) {
209f4a2713aSLionel Sambuc     sys::SmartScopedLock<true> L(*TimerLock);
210f4a2713aSLionel Sambuc 
211f4a2713aSLionel Sambuc     std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName];
212f4a2713aSLionel Sambuc 
213f4a2713aSLionel Sambuc     if (!GroupEntry.first)
214f4a2713aSLionel Sambuc       GroupEntry.first = new TimerGroup(GroupName);
215f4a2713aSLionel Sambuc 
216f4a2713aSLionel Sambuc     Timer &T = GroupEntry.second[Name];
217f4a2713aSLionel Sambuc     if (!T.isInitialized())
218f4a2713aSLionel Sambuc       T.init(Name, *GroupEntry.first);
219f4a2713aSLionel Sambuc     return T;
220f4a2713aSLionel Sambuc   }
221f4a2713aSLionel Sambuc };
222f4a2713aSLionel Sambuc 
223f4a2713aSLionel Sambuc }
224f4a2713aSLionel Sambuc 
225f4a2713aSLionel Sambuc static ManagedStatic<Name2TimerMap> NamedTimers;
226f4a2713aSLionel Sambuc static ManagedStatic<Name2PairMap> NamedGroupedTimers;
227f4a2713aSLionel Sambuc 
getNamedRegionTimer(StringRef Name)228f4a2713aSLionel Sambuc static Timer &getNamedRegionTimer(StringRef Name) {
229f4a2713aSLionel Sambuc   sys::SmartScopedLock<true> L(*TimerLock);
230f4a2713aSLionel Sambuc 
231f4a2713aSLionel Sambuc   Timer &T = (*NamedTimers)[Name];
232f4a2713aSLionel Sambuc   if (!T.isInitialized())
233f4a2713aSLionel Sambuc     T.init(Name);
234f4a2713aSLionel Sambuc   return T;
235f4a2713aSLionel Sambuc }
236f4a2713aSLionel Sambuc 
NamedRegionTimer(StringRef Name,bool Enabled)237f4a2713aSLionel Sambuc NamedRegionTimer::NamedRegionTimer(StringRef Name,
238f4a2713aSLionel Sambuc                                    bool Enabled)
239*0a6a1f1dSLionel Sambuc   : TimeRegion(!Enabled ? nullptr : &getNamedRegionTimer(Name)) {}
240f4a2713aSLionel Sambuc 
NamedRegionTimer(StringRef Name,StringRef GroupName,bool Enabled)241f4a2713aSLionel Sambuc NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef GroupName,
242f4a2713aSLionel Sambuc                                    bool Enabled)
243*0a6a1f1dSLionel Sambuc   : TimeRegion(!Enabled ? nullptr : &NamedGroupedTimers->get(Name, GroupName)){}
244f4a2713aSLionel Sambuc 
245f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
246f4a2713aSLionel Sambuc //   TimerGroup Implementation
247f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
248f4a2713aSLionel Sambuc 
249f4a2713aSLionel Sambuc /// TimerGroupList - This is the global list of TimerGroups, maintained by the
250f4a2713aSLionel Sambuc /// TimerGroup ctor/dtor and is protected by the TimerLock lock.
251*0a6a1f1dSLionel Sambuc static TimerGroup *TimerGroupList = nullptr;
252f4a2713aSLionel Sambuc 
TimerGroup(StringRef name)253f4a2713aSLionel Sambuc TimerGroup::TimerGroup(StringRef name)
254*0a6a1f1dSLionel Sambuc   : Name(name.begin(), name.end()), FirstTimer(nullptr) {
255f4a2713aSLionel Sambuc 
256f4a2713aSLionel Sambuc   // Add the group to TimerGroupList.
257f4a2713aSLionel Sambuc   sys::SmartScopedLock<true> L(*TimerLock);
258f4a2713aSLionel Sambuc   if (TimerGroupList)
259f4a2713aSLionel Sambuc     TimerGroupList->Prev = &Next;
260f4a2713aSLionel Sambuc   Next = TimerGroupList;
261f4a2713aSLionel Sambuc   Prev = &TimerGroupList;
262f4a2713aSLionel Sambuc   TimerGroupList = this;
263f4a2713aSLionel Sambuc }
264f4a2713aSLionel Sambuc 
~TimerGroup()265f4a2713aSLionel Sambuc TimerGroup::~TimerGroup() {
266f4a2713aSLionel Sambuc   // If the timer group is destroyed before the timers it owns, accumulate and
267f4a2713aSLionel Sambuc   // print the timing data.
268*0a6a1f1dSLionel Sambuc   while (FirstTimer)
269f4a2713aSLionel Sambuc     removeTimer(*FirstTimer);
270f4a2713aSLionel Sambuc 
271f4a2713aSLionel Sambuc   // Remove the group from the TimerGroupList.
272f4a2713aSLionel Sambuc   sys::SmartScopedLock<true> L(*TimerLock);
273f4a2713aSLionel Sambuc   *Prev = Next;
274f4a2713aSLionel Sambuc   if (Next)
275f4a2713aSLionel Sambuc     Next->Prev = Prev;
276f4a2713aSLionel Sambuc }
277f4a2713aSLionel Sambuc 
278f4a2713aSLionel Sambuc 
removeTimer(Timer & T)279f4a2713aSLionel Sambuc void TimerGroup::removeTimer(Timer &T) {
280f4a2713aSLionel Sambuc   sys::SmartScopedLock<true> L(*TimerLock);
281f4a2713aSLionel Sambuc 
282f4a2713aSLionel Sambuc   // If the timer was started, move its data to TimersToPrint.
283f4a2713aSLionel Sambuc   if (T.Started)
284f4a2713aSLionel Sambuc     TimersToPrint.push_back(std::make_pair(T.Time, T.Name));
285f4a2713aSLionel Sambuc 
286*0a6a1f1dSLionel Sambuc   T.TG = nullptr;
287f4a2713aSLionel Sambuc 
288f4a2713aSLionel Sambuc   // Unlink the timer from our list.
289f4a2713aSLionel Sambuc   *T.Prev = T.Next;
290f4a2713aSLionel Sambuc   if (T.Next)
291f4a2713aSLionel Sambuc     T.Next->Prev = T.Prev;
292f4a2713aSLionel Sambuc 
293f4a2713aSLionel Sambuc   // Print the report when all timers in this group are destroyed if some of
294f4a2713aSLionel Sambuc   // them were started.
295*0a6a1f1dSLionel Sambuc   if (FirstTimer || TimersToPrint.empty())
296f4a2713aSLionel Sambuc     return;
297f4a2713aSLionel Sambuc 
298f4a2713aSLionel Sambuc   raw_ostream *OutStream = CreateInfoOutputFile();
299f4a2713aSLionel Sambuc   PrintQueuedTimers(*OutStream);
300f4a2713aSLionel Sambuc   delete OutStream;   // Close the file.
301f4a2713aSLionel Sambuc }
302f4a2713aSLionel Sambuc 
addTimer(Timer & T)303f4a2713aSLionel Sambuc void TimerGroup::addTimer(Timer &T) {
304f4a2713aSLionel Sambuc   sys::SmartScopedLock<true> L(*TimerLock);
305f4a2713aSLionel Sambuc 
306f4a2713aSLionel Sambuc   // Add the timer to our list.
307f4a2713aSLionel Sambuc   if (FirstTimer)
308f4a2713aSLionel Sambuc     FirstTimer->Prev = &T.Next;
309f4a2713aSLionel Sambuc   T.Next = FirstTimer;
310f4a2713aSLionel Sambuc   T.Prev = &FirstTimer;
311f4a2713aSLionel Sambuc   FirstTimer = &T;
312f4a2713aSLionel Sambuc }
313f4a2713aSLionel Sambuc 
PrintQueuedTimers(raw_ostream & OS)314f4a2713aSLionel Sambuc void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
315f4a2713aSLionel Sambuc   // Sort the timers in descending order by amount of time taken.
316f4a2713aSLionel Sambuc   std::sort(TimersToPrint.begin(), TimersToPrint.end());
317f4a2713aSLionel Sambuc 
318f4a2713aSLionel Sambuc   TimeRecord Total;
319f4a2713aSLionel Sambuc   for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i)
320f4a2713aSLionel Sambuc     Total += TimersToPrint[i].first;
321f4a2713aSLionel Sambuc 
322f4a2713aSLionel Sambuc   // Print out timing header.
323f4a2713aSLionel Sambuc   OS << "===" << std::string(73, '-') << "===\n";
324f4a2713aSLionel Sambuc   // Figure out how many spaces to indent TimerGroup name.
325f4a2713aSLionel Sambuc   unsigned Padding = (80-Name.length())/2;
326f4a2713aSLionel Sambuc   if (Padding > 80) Padding = 0;         // Don't allow "negative" numbers
327f4a2713aSLionel Sambuc   OS.indent(Padding) << Name << '\n';
328f4a2713aSLionel Sambuc   OS << "===" << std::string(73, '-') << "===\n";
329f4a2713aSLionel Sambuc 
330f4a2713aSLionel Sambuc   // If this is not an collection of ungrouped times, print the total time.
331f4a2713aSLionel Sambuc   // Ungrouped timers don't really make sense to add up.  We still print the
332f4a2713aSLionel Sambuc   // TOTAL line to make the percentages make sense.
333f4a2713aSLionel Sambuc   if (this != DefaultTimerGroup)
334f4a2713aSLionel Sambuc     OS << format("  Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
335f4a2713aSLionel Sambuc                  Total.getProcessTime(), Total.getWallTime());
336f4a2713aSLionel Sambuc   OS << '\n';
337f4a2713aSLionel Sambuc 
338f4a2713aSLionel Sambuc   if (Total.getUserTime())
339f4a2713aSLionel Sambuc     OS << "   ---User Time---";
340f4a2713aSLionel Sambuc   if (Total.getSystemTime())
341f4a2713aSLionel Sambuc     OS << "   --System Time--";
342f4a2713aSLionel Sambuc   if (Total.getProcessTime())
343f4a2713aSLionel Sambuc     OS << "   --User+System--";
344f4a2713aSLionel Sambuc   OS << "   ---Wall Time---";
345f4a2713aSLionel Sambuc   if (Total.getMemUsed())
346f4a2713aSLionel Sambuc     OS << "  ---Mem---";
347f4a2713aSLionel Sambuc   OS << "  --- Name ---\n";
348f4a2713aSLionel Sambuc 
349f4a2713aSLionel Sambuc   // Loop through all of the timing data, printing it out.
350f4a2713aSLionel Sambuc   for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i) {
351f4a2713aSLionel Sambuc     const std::pair<TimeRecord, std::string> &Entry = TimersToPrint[e-i-1];
352f4a2713aSLionel Sambuc     Entry.first.print(Total, OS);
353f4a2713aSLionel Sambuc     OS << Entry.second << '\n';
354f4a2713aSLionel Sambuc   }
355f4a2713aSLionel Sambuc 
356f4a2713aSLionel Sambuc   Total.print(Total, OS);
357f4a2713aSLionel Sambuc   OS << "Total\n\n";
358f4a2713aSLionel Sambuc   OS.flush();
359f4a2713aSLionel Sambuc 
360f4a2713aSLionel Sambuc   TimersToPrint.clear();
361f4a2713aSLionel Sambuc }
362f4a2713aSLionel Sambuc 
363f4a2713aSLionel Sambuc /// print - Print any started timers in this group and zero them.
print(raw_ostream & OS)364f4a2713aSLionel Sambuc void TimerGroup::print(raw_ostream &OS) {
365f4a2713aSLionel Sambuc   sys::SmartScopedLock<true> L(*TimerLock);
366f4a2713aSLionel Sambuc 
367f4a2713aSLionel Sambuc   // See if any of our timers were started, if so add them to TimersToPrint and
368f4a2713aSLionel Sambuc   // reset them.
369f4a2713aSLionel Sambuc   for (Timer *T = FirstTimer; T; T = T->Next) {
370f4a2713aSLionel Sambuc     if (!T->Started) continue;
371f4a2713aSLionel Sambuc     TimersToPrint.push_back(std::make_pair(T->Time, T->Name));
372f4a2713aSLionel Sambuc 
373f4a2713aSLionel Sambuc     // Clear out the time.
374f4a2713aSLionel Sambuc     T->Started = 0;
375f4a2713aSLionel Sambuc     T->Time = TimeRecord();
376f4a2713aSLionel Sambuc   }
377f4a2713aSLionel Sambuc 
378f4a2713aSLionel Sambuc   // If any timers were started, print the group.
379f4a2713aSLionel Sambuc   if (!TimersToPrint.empty())
380f4a2713aSLionel Sambuc     PrintQueuedTimers(OS);
381f4a2713aSLionel Sambuc }
382f4a2713aSLionel Sambuc 
383f4a2713aSLionel Sambuc /// printAll - This static method prints all timers and clears them all out.
printAll(raw_ostream & OS)384f4a2713aSLionel Sambuc void TimerGroup::printAll(raw_ostream &OS) {
385f4a2713aSLionel Sambuc   sys::SmartScopedLock<true> L(*TimerLock);
386f4a2713aSLionel Sambuc 
387f4a2713aSLionel Sambuc   for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
388f4a2713aSLionel Sambuc     TG->print(OS);
389f4a2713aSLionel Sambuc }
390