X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FSupport%2FTimer.cpp;h=896d869aa1e7ed6a9c3fcf8597f79eb29af76a28;hb=fe532525cc4912ec0d1b4e91fa0396122dd087b3;hp=cc903805e8fa9f4a0ac63d978b646d7d57732a8a;hpb=b9312690a2a79de490ab9c439b9b5d7c9319bff8;p=oota-llvm.git diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index cc903805e8f..896d869aa1e 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -12,18 +12,19 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Timer.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Format.h" -#include "llvm/System/Mutex.h" -#include "llvm/System/Process.h" -#include "llvm/ADT/StringMap.h" using namespace llvm; -// GetLibSupportInfoOutputFile - Return a file stream to print our output on. -namespace llvm { extern raw_ostream *GetLibSupportInfoOutputFile(); } +// CreateInfoOutputFile - Return a file stream to print our output on. +namespace llvm { extern raw_ostream *CreateInfoOutputFile(); } // getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy // of constructor/destructor ordering being unspecified by C++. Basically the @@ -52,24 +53,28 @@ namespace { cl::Hidden, cl::location(getLibSupportInfoOutputFilename())); } -// GetLibSupportInfoOutputFile - Return a file stream to print our output on. -raw_ostream *llvm::GetLibSupportInfoOutputFile() { - std::string &LibSupportInfoOutputFilename = getLibSupportInfoOutputFilename(); - if (LibSupportInfoOutputFilename.empty()) - return &errs(); - if (LibSupportInfoOutputFilename == "-") - return &outs(); +// CreateInfoOutputFile - Return a file stream to print our output on. +raw_ostream *llvm::CreateInfoOutputFile() { + const std::string &OutputFilename = getLibSupportInfoOutputFilename(); + if (OutputFilename.empty()) + return new raw_fd_ostream(2, false); // stderr. + if (OutputFilename == "-") + return new raw_fd_ostream(1, false); // stdout. + // Append mode is used because the info output file is opened and closed + // each time -stats or -time-passes wants to print output to it. To + // compensate for this, the test-suite Makefiles have code to delete the + // info output file before running commands which write to it. std::string Error; - raw_ostream *Result = new raw_fd_ostream(LibSupportInfoOutputFilename.c_str(), + raw_ostream *Result = new raw_fd_ostream(OutputFilename.c_str(), Error, raw_fd_ostream::F_Append); if (Error.empty()) return Result; errs() << "Error opening info-output-file '" - << LibSupportInfoOutputFilename << " for appending!\n"; + << OutputFilename << " for appending!\n"; delete Result; - return &errs(); + return new raw_fd_ostream(2, false); // stderr. } @@ -95,53 +100,47 @@ static TimerGroup *getDefaultTimerGroup() { // Timer Implementation //===----------------------------------------------------------------------===// -void Timer::init(const std::string &N) { +void Timer::init(StringRef N) { assert(TG == 0 && "Timer already initialized"); - Name = N; + Name.assign(N.begin(), N.end()); Started = false; TG = getDefaultTimerGroup(); TG->addTimer(*this); } -void Timer::init(const std::string &N, TimerGroup &tg) { +void Timer::init(StringRef N, TimerGroup &tg) { assert(TG == 0 && "Timer already initialized"); - Name = N; + Name.assign(N.begin(), N.end()); Started = false; TG = &tg; TG->addTimer(*this); } Timer::~Timer() { - if (!TG) return; // Never initialized. + if (!TG) return; // Never initialized, or already cleared. TG->removeTimer(*this); } static inline size_t getMemUsage() { - if (TrackSpace) - return sys::Process::GetMallocUsage(); - return 0; + if (!TrackSpace) return 0; + return sys::Process::GetMallocUsage(); } TimeRecord TimeRecord::getCurrentTime(bool Start) { TimeRecord Result; - - sys::TimeValue now(0,0); - sys::TimeValue user(0,0); - sys::TimeValue sys(0,0); - - ssize_t MemUsed = 0; + sys::TimeValue now(0,0), user(0,0), sys(0,0); + if (Start) { - MemUsed = getMemUsage(); + Result.MemUsed = getMemUsage(); sys::Process::GetTimeUsage(now, user, sys); } else { sys::Process::GetTimeUsage(now, user, sys); - MemUsed = getMemUsage(); + Result.MemUsed = getMemUsage(); } Result.WallTime = now.seconds() + now.microseconds() / 1000000.0; Result.UserTime = user.seconds() + user.microseconds() / 1000000.0; Result.SystemTime = sys.seconds() + sys.microseconds() / 1000000.0; - Result.MemUsed = MemUsed; return Result; } @@ -169,10 +168,8 @@ void Timer::stopTimer() { static void printVal(double Val, double Total, raw_ostream &OS) { if (Total < 1e-7) // Avoid dividing by zero. OS << " ----- "; - else { - OS << " " << format("%7.4f", Val) << " ("; - OS << format("%5.1f", Val*100/Total) << "%)"; - } + else + OS << format(" %7.4f (%5.1f%%)", Val, Val*100/Total); } void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const { @@ -187,7 +184,7 @@ void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const { OS << " "; if (Total.getMemUsed()) - OS << format("%9lld", (long long)getMemUsed()) << " "; + OS << format("%9" PRId64 " ", (int64_t)getMemUsed()); } @@ -195,13 +192,40 @@ void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const { // NamedRegionTimer Implementation //===----------------------------------------------------------------------===// +namespace { + typedef StringMap Name2TimerMap; -typedef StringMap > Name2PairMap; + +class Name2PairMap { + StringMap > Map; +public: + ~Name2PairMap() { + for (StringMap >::iterator + I = Map.begin(), E = Map.end(); I != E; ++I) + delete I->second.first; + } + + Timer &get(StringRef Name, StringRef GroupName) { + sys::SmartScopedLock L(*TimerLock); + + std::pair &GroupEntry = Map[GroupName]; + + if (!GroupEntry.first) + GroupEntry.first = new TimerGroup(GroupName); + + Timer &T = GroupEntry.second[Name]; + if (!T.isInitialized()) + T.init(Name, *GroupEntry.first); + return T; + } +}; + +} static ManagedStatic NamedTimers; static ManagedStatic NamedGroupedTimers; -static Timer &getNamedRegionTimer(const std::string &Name) { +static Timer &getNamedRegionTimer(StringRef Name) { sys::SmartScopedLock L(*TimerLock); Timer &T = (*NamedTimers)[Name]; @@ -210,41 +234,56 @@ static Timer &getNamedRegionTimer(const std::string &Name) { return T; } -static Timer &getNamedRegionTimer(const std::string &Name, - const std::string &GroupName) { - sys::SmartScopedLock L(*TimerLock); +NamedRegionTimer::NamedRegionTimer(StringRef Name, + bool Enabled) + : TimeRegion(!Enabled ? 0 : &getNamedRegionTimer(Name)) {} - std::pair &GroupEntry = - (*NamedGroupedTimers)[GroupName]; +NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef GroupName, + bool Enabled) + : TimeRegion(!Enabled ? 0 : &NamedGroupedTimers->get(Name, GroupName)) {} - if (GroupEntry.second.empty()) - GroupEntry.first.setName(GroupName); +//===----------------------------------------------------------------------===// +// TimerGroup Implementation +//===----------------------------------------------------------------------===// - Timer &T = GroupEntry.second[Name]; - if (!T.isInitialized()) - T.init(Name); - return T; -} +/// TimerGroupList - This is the global list of TimerGroups, maintained by the +/// TimerGroup ctor/dtor and is protected by the TimerLock lock. +static TimerGroup *TimerGroupList = 0; -NamedRegionTimer::NamedRegionTimer(const std::string &Name) - : TimeRegion(getNamedRegionTimer(Name)) {} +TimerGroup::TimerGroup(StringRef name) + : Name(name.begin(), name.end()), FirstTimer(0) { + + // Add the group to TimerGroupList. + sys::SmartScopedLock L(*TimerLock); + if (TimerGroupList) + TimerGroupList->Prev = &Next; + Next = TimerGroupList; + Prev = &TimerGroupList; + TimerGroupList = this; +} -NamedRegionTimer::NamedRegionTimer(const std::string &Name, - const std::string &GroupName) - : TimeRegion(getNamedRegionTimer(Name, GroupName)) {} +TimerGroup::~TimerGroup() { + // If the timer group is destroyed before the timers it owns, accumulate and + // print the timing data. + while (FirstTimer != 0) + removeTimer(*FirstTimer); + + // Remove the group from the TimerGroupList. + sys::SmartScopedLock L(*TimerLock); + *Prev = Next; + if (Next) + Next->Prev = Prev; +} -//===----------------------------------------------------------------------===// -// TimerGroup Implementation -//===----------------------------------------------------------------------===// void TimerGroup::removeTimer(Timer &T) { sys::SmartScopedLock L(*TimerLock); // If the timer was started, move its data to TimersToPrint. - if (T.Started) { - T.Started = false; + if (T.Started) TimersToPrint.push_back(std::make_pair(T.Time, T.Name)); - } + + T.TG = 0; // Unlink the timer from our list. *T.Prev = T.Next; @@ -256,12 +295,9 @@ void TimerGroup::removeTimer(Timer &T) { if (FirstTimer != 0 || TimersToPrint.empty()) return; - raw_ostream *OutStream = GetLibSupportInfoOutputFile(); - + raw_ostream *OutStream = CreateInfoOutputFile(); PrintQueuedTimers(*OutStream); - - if (OutStream != &errs() && OutStream != &outs()) - delete OutStream; // Close the file. + delete OutStream; // Close the file. } void TimerGroup::addTimer(Timer &T) { @@ -294,11 +330,9 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { // If this is not an collection of ungrouped times, print the total time. // Ungrouped timers don't really make sense to add up. We still print the // TOTAL line to make the percentages make sense. - if (this != DefaultTimerGroup) { - OS << " Total Execution Time: "; - OS << format("%5.4f", Total.getProcessTime()) << " seconds ("; - OS << format("%5.4f", Total.getWallTime()) << " wall clock)\n"; - } + if (this != DefaultTimerGroup) + OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n", + Total.getProcessTime(), Total.getWallTime()); OS << '\n'; if (Total.getUserTime()) @@ -326,3 +360,30 @@ void TimerGroup::PrintQueuedTimers(raw_ostream &OS) { TimersToPrint.clear(); } +/// print - Print any started timers in this group and zero them. +void TimerGroup::print(raw_ostream &OS) { + sys::SmartScopedLock L(*TimerLock); + + // See if any of our timers were started, if so add them to TimersToPrint and + // reset them. + for (Timer *T = FirstTimer; T; T = T->Next) { + if (!T->Started) continue; + TimersToPrint.push_back(std::make_pair(T->Time, T->Name)); + + // Clear out the time. + T->Started = 0; + T->Time = TimeRecord(); + } + + // If any timers were started, print the group. + if (!TimersToPrint.empty()) + PrintQueuedTimers(OS); +} + +/// printAll - This static method prints all timers and clears them all out. +void TimerGroup::printAll(raw_ostream &OS) { + sys::SmartScopedLock L(*TimerLock); + + for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next) + TG->print(OS); +}