1f22ef01cSRoman Divacky //===-- Timer.cpp - Interval Timing Support -------------------------------===//
2f22ef01cSRoman Divacky //
3f22ef01cSRoman Divacky // The LLVM Compiler Infrastructure
4f22ef01cSRoman Divacky //
5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source
6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details.
7f22ef01cSRoman Divacky //
8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
9f22ef01cSRoman Divacky //
10d88c1a5aSDimitry Andric /// \file Interval Timing implementation.
11f22ef01cSRoman Divacky //
12f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
13f22ef01cSRoman Divacky
14f22ef01cSRoman Divacky #include "llvm/Support/Timer.h"
157d523365SDimitry Andric #include "llvm/ADT/Statistic.h"
16f22ef01cSRoman Divacky #include "llvm/ADT/StringMap.h"
17139f7f9bSDimitry Andric #include "llvm/Support/CommandLine.h"
1891bc56edSDimitry Andric #include "llvm/Support/FileSystem.h"
19139f7f9bSDimitry Andric #include "llvm/Support/Format.h"
20139f7f9bSDimitry Andric #include "llvm/Support/ManagedStatic.h"
21139f7f9bSDimitry Andric #include "llvm/Support/Mutex.h"
22139f7f9bSDimitry Andric #include "llvm/Support/Process.h"
23d88c1a5aSDimitry Andric #include "llvm/Support/YAMLTraits.h"
24db17bf38SDimitry Andric #include "llvm/Support/raw_ostream.h"
254ba319b5SDimitry Andric #include <limits>
264ba319b5SDimitry Andric
27f22ef01cSRoman Divacky using namespace llvm;
28f22ef01cSRoman Divacky
29d88c1a5aSDimitry Andric // This ugly hack is brought to you courtesy of constructor/destructor ordering
30d88c1a5aSDimitry Andric // being unspecified by C++. Basically the problem is that a Statistic object
31d88c1a5aSDimitry Andric // gets destroyed, which ends up calling 'GetLibSupportInfoOutputFile()'
32d88c1a5aSDimitry Andric // (below), which calls this function. LibSupportInfoOutputFilename used to be
33d88c1a5aSDimitry Andric // a global variable, but sometimes it would get destroyed before the Statistic,
34d88c1a5aSDimitry Andric // causing havoc to ensue. We "fix" this by creating the string the first time
35d88c1a5aSDimitry Andric // it is needed and never destroying it.
36f22ef01cSRoman Divacky static ManagedStatic<std::string> LibSupportInfoOutputFilename;
getLibSupportInfoOutputFilename()37f22ef01cSRoman Divacky static std::string &getLibSupportInfoOutputFilename() {
38f22ef01cSRoman Divacky return *LibSupportInfoOutputFilename;
39f22ef01cSRoman Divacky }
40f22ef01cSRoman Divacky
41f22ef01cSRoman Divacky static ManagedStatic<sys::SmartMutex<true> > TimerLock;
42f22ef01cSRoman Divacky
43f22ef01cSRoman Divacky namespace {
44f22ef01cSRoman Divacky static cl::opt<bool>
45f22ef01cSRoman Divacky TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
46f22ef01cSRoman Divacky "tracking (this may be slow)"),
47f22ef01cSRoman Divacky cl::Hidden);
48f22ef01cSRoman Divacky
49f22ef01cSRoman Divacky static cl::opt<std::string, true>
50f22ef01cSRoman Divacky InfoOutputFilename("info-output-file", cl::value_desc("filename"),
51f22ef01cSRoman Divacky cl::desc("File to append -stats and -timer output to"),
52f22ef01cSRoman Divacky cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
533dac3a9bSDimitry Andric }
54f22ef01cSRoman Divacky
CreateInfoOutputFile()557d523365SDimitry Andric std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() {
56f22ef01cSRoman Divacky const std::string &OutputFilename = getLibSupportInfoOutputFilename();
57f22ef01cSRoman Divacky if (OutputFilename.empty())
587d523365SDimitry Andric return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
59f22ef01cSRoman Divacky if (OutputFilename == "-")
607d523365SDimitry Andric return llvm::make_unique<raw_fd_ostream>(1, false); // stdout.
61f22ef01cSRoman Divacky
62f22ef01cSRoman Divacky // Append mode is used because the info output file is opened and closed
63f22ef01cSRoman Divacky // each time -stats or -time-passes wants to print output to it. To
64f22ef01cSRoman Divacky // compensate for this, the test-suite Makefiles have code to delete the
65f22ef01cSRoman Divacky // info output file before running commands which write to it.
6639d628a0SDimitry Andric std::error_code EC;
677d523365SDimitry Andric auto Result = llvm::make_unique<raw_fd_ostream>(
687d523365SDimitry Andric OutputFilename, EC, sys::fs::F_Append | sys::fs::F_Text);
6939d628a0SDimitry Andric if (!EC)
70f22ef01cSRoman Divacky return Result;
71f22ef01cSRoman Divacky
72f22ef01cSRoman Divacky errs() << "Error opening info-output-file '"
73f22ef01cSRoman Divacky << OutputFilename << " for appending!\n";
747d523365SDimitry Andric return llvm::make_unique<raw_fd_ostream>(2, false); // stderr.
75f22ef01cSRoman Divacky }
76f22ef01cSRoman Divacky
7789cb50c9SDimitry Andric namespace {
7889cb50c9SDimitry Andric struct CreateDefaultTimerGroup {
call__anon352446020211::CreateDefaultTimerGroup7989cb50c9SDimitry Andric static void *call() {
8089cb50c9SDimitry Andric return new TimerGroup("misc", "Miscellaneous Ungrouped Timers");
81f22ef01cSRoman Divacky }
8289cb50c9SDimitry Andric };
8389cb50c9SDimitry Andric } // namespace
8489cb50c9SDimitry Andric static ManagedStatic<TimerGroup, CreateDefaultTimerGroup> DefaultTimerGroup;
getDefaultTimerGroup()8589cb50c9SDimitry Andric static TimerGroup *getDefaultTimerGroup() { return &*DefaultTimerGroup; }
86f22ef01cSRoman Divacky
87f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
88f22ef01cSRoman Divacky // Timer Implementation
89f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
90f22ef01cSRoman Divacky
init(StringRef Name,StringRef Description)91d88c1a5aSDimitry Andric void Timer::init(StringRef Name, StringRef Description) {
92d88c1a5aSDimitry Andric init(Name, Description, *getDefaultTimerGroup());
93f22ef01cSRoman Divacky }
94f22ef01cSRoman Divacky
init(StringRef Name,StringRef Description,TimerGroup & tg)95d88c1a5aSDimitry Andric void Timer::init(StringRef Name, StringRef Description, TimerGroup &tg) {
9691bc56edSDimitry Andric assert(!TG && "Timer already initialized");
97d88c1a5aSDimitry Andric this->Name.assign(Name.begin(), Name.end());
98d88c1a5aSDimitry Andric this->Description.assign(Description.begin(), Description.end());
997d523365SDimitry Andric Running = Triggered = false;
100f22ef01cSRoman Divacky TG = &tg;
101f22ef01cSRoman Divacky TG->addTimer(*this);
102f22ef01cSRoman Divacky }
103f22ef01cSRoman Divacky
~Timer()104f22ef01cSRoman Divacky Timer::~Timer() {
105f22ef01cSRoman Divacky if (!TG) return; // Never initialized, or already cleared.
106f22ef01cSRoman Divacky TG->removeTimer(*this);
107f22ef01cSRoman Divacky }
108f22ef01cSRoman Divacky
getMemUsage()109f22ef01cSRoman Divacky static inline size_t getMemUsage() {
110f22ef01cSRoman Divacky if (!TrackSpace) return 0;
111f22ef01cSRoman Divacky return sys::Process::GetMallocUsage();
112f22ef01cSRoman Divacky }
113f22ef01cSRoman Divacky
getCurrentTime(bool Start)114f22ef01cSRoman Divacky TimeRecord TimeRecord::getCurrentTime(bool Start) {
115d88c1a5aSDimitry Andric using Seconds = std::chrono::duration<double, std::ratio<1>>;
116f22ef01cSRoman Divacky TimeRecord Result;
117d88c1a5aSDimitry Andric sys::TimePoint<> now;
118d88c1a5aSDimitry Andric std::chrono::nanoseconds user, sys;
119f22ef01cSRoman Divacky
120f22ef01cSRoman Divacky if (Start) {
121f22ef01cSRoman Divacky Result.MemUsed = getMemUsage();
122f22ef01cSRoman Divacky sys::Process::GetTimeUsage(now, user, sys);
123f22ef01cSRoman Divacky } else {
124f22ef01cSRoman Divacky sys::Process::GetTimeUsage(now, user, sys);
125f22ef01cSRoman Divacky Result.MemUsed = getMemUsage();
126f22ef01cSRoman Divacky }
127f22ef01cSRoman Divacky
128d88c1a5aSDimitry Andric Result.WallTime = Seconds(now.time_since_epoch()).count();
129d88c1a5aSDimitry Andric Result.UserTime = Seconds(user).count();
130d88c1a5aSDimitry Andric Result.SystemTime = Seconds(sys).count();
131f22ef01cSRoman Divacky return Result;
132f22ef01cSRoman Divacky }
133f22ef01cSRoman Divacky
startTimer()134f22ef01cSRoman Divacky void Timer::startTimer() {
1357d523365SDimitry Andric assert(!Running && "Cannot start a running timer");
1367d523365SDimitry Andric Running = Triggered = true;
1377d523365SDimitry Andric StartTime = TimeRecord::getCurrentTime(true);
138f22ef01cSRoman Divacky }
139f22ef01cSRoman Divacky
stopTimer()140f22ef01cSRoman Divacky void Timer::stopTimer() {
1417d523365SDimitry Andric assert(Running && "Cannot stop a paused timer");
1427d523365SDimitry Andric Running = false;
143f22ef01cSRoman Divacky Time += TimeRecord::getCurrentTime(false);
1447d523365SDimitry Andric Time -= StartTime;
145f22ef01cSRoman Divacky }
1467d523365SDimitry Andric
clear()1477d523365SDimitry Andric void Timer::clear() {
1487d523365SDimitry Andric Running = Triggered = false;
1497d523365SDimitry Andric Time = StartTime = TimeRecord();
150f22ef01cSRoman Divacky }
151f22ef01cSRoman Divacky
printVal(double Val,double Total,raw_ostream & OS)152f22ef01cSRoman Divacky static void printVal(double Val, double Total, raw_ostream &OS) {
153f22ef01cSRoman Divacky if (Total < 1e-7) // Avoid dividing by zero.
154f22ef01cSRoman Divacky OS << " ----- ";
155dff0c46cSDimitry Andric else
156dff0c46cSDimitry Andric OS << format(" %7.4f (%5.1f%%)", Val, Val*100/Total);
157f22ef01cSRoman Divacky }
158f22ef01cSRoman Divacky
print(const TimeRecord & Total,raw_ostream & OS) const159f22ef01cSRoman Divacky void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const {
160f22ef01cSRoman Divacky if (Total.getUserTime())
161f22ef01cSRoman Divacky printVal(getUserTime(), Total.getUserTime(), OS);
162f22ef01cSRoman Divacky if (Total.getSystemTime())
163f22ef01cSRoman Divacky printVal(getSystemTime(), Total.getSystemTime(), OS);
164f22ef01cSRoman Divacky if (Total.getProcessTime())
165f22ef01cSRoman Divacky printVal(getProcessTime(), Total.getProcessTime(), OS);
166f22ef01cSRoman Divacky printVal(getWallTime(), Total.getWallTime(), OS);
167f22ef01cSRoman Divacky
168f22ef01cSRoman Divacky OS << " ";
169f22ef01cSRoman Divacky
170f22ef01cSRoman Divacky if (Total.getMemUsed())
171dff0c46cSDimitry Andric OS << format("%9" PRId64 " ", (int64_t)getMemUsed());
172f22ef01cSRoman Divacky }
173f22ef01cSRoman Divacky
174f22ef01cSRoman Divacky
175f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
176f22ef01cSRoman Divacky // NamedRegionTimer Implementation
177f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
178f22ef01cSRoman Divacky
179f22ef01cSRoman Divacky namespace {
180f22ef01cSRoman Divacky
181f22ef01cSRoman Divacky typedef StringMap<Timer> Name2TimerMap;
182f22ef01cSRoman Divacky
183f22ef01cSRoman Divacky class Name2PairMap {
184f22ef01cSRoman Divacky StringMap<std::pair<TimerGroup*, Name2TimerMap> > Map;
185f22ef01cSRoman Divacky public:
~Name2PairMap()186f22ef01cSRoman Divacky ~Name2PairMap() {
187f22ef01cSRoman Divacky for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator
188f22ef01cSRoman Divacky I = Map.begin(), E = Map.end(); I != E; ++I)
189f22ef01cSRoman Divacky delete I->second.first;
190f22ef01cSRoman Divacky }
191f22ef01cSRoman Divacky
get(StringRef Name,StringRef Description,StringRef GroupName,StringRef GroupDescription)192d88c1a5aSDimitry Andric Timer &get(StringRef Name, StringRef Description, StringRef GroupName,
193d88c1a5aSDimitry Andric StringRef GroupDescription) {
194f22ef01cSRoman Divacky sys::SmartScopedLock<true> L(*TimerLock);
195f22ef01cSRoman Divacky
196f22ef01cSRoman Divacky std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName];
197f22ef01cSRoman Divacky
198f22ef01cSRoman Divacky if (!GroupEntry.first)
199d88c1a5aSDimitry Andric GroupEntry.first = new TimerGroup(GroupName, GroupDescription);
200f22ef01cSRoman Divacky
201f22ef01cSRoman Divacky Timer &T = GroupEntry.second[Name];
202f22ef01cSRoman Divacky if (!T.isInitialized())
203d88c1a5aSDimitry Andric T.init(Name, Description, *GroupEntry.first);
204f22ef01cSRoman Divacky return T;
205f22ef01cSRoman Divacky }
206f22ef01cSRoman Divacky };
207f22ef01cSRoman Divacky
2083dac3a9bSDimitry Andric }
209f22ef01cSRoman Divacky
210f22ef01cSRoman Divacky static ManagedStatic<Name2PairMap> NamedGroupedTimers;
211f22ef01cSRoman Divacky
NamedRegionTimer(StringRef Name,StringRef Description,StringRef GroupName,StringRef GroupDescription,bool Enabled)212d88c1a5aSDimitry Andric NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef Description,
213d88c1a5aSDimitry Andric StringRef GroupName,
214d88c1a5aSDimitry Andric StringRef GroupDescription, bool Enabled)
215d88c1a5aSDimitry Andric : TimeRegion(!Enabled ? nullptr
216d88c1a5aSDimitry Andric : &NamedGroupedTimers->get(Name, Description, GroupName,
217d88c1a5aSDimitry Andric GroupDescription)) {}
218f22ef01cSRoman Divacky
219f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
220f22ef01cSRoman Divacky // TimerGroup Implementation
221f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
222f22ef01cSRoman Divacky
223d88c1a5aSDimitry Andric /// This is the global list of TimerGroups, maintained by the TimerGroup
224d88c1a5aSDimitry Andric /// ctor/dtor and is protected by the TimerLock lock.
22591bc56edSDimitry Andric static TimerGroup *TimerGroupList = nullptr;
226f22ef01cSRoman Divacky
TimerGroup(StringRef Name,StringRef Description)227d88c1a5aSDimitry Andric TimerGroup::TimerGroup(StringRef Name, StringRef Description)
228d88c1a5aSDimitry Andric : Name(Name.begin(), Name.end()),
229d88c1a5aSDimitry Andric Description(Description.begin(), Description.end()) {
230f22ef01cSRoman Divacky // Add the group to TimerGroupList.
231f22ef01cSRoman Divacky sys::SmartScopedLock<true> L(*TimerLock);
232f22ef01cSRoman Divacky if (TimerGroupList)
233f22ef01cSRoman Divacky TimerGroupList->Prev = &Next;
234f22ef01cSRoman Divacky Next = TimerGroupList;
235f22ef01cSRoman Divacky Prev = &TimerGroupList;
236f22ef01cSRoman Divacky TimerGroupList = this;
237f22ef01cSRoman Divacky }
238f22ef01cSRoman Divacky
TimerGroup(StringRef Name,StringRef Description,const StringMap<TimeRecord> & Records)2394ba319b5SDimitry Andric TimerGroup::TimerGroup(StringRef Name, StringRef Description,
2404ba319b5SDimitry Andric const StringMap<TimeRecord> &Records)
2414ba319b5SDimitry Andric : TimerGroup(Name, Description) {
2424ba319b5SDimitry Andric TimersToPrint.reserve(Records.size());
2434ba319b5SDimitry Andric for (const auto &P : Records)
2444ba319b5SDimitry Andric TimersToPrint.emplace_back(P.getValue(), P.getKey(), P.getKey());
2454ba319b5SDimitry Andric assert(TimersToPrint.size() == Records.size() && "Size mismatch");
2464ba319b5SDimitry Andric }
2474ba319b5SDimitry Andric
~TimerGroup()248f22ef01cSRoman Divacky TimerGroup::~TimerGroup() {
249f22ef01cSRoman Divacky // If the timer group is destroyed before the timers it owns, accumulate and
250f22ef01cSRoman Divacky // print the timing data.
25191bc56edSDimitry Andric while (FirstTimer)
252f22ef01cSRoman Divacky removeTimer(*FirstTimer);
253f22ef01cSRoman Divacky
254f22ef01cSRoman Divacky // Remove the group from the TimerGroupList.
255f22ef01cSRoman Divacky sys::SmartScopedLock<true> L(*TimerLock);
256f22ef01cSRoman Divacky *Prev = Next;
257f22ef01cSRoman Divacky if (Next)
258f22ef01cSRoman Divacky Next->Prev = Prev;
259f22ef01cSRoman Divacky }
260f22ef01cSRoman Divacky
261f22ef01cSRoman Divacky
removeTimer(Timer & T)262f22ef01cSRoman Divacky void TimerGroup::removeTimer(Timer &T) {
263f22ef01cSRoman Divacky sys::SmartScopedLock<true> L(*TimerLock);
264f22ef01cSRoman Divacky
265f22ef01cSRoman Divacky // If the timer was started, move its data to TimersToPrint.
2667d523365SDimitry Andric if (T.hasTriggered())
267d88c1a5aSDimitry Andric TimersToPrint.emplace_back(T.Time, T.Name, T.Description);
268f22ef01cSRoman Divacky
26991bc56edSDimitry Andric T.TG = nullptr;
270f22ef01cSRoman Divacky
271f22ef01cSRoman Divacky // Unlink the timer from our list.
272f22ef01cSRoman Divacky *T.Prev = T.Next;
273f22ef01cSRoman Divacky if (T.Next)
274f22ef01cSRoman Divacky T.Next->Prev = T.Prev;
275f22ef01cSRoman Divacky
276f22ef01cSRoman Divacky // Print the report when all timers in this group are destroyed if some of
277f22ef01cSRoman Divacky // them were started.
27891bc56edSDimitry Andric if (FirstTimer || TimersToPrint.empty())
279f22ef01cSRoman Divacky return;
280f22ef01cSRoman Divacky
2817d523365SDimitry Andric std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
282f22ef01cSRoman Divacky PrintQueuedTimers(*OutStream);
283f22ef01cSRoman Divacky }
284f22ef01cSRoman Divacky
addTimer(Timer & T)285f22ef01cSRoman Divacky void TimerGroup::addTimer(Timer &T) {
286f22ef01cSRoman Divacky sys::SmartScopedLock<true> L(*TimerLock);
287f22ef01cSRoman Divacky
288f22ef01cSRoman Divacky // Add the timer to our list.
289f22ef01cSRoman Divacky if (FirstTimer)
290f22ef01cSRoman Divacky FirstTimer->Prev = &T.Next;
291f22ef01cSRoman Divacky T.Next = FirstTimer;
292f22ef01cSRoman Divacky T.Prev = &FirstTimer;
293f22ef01cSRoman Divacky FirstTimer = &T;
294f22ef01cSRoman Divacky }
295f22ef01cSRoman Divacky
PrintQueuedTimers(raw_ostream & OS)296f22ef01cSRoman Divacky void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
297f22ef01cSRoman Divacky // Sort the timers in descending order by amount of time taken.
298*b5893f02SDimitry Andric llvm::sort(TimersToPrint);
299f22ef01cSRoman Divacky
300f22ef01cSRoman Divacky TimeRecord Total;
301d88c1a5aSDimitry Andric for (const PrintRecord &Record : TimersToPrint)
302d88c1a5aSDimitry Andric Total += Record.Time;
303f22ef01cSRoman Divacky
304f22ef01cSRoman Divacky // Print out timing header.
305f22ef01cSRoman Divacky OS << "===" << std::string(73, '-') << "===\n";
306f22ef01cSRoman Divacky // Figure out how many spaces to indent TimerGroup name.
307d88c1a5aSDimitry Andric unsigned Padding = (80-Description.length())/2;
308f22ef01cSRoman Divacky if (Padding > 80) Padding = 0; // Don't allow "negative" numbers
309d88c1a5aSDimitry Andric OS.indent(Padding) << Description << '\n';
310f22ef01cSRoman Divacky OS << "===" << std::string(73, '-') << "===\n";
311f22ef01cSRoman Divacky
312f22ef01cSRoman Divacky // If this is not an collection of ungrouped times, print the total time.
313f22ef01cSRoman Divacky // Ungrouped timers don't really make sense to add up. We still print the
314f22ef01cSRoman Divacky // TOTAL line to make the percentages make sense.
3157a7e6055SDimitry Andric if (this != getDefaultTimerGroup())
316dff0c46cSDimitry Andric OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
317dff0c46cSDimitry Andric Total.getProcessTime(), Total.getWallTime());
318f22ef01cSRoman Divacky OS << '\n';
319f22ef01cSRoman Divacky
320f22ef01cSRoman Divacky if (Total.getUserTime())
321f22ef01cSRoman Divacky OS << " ---User Time---";
322f22ef01cSRoman Divacky if (Total.getSystemTime())
323f22ef01cSRoman Divacky OS << " --System Time--";
324f22ef01cSRoman Divacky if (Total.getProcessTime())
325f22ef01cSRoman Divacky OS << " --User+System--";
326f22ef01cSRoman Divacky OS << " ---Wall Time---";
327f22ef01cSRoman Divacky if (Total.getMemUsed())
328f22ef01cSRoman Divacky OS << " ---Mem---";
329f22ef01cSRoman Divacky OS << " --- Name ---\n";
330f22ef01cSRoman Divacky
331f22ef01cSRoman Divacky // Loop through all of the timing data, printing it out.
332d88c1a5aSDimitry Andric for (const PrintRecord &Record : make_range(TimersToPrint.rbegin(),
333d88c1a5aSDimitry Andric TimersToPrint.rend())) {
334d88c1a5aSDimitry Andric Record.Time.print(Total, OS);
335d88c1a5aSDimitry Andric OS << Record.Description << '\n';
336f22ef01cSRoman Divacky }
337f22ef01cSRoman Divacky
338f22ef01cSRoman Divacky Total.print(Total, OS);
339f22ef01cSRoman Divacky OS << "Total\n\n";
340f22ef01cSRoman Divacky OS.flush();
341f22ef01cSRoman Divacky
342f22ef01cSRoman Divacky TimersToPrint.clear();
343f22ef01cSRoman Divacky }
344f22ef01cSRoman Divacky
prepareToPrintList()345d88c1a5aSDimitry Andric void TimerGroup::prepareToPrintList() {
346*b5893f02SDimitry Andric // See if any of our timers were started, if so add them to TimersToPrint.
347f22ef01cSRoman Divacky for (Timer *T = FirstTimer; T; T = T->Next) {
3487d523365SDimitry Andric if (!T->hasTriggered()) continue;
3494ba319b5SDimitry Andric bool WasRunning = T->isRunning();
3504ba319b5SDimitry Andric if (WasRunning)
3514ba319b5SDimitry Andric T->stopTimer();
3524ba319b5SDimitry Andric
353d88c1a5aSDimitry Andric TimersToPrint.emplace_back(T->Time, T->Name, T->Description);
354f22ef01cSRoman Divacky
3554ba319b5SDimitry Andric if (WasRunning)
3564ba319b5SDimitry Andric T->startTimer();
357f22ef01cSRoman Divacky }
358d88c1a5aSDimitry Andric }
359d88c1a5aSDimitry Andric
print(raw_ostream & OS)360d88c1a5aSDimitry Andric void TimerGroup::print(raw_ostream &OS) {
361d88c1a5aSDimitry Andric sys::SmartScopedLock<true> L(*TimerLock);
362d88c1a5aSDimitry Andric
363d88c1a5aSDimitry Andric prepareToPrintList();
364f22ef01cSRoman Divacky
365f22ef01cSRoman Divacky // If any timers were started, print the group.
366f22ef01cSRoman Divacky if (!TimersToPrint.empty())
367f22ef01cSRoman Divacky PrintQueuedTimers(OS);
368f22ef01cSRoman Divacky }
369f22ef01cSRoman Divacky
clear()370*b5893f02SDimitry Andric void TimerGroup::clear() {
371*b5893f02SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock);
372*b5893f02SDimitry Andric for (Timer *T = FirstTimer; T; T = T->Next)
373*b5893f02SDimitry Andric T->clear();
374*b5893f02SDimitry Andric }
375*b5893f02SDimitry Andric
printAll(raw_ostream & OS)376f22ef01cSRoman Divacky void TimerGroup::printAll(raw_ostream &OS) {
377f22ef01cSRoman Divacky sys::SmartScopedLock<true> L(*TimerLock);
378f22ef01cSRoman Divacky
379f22ef01cSRoman Divacky for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
380f22ef01cSRoman Divacky TG->print(OS);
381f22ef01cSRoman Divacky }
382d88c1a5aSDimitry Andric
clearAll()383*b5893f02SDimitry Andric void TimerGroup::clearAll() {
384*b5893f02SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock);
385*b5893f02SDimitry Andric for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
386*b5893f02SDimitry Andric TG->clear();
387*b5893f02SDimitry Andric }
388*b5893f02SDimitry Andric
printJSONValue(raw_ostream & OS,const PrintRecord & R,const char * suffix,double Value)389d88c1a5aSDimitry Andric void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
390d88c1a5aSDimitry Andric const char *suffix, double Value) {
3912cab237bSDimitry Andric assert(yaml::needsQuotes(Name) == yaml::QuotingType::None &&
3924ba319b5SDimitry Andric "TimerGroup name should not need quotes");
3932cab237bSDimitry Andric assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None &&
3944ba319b5SDimitry Andric "Timer name should not need quotes");
3954ba319b5SDimitry Andric constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10;
3964ba319b5SDimitry Andric OS << "\t\"time." << Name << '.' << R.Name << suffix
3974ba319b5SDimitry Andric << "\": " << format("%.*e", max_digits10 - 1, Value);
398d88c1a5aSDimitry Andric }
399d88c1a5aSDimitry Andric
printJSONValues(raw_ostream & OS,const char * delim)400d88c1a5aSDimitry Andric const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
4014ba319b5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock);
4024ba319b5SDimitry Andric
403d88c1a5aSDimitry Andric prepareToPrintList();
404d88c1a5aSDimitry Andric for (const PrintRecord &R : TimersToPrint) {
405d88c1a5aSDimitry Andric OS << delim;
406d88c1a5aSDimitry Andric delim = ",\n";
407d88c1a5aSDimitry Andric
408d88c1a5aSDimitry Andric const TimeRecord &T = R.Time;
409d88c1a5aSDimitry Andric printJSONValue(OS, R, ".wall", T.getWallTime());
410d88c1a5aSDimitry Andric OS << delim;
411d88c1a5aSDimitry Andric printJSONValue(OS, R, ".user", T.getUserTime());
412d88c1a5aSDimitry Andric OS << delim;
413d88c1a5aSDimitry Andric printJSONValue(OS, R, ".sys", T.getSystemTime());
4144ba319b5SDimitry Andric if (T.getMemUsed()) {
4154ba319b5SDimitry Andric OS << delim;
4164ba319b5SDimitry Andric printJSONValue(OS, R, ".mem", T.getMemUsed());
4174ba319b5SDimitry Andric }
418d88c1a5aSDimitry Andric }
419d88c1a5aSDimitry Andric TimersToPrint.clear();
420d88c1a5aSDimitry Andric return delim;
421d88c1a5aSDimitry Andric }
422d88c1a5aSDimitry Andric
printAllJSONValues(raw_ostream & OS,const char * delim)423d88c1a5aSDimitry Andric const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
424d88c1a5aSDimitry Andric sys::SmartScopedLock<true> L(*TimerLock);
425d88c1a5aSDimitry Andric for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
426d88c1a5aSDimitry Andric delim = TG->printJSONValues(OS, delim);
427d88c1a5aSDimitry Andric return delim;
428d88c1a5aSDimitry Andric }
429d88c1a5aSDimitry Andric
ConstructTimerLists()430d88c1a5aSDimitry Andric void TimerGroup::ConstructTimerLists() {
431d88c1a5aSDimitry Andric (void)*NamedGroupedTimers;
432d88c1a5aSDimitry Andric }
433