LLVM API Documentation

Timer.cpp

Go to the documentation of this file.
00001 //===-- Timer.cpp - Interval Timing Support -------------------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // Interval Timing implementation.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "llvm/Support/Timer.h"
00015 #include "llvm/Support/CommandLine.h"
00016 #include "llvm/Support/ManagedStatic.h"
00017 #include "llvm/Support/Streams.h"
00018 #include "llvm/System/Process.h"
00019 #include <algorithm>
00020 #include <fstream>
00021 #include <functional>
00022 #include <map>
00023 using namespace llvm;
00024 
00025 // GetLibSupportInfoOutputFile - Return a file stream to print our output on.
00026 namespace llvm { extern std::ostream *GetLibSupportInfoOutputFile(); }
00027 
00028 // getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy
00029 // of constructor/destructor ordering being unspecified by C++.  Basically the
00030 // problem is that a Statistic object gets destroyed, which ends up calling
00031 // 'GetLibSupportInfoOutputFile()' (below), which calls this function.
00032 // LibSupportInfoOutputFilename used to be a global variable, but sometimes it
00033 // would get destroyed before the Statistic, causing havoc to ensue.  We "fix"
00034 // this by creating the string the first time it is needed and never destroying
00035 // it.
00036 static ManagedStatic<std::string> LibSupportInfoOutputFilename;
00037 static std::string &getLibSupportInfoOutputFilename() {
00038   return *LibSupportInfoOutputFilename;
00039 }
00040 
00041 namespace {
00042   static cl::opt<bool>
00043   TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
00044                                       "tracking (this may be slow)"),
00045              cl::Hidden);
00046 
00047   static cl::opt<std::string, true>
00048   InfoOutputFilename("info-output-file", cl::value_desc("filename"),
00049                      cl::desc("File to append -stats and -timer output to"),
00050                    cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
00051 }
00052 
00053 static TimerGroup *DefaultTimerGroup = 0;
00054 static TimerGroup *getDefaultTimerGroup() {
00055   if (DefaultTimerGroup) return DefaultTimerGroup;
00056   return DefaultTimerGroup = new TimerGroup("Miscellaneous Ungrouped Timers");
00057 }
00058 
00059 Timer::Timer(const std::string &N)
00060   : Elapsed(0), UserTime(0), SystemTime(0), MemUsed(0), PeakMem(0), Name(N),
00061     Started(false), TG(getDefaultTimerGroup()) {
00062   TG->addTimer();
00063 }
00064 
00065 Timer::Timer(const std::string &N, TimerGroup &tg)
00066   : Elapsed(0), UserTime(0), SystemTime(0), MemUsed(0), PeakMem(0), Name(N),
00067     Started(false), TG(&tg) {
00068   TG->addTimer();
00069 }
00070 
00071 Timer::Timer(const Timer &T) {
00072   TG = T.TG;
00073   if (TG) TG->addTimer();
00074   operator=(T);
00075 }
00076 
00077 
00078 // Copy ctor, initialize with no TG member.
00079 Timer::Timer(bool, const Timer &T) {
00080   TG = T.TG;     // Avoid assertion in operator=
00081   operator=(T);  // Copy contents
00082   TG = 0;
00083 }
00084 
00085 
00086 Timer::~Timer() {
00087   if (TG) {
00088     if (Started) {
00089       Started = false;
00090       TG->addTimerToPrint(*this);
00091     }
00092     TG->removeTimer();
00093   }
00094 }
00095 
00096 static inline size_t getMemUsage() {
00097   if (TrackSpace)
00098     return sys::Process::GetMallocUsage();
00099   return 0;
00100 }
00101 
00102 struct TimeRecord {
00103   double Elapsed, UserTime, SystemTime;
00104   ssize_t MemUsed;
00105 };
00106 
00107 static TimeRecord getTimeRecord(bool Start) {
00108   TimeRecord Result;
00109 
00110   sys::TimeValue now(0,0);
00111   sys::TimeValue user(0,0);
00112   sys::TimeValue sys(0,0);
00113 
00114   ssize_t MemUsed = 0;
00115   if (Start) {
00116     MemUsed = getMemUsage();
00117     sys::Process::GetTimeUsage(now,user,sys);
00118   } else {
00119     sys::Process::GetTimeUsage(now,user,sys);
00120     MemUsed = getMemUsage();
00121   }
00122 
00123   Result.Elapsed  = now.seconds()  + now.microseconds()  / 1000000.0;
00124   Result.UserTime = user.seconds() + user.microseconds() / 1000000.0;
00125   Result.SystemTime  = sys.seconds()  + sys.microseconds()  / 1000000.0;
00126   Result.MemUsed  = MemUsed;
00127 
00128   return Result;
00129 }
00130 
00131 static ManagedStatic<std::vector<Timer*> > ActiveTimers;
00132 
00133 void Timer::startTimer() {
00134   Started = true;
00135   ActiveTimers->push_back(this);
00136   TimeRecord TR = getTimeRecord(true);
00137   Elapsed    -= TR.Elapsed;
00138   UserTime   -= TR.UserTime;
00139   SystemTime -= TR.SystemTime;
00140   MemUsed    -= TR.MemUsed;
00141   PeakMemBase = TR.MemUsed;
00142 }
00143 
00144 void Timer::stopTimer() {
00145   TimeRecord TR = getTimeRecord(false);
00146   Elapsed    += TR.Elapsed;
00147   UserTime   += TR.UserTime;
00148   SystemTime += TR.SystemTime;
00149   MemUsed    += TR.MemUsed;
00150 
00151   if (ActiveTimers->back() == this) {
00152     ActiveTimers->pop_back();
00153   } else {
00154     std::vector<Timer*>::iterator I =
00155       std::find(ActiveTimers->begin(), ActiveTimers->end(), this);
00156     assert(I != ActiveTimers->end() && "stop but no startTimer?");
00157     ActiveTimers->erase(I);
00158   }
00159 }
00160 
00161 void Timer::sum(const Timer &T) {
00162   Elapsed    += T.Elapsed;
00163   UserTime   += T.UserTime;
00164   SystemTime += T.SystemTime;
00165   MemUsed    += T.MemUsed;
00166   PeakMem    += T.PeakMem;
00167 }
00168 
00169 /// addPeakMemoryMeasurement - This method should be called whenever memory
00170 /// usage needs to be checked.  It adds a peak memory measurement to the
00171 /// currently active timers, which will be printed when the timer group prints
00172 ///
00173 void Timer::addPeakMemoryMeasurement() {
00174   size_t MemUsed = getMemUsage();
00175 
00176   for (std::vector<Timer*>::iterator I = ActiveTimers->begin(),
00177          E = ActiveTimers->end(); I != E; ++I)
00178     (*I)->PeakMem = std::max((*I)->PeakMem, MemUsed-(*I)->PeakMemBase);
00179 }
00180 
00181 //===----------------------------------------------------------------------===//
00182 //   NamedRegionTimer Implementation
00183 //===----------------------------------------------------------------------===//
00184 
00185 namespace {
00186 
00187 typedef std::map<std::string, Timer> Name2Timer;
00188 typedef std::map<std::string, std::pair<TimerGroup, Name2Timer> > Name2Pair;
00189 
00190 }
00191 
00192 static ManagedStatic<Name2Timer> NamedTimers;
00193 
00194 static ManagedStatic<Name2Pair> NamedGroupedTimers;
00195 
00196 static Timer &getNamedRegionTimer(const std::string &Name) {
00197   Name2Timer::iterator I = NamedTimers->find(Name);
00198   if (I != NamedTimers->end())
00199     return I->second;
00200 
00201   return NamedTimers->insert(I, std::make_pair(Name, Timer(Name)))->second;
00202 }
00203 
00204 static Timer &getNamedRegionTimer(const std::string &Name,
00205                                   const std::string &GroupName) {
00206 
00207   Name2Pair::iterator I = NamedGroupedTimers->find(GroupName);
00208   if (I == NamedGroupedTimers->end()) {
00209     TimerGroup TG(GroupName);
00210     std::pair<TimerGroup, Name2Timer> Pair(TG, Name2Timer());
00211     I = NamedGroupedTimers->insert(I, std::make_pair(GroupName, Pair));
00212   }
00213 
00214   Name2Timer::iterator J = I->second.second.find(Name);
00215   if (J == I->second.second.end())
00216     J = I->second.second.insert(J,
00217                                 std::make_pair(Name,
00218                                                Timer(Name,
00219                                                      I->second.first)));
00220 
00221   return J->second;
00222 }
00223 
00224 NamedRegionTimer::NamedRegionTimer(const std::string &Name)
00225   : TimeRegion(getNamedRegionTimer(Name)) {}
00226 
00227 NamedRegionTimer::NamedRegionTimer(const std::string &Name,
00228                                    const std::string &GroupName)
00229   : TimeRegion(getNamedRegionTimer(Name, GroupName)) {}
00230 
00231 //===----------------------------------------------------------------------===//
00232 //   TimerGroup Implementation
00233 //===----------------------------------------------------------------------===//
00234 
00235 // printAlignedFP - Simulate the printf "%A.Bf" format, where A is the
00236 // TotalWidth size, and B is the AfterDec size.
00237 //
00238 static void printAlignedFP(double Val, unsigned AfterDec, unsigned TotalWidth,
00239                            std::ostream &OS) {
00240   assert(TotalWidth >= AfterDec+1 && "Bad FP Format!");
00241   OS.width(TotalWidth-AfterDec-1);
00242   char OldFill = OS.fill();
00243   OS.fill(' ');
00244   OS << (int)Val;  // Integer part;
00245   OS << ".";
00246   OS.width(AfterDec);
00247   OS.fill('0');
00248   unsigned ResultFieldSize = 1;
00249   while (AfterDec--) ResultFieldSize *= 10;
00250   OS << (int)(Val*ResultFieldSize) % ResultFieldSize;
00251   OS.fill(OldFill);
00252 }
00253 
00254 static void printVal(double Val, double Total, std::ostream &OS) {
00255   if (Total < 1e-7)   // Avoid dividing by zero...
00256     OS << "        -----     ";
00257   else {
00258     OS << "  ";
00259     printAlignedFP(Val, 4, 7, OS);
00260     OS << " (";
00261     printAlignedFP(Val*100/Total, 1, 5, OS);
00262     OS << "%)";
00263   }
00264 }
00265 
00266 void Timer::print(const Timer &Total, std::ostream &OS) {
00267   if (Total.UserTime)
00268     printVal(UserTime, Total.UserTime, OS);
00269   if (Total.SystemTime)
00270     printVal(SystemTime, Total.SystemTime, OS);
00271   if (Total.getProcessTime())
00272     printVal(getProcessTime(), Total.getProcessTime(), OS);
00273   printVal(Elapsed, Total.Elapsed, OS);
00274 
00275   OS << "  ";
00276 
00277   if (Total.MemUsed) {
00278     OS.width(9);
00279     OS << MemUsed << "  ";
00280   }
00281   if (Total.PeakMem) {
00282     if (PeakMem) {
00283       OS.width(9);
00284       OS << PeakMem << "  ";
00285     } else
00286       OS << "           ";
00287   }
00288   OS << Name << "\n";
00289 
00290   Started = false;  // Once printed, don't print again
00291 }
00292 
00293 // GetLibSupportInfoOutputFile - Return a file stream to print our output on...
00294 std::ostream *
00295 llvm::GetLibSupportInfoOutputFile() {
00296   std::string &LibSupportInfoOutputFilename = getLibSupportInfoOutputFilename();
00297   if (LibSupportInfoOutputFilename.empty())
00298     return cerr.stream();
00299   if (LibSupportInfoOutputFilename == "-")
00300     return cout.stream();
00301 
00302   std::ostream *Result = new std::ofstream(LibSupportInfoOutputFilename.c_str(),
00303                                            std::ios::app);
00304   if (!Result->good()) {
00305     cerr << "Error opening info-output-file '"
00306          << LibSupportInfoOutputFilename << " for appending!\n";
00307     delete Result;
00308     return cerr.stream();
00309   }
00310   return Result;
00311 }
00312 
00313 
00314 void TimerGroup::removeTimer() {
00315   if (--NumTimers == 0 && !TimersToPrint.empty()) { // Print timing report...
00316     // Sort the timers in descending order by amount of time taken...
00317     std::sort(TimersToPrint.begin(), TimersToPrint.end(),
00318               std::greater<Timer>());
00319 
00320     // Figure out how many spaces to indent TimerGroup name...
00321     unsigned Padding = (80-Name.length())/2;
00322     if (Padding > 80) Padding = 0;         // Don't allow "negative" numbers
00323 
00324     std::ostream *OutStream = GetLibSupportInfoOutputFile();
00325 
00326     ++NumTimers;
00327     {  // Scope to contain Total timer... don't allow total timer to drop us to
00328        // zero timers...
00329       Timer Total("TOTAL");
00330 
00331       for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i)
00332         Total.sum(TimersToPrint[i]);
00333 
00334       // Print out timing header...
00335       *OutStream << "===" << std::string(73, '-') << "===\n"
00336                  << std::string(Padding, ' ') << Name << "\n"
00337                  << "===" << std::string(73, '-')
00338                  << "===\n";
00339 
00340       // If this is not an collection of ungrouped times, print the total time.
00341       // Ungrouped timers don't really make sense to add up.  We still print the
00342       // TOTAL line to make the percentages make sense.
00343       if (this != DefaultTimerGroup) {
00344         *OutStream << "  Total Execution Time: ";
00345 
00346         printAlignedFP(Total.getProcessTime(), 4, 5, *OutStream);
00347         *OutStream << " seconds (";
00348         printAlignedFP(Total.getWallTime(), 4, 5, *OutStream);
00349         *OutStream << " wall clock)\n";
00350       }
00351       *OutStream << "\n";
00352 
00353       if (Total.UserTime)
00354         *OutStream << "   ---User Time---";
00355       if (Total.SystemTime)
00356         *OutStream << "   --System Time--";
00357       if (Total.getProcessTime())
00358         *OutStream << "   --User+System--";
00359       *OutStream << "   ---Wall Time---";
00360       if (Total.getMemUsed())
00361         *OutStream << "  ---Mem---";
00362       if (Total.getPeakMem())
00363         *OutStream << "  -PeakMem-";
00364       *OutStream << "  --- Name ---\n";
00365 
00366       // Loop through all of the timing data, printing it out...
00367       for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i)
00368         TimersToPrint[i].print(Total, *OutStream);
00369 
00370       Total.print(Total, *OutStream);
00371       *OutStream << std::endl;  // Flush output
00372     }
00373     --NumTimers;
00374 
00375     TimersToPrint.clear();
00376 
00377     if (OutStream != cerr.stream() && OutStream != cout.stream())
00378       delete OutStream;   // Close the file...
00379   }
00380 
00381   // Delete default timer group!
00382   if (NumTimers == 0 && this == DefaultTimerGroup) {
00383     delete DefaultTimerGroup;
00384     DefaultTimerGroup = 0;
00385   }
00386 }
00387 



This web site is hosted by the Computer Science Department at the University of Illinois at Urbana-Champaign.