Changeset View
Changeset View
Standalone View
Standalone View
lib/Support/Timer.cpp
Show All 13 Lines | |||||
#include "llvm/Support/Timer.h" | #include "llvm/Support/Timer.h" | ||||
#include "llvm/ADT/StringMap.h" | #include "llvm/ADT/StringMap.h" | ||||
#include "llvm/Support/CommandLine.h" | #include "llvm/Support/CommandLine.h" | ||||
#include "llvm/Support/Debug.h" | #include "llvm/Support/Debug.h" | ||||
#include "llvm/Support/FileSystem.h" | #include "llvm/Support/FileSystem.h" | ||||
#include "llvm/Support/Format.h" | #include "llvm/Support/Format.h" | ||||
#include "llvm/Support/ManagedStatic.h" | #include "llvm/Support/ManagedStatic.h" | ||||
#include "llvm/Support/Mutex.h" | #include "llvm/Support/Mutex.h" | ||||
#include "llvm/Support/MutexGuard.h" | |||||
#include "llvm/Support/Process.h" | #include "llvm/Support/Process.h" | ||||
#include "llvm/Support/raw_ostream.h" | #include "llvm/Support/raw_ostream.h" | ||||
using namespace llvm; | using namespace llvm; | ||||
// CreateInfoOutputFile - Return a file stream to print our output on. | // CreateInfoOutputFile - Return a file stream to print our output on. | ||||
namespace llvm { extern raw_ostream *CreateInfoOutputFile(); } | namespace llvm { extern raw_ostream *CreateInfoOutputFile(); } | ||||
// getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy | // getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy | ||||
// of constructor/destructor ordering being unspecified by C++. Basically the | // of constructor/destructor ordering being unspecified by C++. Basically the | ||||
// problem is that a Statistic object gets destroyed, which ends up calling | // problem is that a Statistic object gets destroyed, which ends up calling | ||||
// 'GetLibSupportInfoOutputFile()' (below), which calls this function. | // 'GetLibSupportInfoOutputFile()' (below), which calls this function. | ||||
// LibSupportInfoOutputFilename used to be a global variable, but sometimes it | // LibSupportInfoOutputFilename used to be a global variable, but sometimes it | ||||
// would get destroyed before the Statistic, causing havoc to ensue. We "fix" | // would get destroyed before the Statistic, causing havoc to ensue. We "fix" | ||||
// this by creating the string the first time it is needed and never destroying | // this by creating the string the first time it is needed and never destroying | ||||
// it. | // it. | ||||
static ManagedStatic<std::string> LibSupportInfoOutputFilename; | static ManagedStatic<std::string> LibSupportInfoOutputFilename; | ||||
static std::string &getLibSupportInfoOutputFilename() { | static std::string &getLibSupportInfoOutputFilename() { | ||||
return *LibSupportInfoOutputFilename; | return *LibSupportInfoOutputFilename; | ||||
} | } | ||||
static ManagedStatic<sys::SmartMutex<true> > TimerLock; | static ManagedStatic<sys::RecursiveDebugMutex> TimerLock; | ||||
namespace { | namespace { | ||||
static cl::opt<bool> | static cl::opt<bool> | ||||
TrackSpace("track-memory", cl::desc("Enable -time-passes memory " | TrackSpace("track-memory", cl::desc("Enable -time-passes memory " | ||||
"tracking (this may be slow)"), | "tracking (this may be slow)"), | ||||
cl::Hidden); | cl::Hidden); | ||||
static cl::opt<std::string, true> | static cl::opt<std::string, true> | ||||
▲ Show 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | |||||
public: | public: | ||||
~Name2PairMap() { | ~Name2PairMap() { | ||||
for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator | for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator | ||||
I = Map.begin(), E = Map.end(); I != E; ++I) | I = Map.begin(), E = Map.end(); I != E; ++I) | ||||
delete I->second.first; | delete I->second.first; | ||||
} | } | ||||
Timer &get(StringRef Name, StringRef GroupName) { | Timer &get(StringRef Name, StringRef GroupName) { | ||||
sys::SmartScopedLock<true> L(*TimerLock); | llvm::MutexGuard lock(*TimerLock); | ||||
std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName]; | std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName]; | ||||
if (!GroupEntry.first) | if (!GroupEntry.first) | ||||
GroupEntry.first = new TimerGroup(GroupName); | GroupEntry.first = new TimerGroup(GroupName); | ||||
Timer &T = GroupEntry.second[Name]; | Timer &T = GroupEntry.second[Name]; | ||||
if (!T.isInitialized()) | if (!T.isInitialized()) | ||||
T.init(Name, *GroupEntry.first); | T.init(Name, *GroupEntry.first); | ||||
return T; | return T; | ||||
} | } | ||||
}; | }; | ||||
} | } | ||||
static ManagedStatic<Name2TimerMap> NamedTimers; | static ManagedStatic<Name2TimerMap> NamedTimers; | ||||
static ManagedStatic<Name2PairMap> NamedGroupedTimers; | static ManagedStatic<Name2PairMap> NamedGroupedTimers; | ||||
static Timer &getNamedRegionTimer(StringRef Name) { | static Timer &getNamedRegionTimer(StringRef Name) { | ||||
sys::SmartScopedLock<true> L(*TimerLock); | llvm::MutexGuard lock(*TimerLock); | ||||
Timer &T = (*NamedTimers)[Name]; | Timer &T = (*NamedTimers)[Name]; | ||||
if (!T.isInitialized()) | if (!T.isInitialized()) | ||||
T.init(Name); | T.init(Name); | ||||
return T; | return T; | ||||
} | } | ||||
NamedRegionTimer::NamedRegionTimer(StringRef Name, | NamedRegionTimer::NamedRegionTimer(StringRef Name, | ||||
Show All 11 Lines | |||||
/// TimerGroupList - This is the global list of TimerGroups, maintained by the | /// TimerGroupList - This is the global list of TimerGroups, maintained by the | ||||
/// TimerGroup ctor/dtor and is protected by the TimerLock lock. | /// TimerGroup ctor/dtor and is protected by the TimerLock lock. | ||||
static TimerGroup *TimerGroupList = nullptr; | static TimerGroup *TimerGroupList = nullptr; | ||||
TimerGroup::TimerGroup(StringRef name) | TimerGroup::TimerGroup(StringRef name) | ||||
: Name(name.begin(), name.end()), FirstTimer(nullptr) { | : Name(name.begin(), name.end()), FirstTimer(nullptr) { | ||||
// Add the group to TimerGroupList. | // Add the group to TimerGroupList. | ||||
sys::SmartScopedLock<true> L(*TimerLock); | llvm::MutexGuard lock(*TimerLock); | ||||
if (TimerGroupList) | if (TimerGroupList) | ||||
TimerGroupList->Prev = &Next; | TimerGroupList->Prev = &Next; | ||||
Next = TimerGroupList; | Next = TimerGroupList; | ||||
Prev = &TimerGroupList; | Prev = &TimerGroupList; | ||||
TimerGroupList = this; | TimerGroupList = this; | ||||
} | } | ||||
TimerGroup::~TimerGroup() { | TimerGroup::~TimerGroup() { | ||||
// If the timer group is destroyed before the timers it owns, accumulate and | // If the timer group is destroyed before the timers it owns, accumulate and | ||||
// print the timing data. | // print the timing data. | ||||
while (FirstTimer) | while (FirstTimer) | ||||
removeTimer(*FirstTimer); | removeTimer(*FirstTimer); | ||||
// Remove the group from the TimerGroupList. | // Remove the group from the TimerGroupList. | ||||
sys::SmartScopedLock<true> L(*TimerLock); | llvm::MutexGuard lock(*TimerLock); | ||||
*Prev = Next; | *Prev = Next; | ||||
if (Next) | if (Next) | ||||
Next->Prev = Prev; | Next->Prev = Prev; | ||||
} | } | ||||
void TimerGroup::removeTimer(Timer &T) { | void TimerGroup::removeTimer(Timer &T) { | ||||
sys::SmartScopedLock<true> L(*TimerLock); | llvm::MutexGuard lock(*TimerLock); | ||||
// If the timer was started, move its data to TimersToPrint. | // If the timer was started, move its data to TimersToPrint. | ||||
if (T.Started) | if (T.Started) | ||||
TimersToPrint.push_back(std::make_pair(T.Time, T.Name)); | TimersToPrint.push_back(std::make_pair(T.Time, T.Name)); | ||||
T.TG = nullptr; | T.TG = nullptr; | ||||
// Unlink the timer from our list. | // Unlink the timer from our list. | ||||
*T.Prev = T.Next; | *T.Prev = T.Next; | ||||
if (T.Next) | if (T.Next) | ||||
T.Next->Prev = T.Prev; | T.Next->Prev = T.Prev; | ||||
// Print the report when all timers in this group are destroyed if some of | // Print the report when all timers in this group are destroyed if some of | ||||
// them were started. | // them were started. | ||||
if (FirstTimer || TimersToPrint.empty()) | if (FirstTimer || TimersToPrint.empty()) | ||||
return; | return; | ||||
raw_ostream *OutStream = CreateInfoOutputFile(); | raw_ostream *OutStream = CreateInfoOutputFile(); | ||||
PrintQueuedTimers(*OutStream); | PrintQueuedTimers(*OutStream); | ||||
delete OutStream; // Close the file. | delete OutStream; // Close the file. | ||||
} | } | ||||
void TimerGroup::addTimer(Timer &T) { | void TimerGroup::addTimer(Timer &T) { | ||||
sys::SmartScopedLock<true> L(*TimerLock); | llvm::MutexGuard lock(*TimerLock); | ||||
// Add the timer to our list. | // Add the timer to our list. | ||||
if (FirstTimer) | if (FirstTimer) | ||||
FirstTimer->Prev = &T.Next; | FirstTimer->Prev = &T.Next; | ||||
T.Next = FirstTimer; | T.Next = FirstTimer; | ||||
T.Prev = &FirstTimer; | T.Prev = &FirstTimer; | ||||
FirstTimer = &T; | FirstTimer = &T; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { | ||||
OS << "Total\n\n"; | OS << "Total\n\n"; | ||||
OS.flush(); | OS.flush(); | ||||
TimersToPrint.clear(); | TimersToPrint.clear(); | ||||
} | } | ||||
/// print - Print any started timers in this group and zero them. | /// print - Print any started timers in this group and zero them. | ||||
void TimerGroup::print(raw_ostream &OS) { | void TimerGroup::print(raw_ostream &OS) { | ||||
sys::SmartScopedLock<true> L(*TimerLock); | llvm::MutexGuard lock(*TimerLock); | ||||
// See if any of our timers were started, if so add them to TimersToPrint and | // See if any of our timers were started, if so add them to TimersToPrint and | ||||
// reset them. | // reset them. | ||||
for (Timer *T = FirstTimer; T; T = T->Next) { | for (Timer *T = FirstTimer; T; T = T->Next) { | ||||
if (!T->Started) continue; | if (!T->Started) continue; | ||||
TimersToPrint.push_back(std::make_pair(T->Time, T->Name)); | TimersToPrint.push_back(std::make_pair(T->Time, T->Name)); | ||||
// Clear out the time. | // Clear out the time. | ||||
T->Started = 0; | T->Started = 0; | ||||
T->Time = TimeRecord(); | T->Time = TimeRecord(); | ||||
} | } | ||||
// If any timers were started, print the group. | // If any timers were started, print the group. | ||||
if (!TimersToPrint.empty()) | if (!TimersToPrint.empty()) | ||||
PrintQueuedTimers(OS); | PrintQueuedTimers(OS); | ||||
} | } | ||||
/// printAll - This static method prints all timers and clears them all out. | /// printAll - This static method prints all timers and clears them all out. | ||||
void TimerGroup::printAll(raw_ostream &OS) { | void TimerGroup::printAll(raw_ostream &OS) { | ||||
sys::SmartScopedLock<true> L(*TimerLock); | llvm::MutexGuard lock(*TimerLock); | ||||
for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next) | for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next) | ||||
TG->print(OS); | TG->print(OS); | ||||
} | } |