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())); 56*e8d8bef9SDimitry Andric 57*e8d8bef9SDimitry Andric static cl::opt<bool> 58*e8d8bef9SDimitry Andric SortTimers("sort-timers", cl::desc("In the report, sort the timers in each group " 59*e8d8bef9SDimitry Andric "in wall clock time order"), 60*e8d8bef9SDimitry Andric cl::init(true), cl::Hidden); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric std::unique_ptr<raw_fd_ostream> llvm::CreateInfoOutputFile() { 640b57cec5SDimitry Andric const std::string &OutputFilename = getLibSupportInfoOutputFilename(); 650b57cec5SDimitry Andric if (OutputFilename.empty()) 668bcb0991SDimitry Andric return std::make_unique<raw_fd_ostream>(2, false); // stderr. 670b57cec5SDimitry Andric if (OutputFilename == "-") 688bcb0991SDimitry Andric return std::make_unique<raw_fd_ostream>(1, false); // stdout. 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // Append mode is used because the info output file is opened and closed 710b57cec5SDimitry Andric // each time -stats or -time-passes wants to print output to it. To 720b57cec5SDimitry Andric // compensate for this, the test-suite Makefiles have code to delete the 730b57cec5SDimitry Andric // info output file before running commands which write to it. 740b57cec5SDimitry Andric std::error_code EC; 758bcb0991SDimitry Andric auto Result = std::make_unique<raw_fd_ostream>( 768bcb0991SDimitry Andric OutputFilename, EC, sys::fs::OF_Append | sys::fs::OF_Text); 770b57cec5SDimitry Andric if (!EC) 780b57cec5SDimitry Andric return Result; 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric errs() << "Error opening info-output-file '" 810b57cec5SDimitry Andric << OutputFilename << " for appending!\n"; 828bcb0991SDimitry Andric return std::make_unique<raw_fd_ostream>(2, false); // stderr. 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric namespace { 860b57cec5SDimitry Andric struct CreateDefaultTimerGroup { 870b57cec5SDimitry Andric static void *call() { 880b57cec5SDimitry Andric return new TimerGroup("misc", "Miscellaneous Ungrouped Timers"); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric }; 910b57cec5SDimitry Andric } // namespace 920b57cec5SDimitry Andric static ManagedStatic<TimerGroup, CreateDefaultTimerGroup> DefaultTimerGroup; 930b57cec5SDimitry Andric static TimerGroup *getDefaultTimerGroup() { return &*DefaultTimerGroup; } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 960b57cec5SDimitry Andric // Timer Implementation 970b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 980b57cec5SDimitry Andric 99480093f4SDimitry Andric void Timer::init(StringRef TimerName, StringRef TimerDescription) { 100480093f4SDimitry Andric init(TimerName, TimerDescription, *getDefaultTimerGroup()); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 103480093f4SDimitry Andric void Timer::init(StringRef TimerName, StringRef TimerDescription, 104480093f4SDimitry Andric TimerGroup &tg) { 1050b57cec5SDimitry Andric assert(!TG && "Timer already initialized"); 106480093f4SDimitry Andric Name.assign(TimerName.begin(), TimerName.end()); 107480093f4SDimitry Andric Description.assign(TimerDescription.begin(), TimerDescription.end()); 1080b57cec5SDimitry Andric Running = Triggered = false; 1090b57cec5SDimitry Andric TG = &tg; 1100b57cec5SDimitry Andric TG->addTimer(*this); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric Timer::~Timer() { 1140b57cec5SDimitry Andric if (!TG) return; // Never initialized, or already cleared. 1150b57cec5SDimitry Andric TG->removeTimer(*this); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric static inline size_t getMemUsage() { 1190b57cec5SDimitry Andric if (!TrackSpace) return 0; 1200b57cec5SDimitry Andric return sys::Process::GetMallocUsage(); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric TimeRecord TimeRecord::getCurrentTime(bool Start) { 1240b57cec5SDimitry Andric using Seconds = std::chrono::duration<double, std::ratio<1>>; 1250b57cec5SDimitry Andric TimeRecord Result; 1260b57cec5SDimitry Andric sys::TimePoint<> now; 1270b57cec5SDimitry Andric std::chrono::nanoseconds user, sys; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric if (Start) { 1300b57cec5SDimitry Andric Result.MemUsed = getMemUsage(); 1310b57cec5SDimitry Andric sys::Process::GetTimeUsage(now, user, sys); 1320b57cec5SDimitry Andric } else { 1330b57cec5SDimitry Andric sys::Process::GetTimeUsage(now, user, sys); 1340b57cec5SDimitry Andric Result.MemUsed = getMemUsage(); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric Result.WallTime = Seconds(now.time_since_epoch()).count(); 1380b57cec5SDimitry Andric Result.UserTime = Seconds(user).count(); 1390b57cec5SDimitry Andric Result.SystemTime = Seconds(sys).count(); 1400b57cec5SDimitry Andric return Result; 1410b57cec5SDimitry Andric } 1420b57cec5SDimitry Andric 1430b57cec5SDimitry Andric void Timer::startTimer() { 1440b57cec5SDimitry Andric assert(!Running && "Cannot start a running timer"); 1450b57cec5SDimitry Andric Running = Triggered = true; 146*e8d8bef9SDimitry Andric Signposts->startInterval(this, getName()); 1470b57cec5SDimitry Andric StartTime = TimeRecord::getCurrentTime(true); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric void Timer::stopTimer() { 1510b57cec5SDimitry Andric assert(Running && "Cannot stop a paused timer"); 1520b57cec5SDimitry Andric Running = false; 1530b57cec5SDimitry Andric Time += TimeRecord::getCurrentTime(false); 1540b57cec5SDimitry Andric Time -= StartTime; 155*e8d8bef9SDimitry Andric Signposts->endInterval(this, getName()); 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric void Timer::clear() { 1590b57cec5SDimitry Andric Running = Triggered = false; 1600b57cec5SDimitry Andric Time = StartTime = TimeRecord(); 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric static void printVal(double Val, double Total, raw_ostream &OS) { 1640b57cec5SDimitry Andric if (Total < 1e-7) // Avoid dividing by zero. 1650b57cec5SDimitry Andric OS << " ----- "; 1660b57cec5SDimitry Andric else 1670b57cec5SDimitry Andric OS << format(" %7.4f (%5.1f%%)", Val, Val*100/Total); 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const { 1710b57cec5SDimitry Andric if (Total.getUserTime()) 1720b57cec5SDimitry Andric printVal(getUserTime(), Total.getUserTime(), OS); 1730b57cec5SDimitry Andric if (Total.getSystemTime()) 1740b57cec5SDimitry Andric printVal(getSystemTime(), Total.getSystemTime(), OS); 1750b57cec5SDimitry Andric if (Total.getProcessTime()) 1760b57cec5SDimitry Andric printVal(getProcessTime(), Total.getProcessTime(), OS); 1770b57cec5SDimitry Andric printVal(getWallTime(), Total.getWallTime(), OS); 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric OS << " "; 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric if (Total.getMemUsed()) 1820b57cec5SDimitry Andric OS << format("%9" PRId64 " ", (int64_t)getMemUsed()); 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1870b57cec5SDimitry Andric // NamedRegionTimer Implementation 1880b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric namespace { 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric typedef StringMap<Timer> Name2TimerMap; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric class Name2PairMap { 1950b57cec5SDimitry Andric StringMap<std::pair<TimerGroup*, Name2TimerMap> > Map; 1960b57cec5SDimitry Andric public: 1970b57cec5SDimitry Andric ~Name2PairMap() { 1980b57cec5SDimitry Andric for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator 1990b57cec5SDimitry Andric I = Map.begin(), E = Map.end(); I != E; ++I) 2000b57cec5SDimitry Andric delete I->second.first; 2010b57cec5SDimitry Andric } 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric Timer &get(StringRef Name, StringRef Description, StringRef GroupName, 2040b57cec5SDimitry Andric StringRef GroupDescription) { 2050b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName]; 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric if (!GroupEntry.first) 2100b57cec5SDimitry Andric GroupEntry.first = new TimerGroup(GroupName, GroupDescription); 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric Timer &T = GroupEntry.second[Name]; 2130b57cec5SDimitry Andric if (!T.isInitialized()) 2140b57cec5SDimitry Andric T.init(Name, Description, *GroupEntry.first); 2150b57cec5SDimitry Andric return T; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric }; 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric static ManagedStatic<Name2PairMap> NamedGroupedTimers; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef Description, 2240b57cec5SDimitry Andric StringRef GroupName, 2250b57cec5SDimitry Andric StringRef GroupDescription, bool Enabled) 2260b57cec5SDimitry Andric : TimeRegion(!Enabled ? nullptr 2270b57cec5SDimitry Andric : &NamedGroupedTimers->get(Name, Description, GroupName, 2280b57cec5SDimitry Andric GroupDescription)) {} 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2310b57cec5SDimitry Andric // TimerGroup Implementation 2320b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric /// This is the global list of TimerGroups, maintained by the TimerGroup 2350b57cec5SDimitry Andric /// ctor/dtor and is protected by the TimerLock lock. 2360b57cec5SDimitry Andric static TimerGroup *TimerGroupList = nullptr; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric TimerGroup::TimerGroup(StringRef Name, StringRef Description) 2390b57cec5SDimitry Andric : Name(Name.begin(), Name.end()), 2400b57cec5SDimitry Andric Description(Description.begin(), Description.end()) { 2410b57cec5SDimitry Andric // Add the group to TimerGroupList. 2420b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 2430b57cec5SDimitry Andric if (TimerGroupList) 2440b57cec5SDimitry Andric TimerGroupList->Prev = &Next; 2450b57cec5SDimitry Andric Next = TimerGroupList; 2460b57cec5SDimitry Andric Prev = &TimerGroupList; 2470b57cec5SDimitry Andric TimerGroupList = this; 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric TimerGroup::TimerGroup(StringRef Name, StringRef Description, 2510b57cec5SDimitry Andric const StringMap<TimeRecord> &Records) 2520b57cec5SDimitry Andric : TimerGroup(Name, Description) { 2530b57cec5SDimitry Andric TimersToPrint.reserve(Records.size()); 2540b57cec5SDimitry Andric for (const auto &P : Records) 2555ffd83dbSDimitry Andric TimersToPrint.emplace_back(P.getValue(), std::string(P.getKey()), 2565ffd83dbSDimitry Andric std::string(P.getKey())); 2570b57cec5SDimitry Andric assert(TimersToPrint.size() == Records.size() && "Size mismatch"); 2580b57cec5SDimitry Andric } 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric TimerGroup::~TimerGroup() { 2610b57cec5SDimitry Andric // If the timer group is destroyed before the timers it owns, accumulate and 2620b57cec5SDimitry Andric // print the timing data. 2630b57cec5SDimitry Andric while (FirstTimer) 2640b57cec5SDimitry Andric removeTimer(*FirstTimer); 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric // Remove the group from the TimerGroupList. 2670b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 2680b57cec5SDimitry Andric *Prev = Next; 2690b57cec5SDimitry Andric if (Next) 2700b57cec5SDimitry Andric Next->Prev = Prev; 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric void TimerGroup::removeTimer(Timer &T) { 2750b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric // If the timer was started, move its data to TimersToPrint. 2780b57cec5SDimitry Andric if (T.hasTriggered()) 2790b57cec5SDimitry Andric TimersToPrint.emplace_back(T.Time, T.Name, T.Description); 2800b57cec5SDimitry Andric 2810b57cec5SDimitry Andric T.TG = nullptr; 2820b57cec5SDimitry Andric 2830b57cec5SDimitry Andric // Unlink the timer from our list. 2840b57cec5SDimitry Andric *T.Prev = T.Next; 2850b57cec5SDimitry Andric if (T.Next) 2860b57cec5SDimitry Andric T.Next->Prev = T.Prev; 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric // Print the report when all timers in this group are destroyed if some of 2890b57cec5SDimitry Andric // them were started. 2900b57cec5SDimitry Andric if (FirstTimer || TimersToPrint.empty()) 2910b57cec5SDimitry Andric return; 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile(); 2940b57cec5SDimitry Andric PrintQueuedTimers(*OutStream); 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric void TimerGroup::addTimer(Timer &T) { 2980b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric // Add the timer to our list. 3010b57cec5SDimitry Andric if (FirstTimer) 3020b57cec5SDimitry Andric FirstTimer->Prev = &T.Next; 3030b57cec5SDimitry Andric T.Next = FirstTimer; 3040b57cec5SDimitry Andric T.Prev = &FirstTimer; 3050b57cec5SDimitry Andric FirstTimer = &T; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { 309*e8d8bef9SDimitry Andric // Perhaps sort the timers in descending order by amount of time taken. 310*e8d8bef9SDimitry Andric if (SortTimers) 3110b57cec5SDimitry Andric llvm::sort(TimersToPrint); 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric TimeRecord Total; 3140b57cec5SDimitry Andric for (const PrintRecord &Record : TimersToPrint) 3150b57cec5SDimitry Andric Total += Record.Time; 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric // Print out timing header. 3180b57cec5SDimitry Andric OS << "===" << std::string(73, '-') << "===\n"; 3190b57cec5SDimitry Andric // Figure out how many spaces to indent TimerGroup name. 3200b57cec5SDimitry Andric unsigned Padding = (80-Description.length())/2; 3210b57cec5SDimitry Andric if (Padding > 80) Padding = 0; // Don't allow "negative" numbers 3220b57cec5SDimitry Andric OS.indent(Padding) << Description << '\n'; 3230b57cec5SDimitry Andric OS << "===" << std::string(73, '-') << "===\n"; 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric // If this is not an collection of ungrouped times, print the total time. 3260b57cec5SDimitry Andric // Ungrouped timers don't really make sense to add up. We still print the 3270b57cec5SDimitry Andric // TOTAL line to make the percentages make sense. 3280b57cec5SDimitry Andric if (this != getDefaultTimerGroup()) 3290b57cec5SDimitry Andric OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n", 3300b57cec5SDimitry Andric Total.getProcessTime(), Total.getWallTime()); 3310b57cec5SDimitry Andric OS << '\n'; 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric if (Total.getUserTime()) 3340b57cec5SDimitry Andric OS << " ---User Time---"; 3350b57cec5SDimitry Andric if (Total.getSystemTime()) 3360b57cec5SDimitry Andric OS << " --System Time--"; 3370b57cec5SDimitry Andric if (Total.getProcessTime()) 3380b57cec5SDimitry Andric OS << " --User+System--"; 3390b57cec5SDimitry Andric OS << " ---Wall Time---"; 3400b57cec5SDimitry Andric if (Total.getMemUsed()) 3410b57cec5SDimitry Andric OS << " ---Mem---"; 3420b57cec5SDimitry Andric OS << " --- Name ---\n"; 3430b57cec5SDimitry Andric 3440b57cec5SDimitry Andric // Loop through all of the timing data, printing it out. 3450b57cec5SDimitry Andric for (const PrintRecord &Record : make_range(TimersToPrint.rbegin(), 3460b57cec5SDimitry Andric TimersToPrint.rend())) { 3470b57cec5SDimitry Andric Record.Time.print(Total, OS); 3480b57cec5SDimitry Andric OS << Record.Description << '\n'; 3490b57cec5SDimitry Andric } 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric Total.print(Total, OS); 3520b57cec5SDimitry Andric OS << "Total\n\n"; 3530b57cec5SDimitry Andric OS.flush(); 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric TimersToPrint.clear(); 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric void TimerGroup::prepareToPrintList(bool ResetTime) { 3590b57cec5SDimitry Andric // See if any of our timers were started, if so add them to TimersToPrint. 3600b57cec5SDimitry Andric for (Timer *T = FirstTimer; T; T = T->Next) { 3610b57cec5SDimitry Andric if (!T->hasTriggered()) continue; 3620b57cec5SDimitry Andric bool WasRunning = T->isRunning(); 3630b57cec5SDimitry Andric if (WasRunning) 3640b57cec5SDimitry Andric T->stopTimer(); 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andric TimersToPrint.emplace_back(T->Time, T->Name, T->Description); 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric if (ResetTime) 3690b57cec5SDimitry Andric T->clear(); 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric if (WasRunning) 3720b57cec5SDimitry Andric T->startTimer(); 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric void TimerGroup::print(raw_ostream &OS, bool ResetAfterPrint) { 3770b57cec5SDimitry Andric { 3780b57cec5SDimitry Andric // After preparing the timers we can free the lock 3790b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 3800b57cec5SDimitry Andric prepareToPrintList(ResetAfterPrint); 3810b57cec5SDimitry Andric } 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric // If any timers were started, print the group. 3840b57cec5SDimitry Andric if (!TimersToPrint.empty()) 3850b57cec5SDimitry Andric PrintQueuedTimers(OS); 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric void TimerGroup::clear() { 3890b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 3900b57cec5SDimitry Andric for (Timer *T = FirstTimer; T; T = T->Next) 3910b57cec5SDimitry Andric T->clear(); 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric void TimerGroup::printAll(raw_ostream &OS) { 3950b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next) 3980b57cec5SDimitry Andric TG->print(OS); 3990b57cec5SDimitry Andric } 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andric void TimerGroup::clearAll() { 4020b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 4030b57cec5SDimitry Andric for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next) 4040b57cec5SDimitry Andric TG->clear(); 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R, 4080b57cec5SDimitry Andric const char *suffix, double Value) { 4090b57cec5SDimitry Andric assert(yaml::needsQuotes(Name) == yaml::QuotingType::None && 4100b57cec5SDimitry Andric "TimerGroup name should not need quotes"); 4110b57cec5SDimitry Andric assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None && 4120b57cec5SDimitry Andric "Timer name should not need quotes"); 4130b57cec5SDimitry Andric constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10; 4140b57cec5SDimitry Andric OS << "\t\"time." << Name << '.' << R.Name << suffix 4150b57cec5SDimitry Andric << "\": " << format("%.*e", max_digits10 - 1, Value); 4160b57cec5SDimitry Andric } 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) { 4190b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric prepareToPrintList(false); 4220b57cec5SDimitry Andric for (const PrintRecord &R : TimersToPrint) { 4230b57cec5SDimitry Andric OS << delim; 4240b57cec5SDimitry Andric delim = ",\n"; 4250b57cec5SDimitry Andric 4260b57cec5SDimitry Andric const TimeRecord &T = R.Time; 4270b57cec5SDimitry Andric printJSONValue(OS, R, ".wall", T.getWallTime()); 4280b57cec5SDimitry Andric OS << delim; 4290b57cec5SDimitry Andric printJSONValue(OS, R, ".user", T.getUserTime()); 4300b57cec5SDimitry Andric OS << delim; 4310b57cec5SDimitry Andric printJSONValue(OS, R, ".sys", T.getSystemTime()); 4320b57cec5SDimitry Andric if (T.getMemUsed()) { 4330b57cec5SDimitry Andric OS << delim; 4340b57cec5SDimitry Andric printJSONValue(OS, R, ".mem", T.getMemUsed()); 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric TimersToPrint.clear(); 4380b57cec5SDimitry Andric return delim; 4390b57cec5SDimitry Andric } 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) { 4420b57cec5SDimitry Andric sys::SmartScopedLock<true> L(*TimerLock); 4430b57cec5SDimitry Andric for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next) 4440b57cec5SDimitry Andric delim = TG->printJSONValues(OS, delim); 4450b57cec5SDimitry Andric return delim; 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric void TimerGroup::ConstructTimerLists() { 4490b57cec5SDimitry Andric (void)*NamedGroupedTimers; 4500b57cec5SDimitry Andric } 451cd675bb6SDimitry Andric 452cd675bb6SDimitry Andric std::unique_ptr<TimerGroup> TimerGroup::aquireDefaultGroup() { 453cd675bb6SDimitry Andric return std::unique_ptr<TimerGroup>(DefaultTimerGroup.claim()); 454cd675bb6SDimitry Andric } 455