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