lib/CodeGen/AsmPrinter/CMakeLists.txt: Fix CMake build, following up to r127099.
[oota-llvm.git] / lib / Support / Timer.cpp
index daafd63dd2dca69ecace70a7f092bc860b795346..a9ed5eecfa7e0d9c9ee9bfa5cb229a8b752ccb41 100644 (file)
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Format.h"
-#include "llvm/System/Mutex.h"
-#include "llvm/System/Process.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Process.h"
+#include "llvm/ADT/OwningPtr.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;
 }
 
@@ -195,13 +194,40 @@ void TimeRecord::print(const TimeRecord &Total, raw_ostream &OS) const {
 //   NamedRegionTimer Implementation
 //===----------------------------------------------------------------------===//
 
+namespace {
+
 typedef StringMap<Timer> Name2TimerMap;
-typedef StringMap<std::pair<TimerGroup, Name2TimerMap> > Name2PairMap;
+
+class Name2PairMap {
+  StringMap<std::pair<TimerGroup*, Name2TimerMap> > Map;
+public:
+  ~Name2PairMap() {
+    for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator
+         I = Map.begin(), E = Map.end(); I != E; ++I)
+      delete I->second.first;
+  }
+  
+  Timer &get(StringRef Name, StringRef GroupName) {
+    sys::SmartScopedLock<true> L(*TimerLock);
+    
+    std::pair<TimerGroup*, Name2TimerMap> &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<Name2TimerMap> NamedTimers;
 static ManagedStatic<Name2PairMap> NamedGroupedTimers;
 
-static Timer &getNamedRegionTimer(const std::string &Name) {
+static Timer &getNamedRegionTimer(StringRef Name) {
   sys::SmartScopedLock<true> L(*TimerLock);
   
   Timer &T = (*NamedTimers)[Name];
@@ -210,38 +236,45 @@ static Timer &getNamedRegionTimer(const std::string &Name) {
   return T;
 }
 
-static Timer &getNamedRegionTimer(const std::string &Name,
-                                  const std::string &GroupName) {
-  sys::SmartScopedLock<true> L(*TimerLock);
-
-  std::pair<TimerGroup, Name2TimerMap> &GroupEntry =
-    (*NamedGroupedTimers)[GroupName];
-
-  if (GroupEntry.second.empty())
-    GroupEntry.first.setName(GroupName);
-
-  Timer &T = GroupEntry.second[Name];
-  if (!T.isInitialized())
-    T.init(Name);
-  return T;
-}
+NamedRegionTimer::NamedRegionTimer(StringRef Name,
+                                   bool Enabled)
+  : TimeRegion(!Enabled ? 0 : &getNamedRegionTimer(Name)) {}
 
-NamedRegionTimer::NamedRegionTimer(const std::string &Name)
-  : TimeRegion(getNamedRegionTimer(Name)) {}
-
-NamedRegionTimer::NamedRegionTimer(const std::string &Name,
-                                   const std::string &GroupName)
-  : TimeRegion(getNamedRegionTimer(Name, GroupName)) {}
+NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef GroupName,
+                                   bool Enabled)
+  : TimeRegion(!Enabled ? 0 : &NamedGroupedTimers->get(Name, GroupName)) {}
 
 //===----------------------------------------------------------------------===//
 //   TimerGroup Implementation
 //===----------------------------------------------------------------------===//
 
+/// 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;
+
+TimerGroup::TimerGroup(StringRef name)
+  : Name(name.begin(), name.end()), FirstTimer(0) {
+    
+  // Add the group to TimerGroupList.
+  sys::SmartScopedLock<true> L(*TimerLock);
+  if (TimerGroupList)
+    TimerGroupList->Prev = &Next;
+  Next = TimerGroupList;
+  Prev = &TimerGroupList;
+  TimerGroupList = this;
+}
+
 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<true> L(*TimerLock);
+  *Prev = Next;
+  if (Next)
+    Next->Prev = Prev;
 }
 
 
@@ -264,12 +297,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) {
@@ -334,3 +364,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<true> 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<true> L(*TimerLock);
+
+  for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
+    TG->print(OS);
+}