LLVM API Documentation
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.