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