xref: /freebsd/contrib/llvm-project/llvm/lib/Support/Timer.cpp (revision 8bcb0991864975618c09697b1aca10683346d9f0)
10b57cec5SDimitry Andric //===-- Timer.cpp - Interval Timing Support -------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file Interval Timing implementation.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/Support/Timer.h"
140b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringMap.h"
160b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
170b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h"
180b57cec5SDimitry Andric #include "llvm/Support/Format.h"
190b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h"
200b57cec5SDimitry Andric #include "llvm/Support/Mutex.h"
210b57cec5SDimitry Andric #include "llvm/Support/Process.h"
220b57cec5SDimitry Andric #include "llvm/Support/Signposts.h"
230b57cec5SDimitry Andric #include "llvm/Support/YAMLTraits.h"
240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
250b57cec5SDimitry Andric #include <limits>
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric using namespace llvm;
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric // This ugly hack is brought to you courtesy of constructor/destructor ordering
300b57cec5SDimitry Andric // being unspecified by C++.  Basically the problem is that a Statistic object
310b57cec5SDimitry Andric // gets destroyed, which ends up calling 'GetLibSupportInfoOutputFile()'
320b57cec5SDimitry Andric // (below), which calls this function.  LibSupportInfoOutputFilename used to be
330b57cec5SDimitry Andric // a global variable, but sometimes it would get destroyed before the Statistic,
340b57cec5SDimitry Andric // causing havoc to ensue.  We "fix" this by creating the string the first time
350b57cec5SDimitry Andric // it is needed and never destroying it.
360b57cec5SDimitry Andric static ManagedStatic<std::string> LibSupportInfoOutputFilename;
370b57cec5SDimitry Andric static std::string &getLibSupportInfoOutputFilename() {
380b57cec5SDimitry Andric   return *LibSupportInfoOutputFilename;
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric static ManagedStatic<sys::SmartMutex<true> > TimerLock;
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric /// Allows llvm::Timer to emit signposts when supported.
440b57cec5SDimitry Andric static ManagedStatic<SignpostEmitter> Signposts;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric namespace {
470b57cec5SDimitry Andric   static cl::opt<bool>
480b57cec5SDimitry Andric   TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
490b57cec5SDimitry Andric                                       "tracking (this may be slow)"),
500b57cec5SDimitry Andric              cl::Hidden);
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   static cl::opt<std::string, true>
530b57cec5SDimitry Andric   InfoOutputFilename("info-output-file", cl::value_desc("filename"),
540b57cec5SDimitry Andric                      cl::desc("File to append -stats and -timer output to"),
550b57cec5SDimitry Andric                    cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() {
590b57cec5SDimitry Andric   const std::string &OutputFilename = getLibSupportInfoOutputFilename();
600b57cec5SDimitry Andric   if (OutputFilename.empty())
61*8bcb0991SDimitry Andric     return std::make_unique<raw_fd_ostream>(2, false); // stderr.
620b57cec5SDimitry Andric   if (OutputFilename == "-")
63*8bcb0991SDimitry Andric     return std::make_unique<raw_fd_ostream>(1, false); // stdout.
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   // Append mode is used because the info output file is opened and closed
660b57cec5SDimitry Andric   // each time -stats or -time-passes wants to print output to it. To
670b57cec5SDimitry Andric   // compensate for this, the test-suite Makefiles have code to delete the
680b57cec5SDimitry Andric   // info output file before running commands which write to it.
690b57cec5SDimitry Andric   std::error_code EC;
70*8bcb0991SDimitry Andric   auto Result = std::make_unique<raw_fd_ostream>(
71*8bcb0991SDimitry Andric       OutputFilename, EC, sys::fs::OF_Append | sys::fs::OF_Text);
720b57cec5SDimitry Andric   if (!EC)
730b57cec5SDimitry Andric     return Result;
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   errs() << "Error opening info-output-file '"
760b57cec5SDimitry Andric     << OutputFilename << " for appending!\n";
77*8bcb0991SDimitry Andric   return std::make_unique<raw_fd_ostream>(2, false); // stderr.
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric namespace {
810b57cec5SDimitry Andric struct CreateDefaultTimerGroup {
820b57cec5SDimitry Andric   static void *call() {
830b57cec5SDimitry Andric     return new TimerGroup("misc", "Miscellaneous Ungrouped Timers");
840b57cec5SDimitry Andric   }
850b57cec5SDimitry Andric };
860b57cec5SDimitry Andric } // namespace
870b57cec5SDimitry Andric static ManagedStatic<TimerGroup, CreateDefaultTimerGroup> DefaultTimerGroup;
880b57cec5SDimitry Andric static TimerGroup *getDefaultTimerGroup() { return &*DefaultTimerGroup; }
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
910b57cec5SDimitry Andric // Timer Implementation
920b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric void Timer::init(StringRef Name, StringRef Description) {
950b57cec5SDimitry Andric   init(Name, Description, *getDefaultTimerGroup());
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric void Timer::init(StringRef Name, StringRef Description, TimerGroup &tg) {
990b57cec5SDimitry Andric   assert(!TG && "Timer already initialized");
1000b57cec5SDimitry Andric   this->Name.assign(Name.begin(), Name.end());
1010b57cec5SDimitry Andric   this->Description.assign(Description.begin(), Description.end());
1020b57cec5SDimitry Andric   Running = Triggered = false;
1030b57cec5SDimitry Andric   TG = &tg;
1040b57cec5SDimitry Andric   TG->addTimer(*this);
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric Timer::~Timer() {
1080b57cec5SDimitry Andric   if (!TG) return;  // Never initialized, or already cleared.
1090b57cec5SDimitry Andric   TG->removeTimer(*this);
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric static inline size_t getMemUsage() {
1130b57cec5SDimitry Andric   if (!TrackSpace) return 0;
1140b57cec5SDimitry Andric   return sys::Process::GetMallocUsage();
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric TimeRecord TimeRecord::getCurrentTime(bool Start) {
1180b57cec5SDimitry Andric   using Seconds = std::chrono::duration<double, std::ratio<1>>;
1190b57cec5SDimitry Andric   TimeRecord Result;
1200b57cec5SDimitry Andric   sys::TimePoint<> now;
1210b57cec5SDimitry Andric   std::chrono::nanoseconds user, sys;
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   if (Start) {
1240b57cec5SDimitry Andric     Result.MemUsed = getMemUsage();
1250b57cec5SDimitry Andric     sys::Process::GetTimeUsage(now, user, sys);
1260b57cec5SDimitry Andric   } else {
1270b57cec5SDimitry Andric     sys::Process::GetTimeUsage(now, user, sys);
1280b57cec5SDimitry Andric     Result.MemUsed = getMemUsage();
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   Result.WallTime = Seconds(now.time_since_epoch()).count();
1320b57cec5SDimitry Andric   Result.UserTime = Seconds(user).count();
1330b57cec5SDimitry Andric   Result.SystemTime = Seconds(sys).count();
1340b57cec5SDimitry Andric   return Result;
1350b57cec5SDimitry Andric }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric void Timer::startTimer() {
1380b57cec5SDimitry Andric   assert(!Running && "Cannot start a running timer");
1390b57cec5SDimitry Andric   Running = Triggered = true;
1400b57cec5SDimitry Andric   Signposts->startTimerInterval(this);
1410b57cec5SDimitry Andric   StartTime = TimeRecord::getCurrentTime(true);
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric void Timer::stopTimer() {
1450b57cec5SDimitry Andric   assert(Running && "Cannot stop a paused timer");
1460b57cec5SDimitry Andric   Running = false;
1470b57cec5SDimitry Andric   Time += TimeRecord::getCurrentTime(false);
1480b57cec5SDimitry Andric   Time -= StartTime;
1490b57cec5SDimitry Andric   Signposts->endTimerInterval(this);
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric void Timer::clear() {
1530b57cec5SDimitry Andric   Running = Triggered = false;
1540b57cec5SDimitry Andric   Time = StartTime = TimeRecord();
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric static void printVal(double Val, double Total, raw_ostream &OS) {
1580b57cec5SDimitry Andric   if (Total < 1e-7)   // Avoid dividing by zero.
1590b57cec5SDimitry Andric     OS << "        -----     ";
1600b57cec5SDimitry Andric   else
1610b57cec5SDimitry Andric     OS << format("  %7.4f (%5.1f%%)", Val, Val*100/Total);
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const {
1650b57cec5SDimitry Andric   if (Total.getUserTime())
1660b57cec5SDimitry Andric     printVal(getUserTime(), Total.getUserTime(), OS);
1670b57cec5SDimitry Andric   if (Total.getSystemTime())
1680b57cec5SDimitry Andric     printVal(getSystemTime(), Total.getSystemTime(), OS);
1690b57cec5SDimitry Andric   if (Total.getProcessTime())
1700b57cec5SDimitry Andric     printVal(getProcessTime(), Total.getProcessTime(), OS);
1710b57cec5SDimitry Andric   printVal(getWallTime(), Total.getWallTime(), OS);
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   OS << "  ";
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   if (Total.getMemUsed())
1760b57cec5SDimitry Andric     OS << format("%9" PRId64 "  ", (int64_t)getMemUsed());
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1810b57cec5SDimitry Andric //   NamedRegionTimer Implementation
1820b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric namespace {
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric typedef StringMap<Timer> Name2TimerMap;
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric class Name2PairMap {
1890b57cec5SDimitry Andric   StringMap<std::pair<TimerGroup*, Name2TimerMap> > Map;
1900b57cec5SDimitry Andric public:
1910b57cec5SDimitry Andric   ~Name2PairMap() {
1920b57cec5SDimitry Andric     for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator
1930b57cec5SDimitry Andric          I = Map.begin(), E = Map.end(); I != E; ++I)
1940b57cec5SDimitry Andric       delete I->second.first;
1950b57cec5SDimitry Andric   }
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   Timer &get(StringRef Name, StringRef Description, StringRef GroupName,
1980b57cec5SDimitry Andric              StringRef GroupDescription) {
1990b57cec5SDimitry Andric     sys::SmartScopedLock<true> L(*TimerLock);
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric     std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName];
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric     if (!GroupEntry.first)
2040b57cec5SDimitry Andric       GroupEntry.first = new TimerGroup(GroupName, GroupDescription);
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric     Timer &T = GroupEntry.second[Name];
2070b57cec5SDimitry Andric     if (!T.isInitialized())
2080b57cec5SDimitry Andric       T.init(Name, Description, *GroupEntry.first);
2090b57cec5SDimitry Andric     return T;
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric };
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric static ManagedStatic<Name2PairMap> NamedGroupedTimers;
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef Description,
2180b57cec5SDimitry Andric                                    StringRef GroupName,
2190b57cec5SDimitry Andric                                    StringRef GroupDescription, bool Enabled)
2200b57cec5SDimitry Andric   : TimeRegion(!Enabled ? nullptr
2210b57cec5SDimitry Andric                  : &NamedGroupedTimers->get(Name, Description, GroupName,
2220b57cec5SDimitry Andric                                             GroupDescription)) {}
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2250b57cec5SDimitry Andric //   TimerGroup Implementation
2260b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric /// This is the global list of TimerGroups, maintained by the TimerGroup
2290b57cec5SDimitry Andric /// ctor/dtor and is protected by the TimerLock lock.
2300b57cec5SDimitry Andric static TimerGroup *TimerGroupList = nullptr;
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric TimerGroup::TimerGroup(StringRef Name, StringRef Description)
2330b57cec5SDimitry Andric   : Name(Name.begin(), Name.end()),
2340b57cec5SDimitry Andric     Description(Description.begin(), Description.end()) {
2350b57cec5SDimitry Andric   // Add the group to TimerGroupList.
2360b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
2370b57cec5SDimitry Andric   if (TimerGroupList)
2380b57cec5SDimitry Andric     TimerGroupList->Prev = &Next;
2390b57cec5SDimitry Andric   Next = TimerGroupList;
2400b57cec5SDimitry Andric   Prev = &TimerGroupList;
2410b57cec5SDimitry Andric   TimerGroupList = this;
2420b57cec5SDimitry Andric }
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric TimerGroup::TimerGroup(StringRef Name, StringRef Description,
2450b57cec5SDimitry Andric                        const StringMap<TimeRecord> &Records)
2460b57cec5SDimitry Andric     : TimerGroup(Name, Description) {
2470b57cec5SDimitry Andric   TimersToPrint.reserve(Records.size());
2480b57cec5SDimitry Andric   for (const auto &P : Records)
2490b57cec5SDimitry Andric     TimersToPrint.emplace_back(P.getValue(), P.getKey(), P.getKey());
2500b57cec5SDimitry Andric   assert(TimersToPrint.size() == Records.size() && "Size mismatch");
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric TimerGroup::~TimerGroup() {
2540b57cec5SDimitry Andric   // If the timer group is destroyed before the timers it owns, accumulate and
2550b57cec5SDimitry Andric   // print the timing data.
2560b57cec5SDimitry Andric   while (FirstTimer)
2570b57cec5SDimitry Andric     removeTimer(*FirstTimer);
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   // Remove the group from the TimerGroupList.
2600b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
2610b57cec5SDimitry Andric   *Prev = Next;
2620b57cec5SDimitry Andric   if (Next)
2630b57cec5SDimitry Andric     Next->Prev = Prev;
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric void TimerGroup::removeTimer(Timer &T) {
2680b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   // If the timer was started, move its data to TimersToPrint.
2710b57cec5SDimitry Andric   if (T.hasTriggered())
2720b57cec5SDimitry Andric     TimersToPrint.emplace_back(T.Time, T.Name, T.Description);
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric   T.TG = nullptr;
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   // Unlink the timer from our list.
2770b57cec5SDimitry Andric   *T.Prev = T.Next;
2780b57cec5SDimitry Andric   if (T.Next)
2790b57cec5SDimitry Andric     T.Next->Prev = T.Prev;
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric   // Print the report when all timers in this group are destroyed if some of
2820b57cec5SDimitry Andric   // them were started.
2830b57cec5SDimitry Andric   if (FirstTimer || TimersToPrint.empty())
2840b57cec5SDimitry Andric     return;
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
2870b57cec5SDimitry Andric   PrintQueuedTimers(*OutStream);
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric void TimerGroup::addTimer(Timer &T) {
2910b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   // Add the timer to our list.
2940b57cec5SDimitry Andric   if (FirstTimer)
2950b57cec5SDimitry Andric     FirstTimer->Prev = &T.Next;
2960b57cec5SDimitry Andric   T.Next = FirstTimer;
2970b57cec5SDimitry Andric   T.Prev = &FirstTimer;
2980b57cec5SDimitry Andric   FirstTimer = &T;
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
3020b57cec5SDimitry Andric   // Sort the timers in descending order by amount of time taken.
3030b57cec5SDimitry Andric   llvm::sort(TimersToPrint);
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   TimeRecord Total;
3060b57cec5SDimitry Andric   for (const PrintRecord &Record : TimersToPrint)
3070b57cec5SDimitry Andric     Total += Record.Time;
3080b57cec5SDimitry Andric 
3090b57cec5SDimitry Andric   // Print out timing header.
3100b57cec5SDimitry Andric   OS << "===" << std::string(73, '-') << "===\n";
3110b57cec5SDimitry Andric   // Figure out how many spaces to indent TimerGroup name.
3120b57cec5SDimitry Andric   unsigned Padding = (80-Description.length())/2;
3130b57cec5SDimitry Andric   if (Padding > 80) Padding = 0;         // Don't allow "negative" numbers
3140b57cec5SDimitry Andric   OS.indent(Padding) << Description << '\n';
3150b57cec5SDimitry Andric   OS << "===" << std::string(73, '-') << "===\n";
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   // If this is not an collection of ungrouped times, print the total time.
3180b57cec5SDimitry Andric   // Ungrouped timers don't really make sense to add up.  We still print the
3190b57cec5SDimitry Andric   // TOTAL line to make the percentages make sense.
3200b57cec5SDimitry Andric   if (this != getDefaultTimerGroup())
3210b57cec5SDimitry Andric     OS << format("  Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
3220b57cec5SDimitry Andric                  Total.getProcessTime(), Total.getWallTime());
3230b57cec5SDimitry Andric   OS << '\n';
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric   if (Total.getUserTime())
3260b57cec5SDimitry Andric     OS << "   ---User Time---";
3270b57cec5SDimitry Andric   if (Total.getSystemTime())
3280b57cec5SDimitry Andric     OS << "   --System Time--";
3290b57cec5SDimitry Andric   if (Total.getProcessTime())
3300b57cec5SDimitry Andric     OS << "   --User+System--";
3310b57cec5SDimitry Andric   OS << "   ---Wall Time---";
3320b57cec5SDimitry Andric   if (Total.getMemUsed())
3330b57cec5SDimitry Andric     OS << "  ---Mem---";
3340b57cec5SDimitry Andric   OS << "  --- Name ---\n";
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric   // Loop through all of the timing data, printing it out.
3370b57cec5SDimitry Andric   for (const PrintRecord &Record : make_range(TimersToPrint.rbegin(),
3380b57cec5SDimitry Andric                                               TimersToPrint.rend())) {
3390b57cec5SDimitry Andric     Record.Time.print(Total, OS);
3400b57cec5SDimitry Andric     OS << Record.Description << '\n';
3410b57cec5SDimitry Andric   }
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   Total.print(Total, OS);
3440b57cec5SDimitry Andric   OS << "Total\n\n";
3450b57cec5SDimitry Andric   OS.flush();
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric   TimersToPrint.clear();
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric void TimerGroup::prepareToPrintList(bool ResetTime) {
3510b57cec5SDimitry Andric   // See if any of our timers were started, if so add them to TimersToPrint.
3520b57cec5SDimitry Andric   for (Timer *T = FirstTimer; T; T = T->Next) {
3530b57cec5SDimitry Andric     if (!T->hasTriggered()) continue;
3540b57cec5SDimitry Andric     bool WasRunning = T->isRunning();
3550b57cec5SDimitry Andric     if (WasRunning)
3560b57cec5SDimitry Andric       T->stopTimer();
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric     TimersToPrint.emplace_back(T->Time, T->Name, T->Description);
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric     if (ResetTime)
3610b57cec5SDimitry Andric       T->clear();
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric     if (WasRunning)
3640b57cec5SDimitry Andric       T->startTimer();
3650b57cec5SDimitry Andric   }
3660b57cec5SDimitry Andric }
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric void TimerGroup::print(raw_ostream &OS, bool ResetAfterPrint) {
3690b57cec5SDimitry Andric   {
3700b57cec5SDimitry Andric     // After preparing the timers we can free the lock
3710b57cec5SDimitry Andric     sys::SmartScopedLock<true> L(*TimerLock);
3720b57cec5SDimitry Andric     prepareToPrintList(ResetAfterPrint);
3730b57cec5SDimitry Andric   }
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric   // If any timers were started, print the group.
3760b57cec5SDimitry Andric   if (!TimersToPrint.empty())
3770b57cec5SDimitry Andric     PrintQueuedTimers(OS);
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric 
3800b57cec5SDimitry Andric void TimerGroup::clear() {
3810b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
3820b57cec5SDimitry Andric   for (Timer *T = FirstTimer; T; T = T->Next)
3830b57cec5SDimitry Andric     T->clear();
3840b57cec5SDimitry Andric }
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric void TimerGroup::printAll(raw_ostream &OS) {
3870b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric   for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
3900b57cec5SDimitry Andric     TG->print(OS);
3910b57cec5SDimitry Andric }
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric void TimerGroup::clearAll() {
3940b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
3950b57cec5SDimitry Andric   for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
3960b57cec5SDimitry Andric     TG->clear();
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
4000b57cec5SDimitry Andric                                 const char *suffix, double Value) {
4010b57cec5SDimitry Andric   assert(yaml::needsQuotes(Name) == yaml::QuotingType::None &&
4020b57cec5SDimitry Andric          "TimerGroup name should not need quotes");
4030b57cec5SDimitry Andric   assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None &&
4040b57cec5SDimitry Andric          "Timer name should not need quotes");
4050b57cec5SDimitry Andric   constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10;
4060b57cec5SDimitry Andric   OS << "\t\"time." << Name << '.' << R.Name << suffix
4070b57cec5SDimitry Andric      << "\": " << format("%.*e", max_digits10 - 1, Value);
4080b57cec5SDimitry Andric }
4090b57cec5SDimitry Andric 
4100b57cec5SDimitry Andric const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
4110b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   prepareToPrintList(false);
4140b57cec5SDimitry Andric   for (const PrintRecord &R : TimersToPrint) {
4150b57cec5SDimitry Andric     OS << delim;
4160b57cec5SDimitry Andric     delim = ",\n";
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric     const TimeRecord &T = R.Time;
4190b57cec5SDimitry Andric     printJSONValue(OS, R, ".wall", T.getWallTime());
4200b57cec5SDimitry Andric     OS << delim;
4210b57cec5SDimitry Andric     printJSONValue(OS, R, ".user", T.getUserTime());
4220b57cec5SDimitry Andric     OS << delim;
4230b57cec5SDimitry Andric     printJSONValue(OS, R, ".sys", T.getSystemTime());
4240b57cec5SDimitry Andric     if (T.getMemUsed()) {
4250b57cec5SDimitry Andric       OS << delim;
4260b57cec5SDimitry Andric       printJSONValue(OS, R, ".mem", T.getMemUsed());
4270b57cec5SDimitry Andric     }
4280b57cec5SDimitry Andric   }
4290b57cec5SDimitry Andric   TimersToPrint.clear();
4300b57cec5SDimitry Andric   return delim;
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
4340b57cec5SDimitry Andric   sys::SmartScopedLock<true> L(*TimerLock);
4350b57cec5SDimitry Andric   for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
4360b57cec5SDimitry Andric     delim = TG->printJSONValues(OS, delim);
4370b57cec5SDimitry Andric   return delim;
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric 
4400b57cec5SDimitry Andric void TimerGroup::ConstructTimerLists() {
4410b57cec5SDimitry Andric   (void)*NamedGroupedTimers;
4420b57cec5SDimitry Andric }
443