Timer.cpp revision 6cd11f6535600da5f286056748d4817e0f44b778
1//===-- Timer.cpp - Interval Timing Support -------------------------------===// 2// 3// Interval Timing implementation. 4// 5//===----------------------------------------------------------------------===// 6 7#include "Support/Timer.h" 8#include <sys/resource.h> 9#include <sys/time.h> 10#include <sys/unistd.h> 11#include <unistd.h> 12#include <malloc.h> 13#include <stdio.h> 14#include <iostream> 15#include <algorithm> 16#include <functional> 17 18static TimerGroup *DefaultTimerGroup = 0; 19static TimerGroup *getDefaultTimerGroup() { 20 if (DefaultTimerGroup) return DefaultTimerGroup; 21 return DefaultTimerGroup = new TimerGroup("Miscellaneous Ungrouped Timers"); 22} 23 24Timer::Timer(const std::string &N) 25 : Elapsed(0), UserTime(0), SystemTime(0), MaxRSS(0), Name(N), 26 Started(false), TG(getDefaultTimerGroup()) { 27 TG->addTimer(); 28} 29 30Timer::Timer(const std::string &N, TimerGroup &tg) 31 : Elapsed(0), UserTime(0), SystemTime(0), MaxRSS(0), Name(N), 32 Started(false), TG(&tg) { 33 TG->addTimer(); 34} 35 36Timer::Timer(const Timer &T) { 37 TG = T.TG; 38 if (TG) TG->addTimer(); 39 operator=(T); 40} 41 42 43// Copy ctor, initialize with no TG member. 44Timer::Timer(bool, const Timer &T) { 45 TG = T.TG; // Avoid assertion in operator= 46 operator=(T); // Copy contents 47 TG = 0; 48} 49 50 51Timer::~Timer() { 52 if (TG) { 53 if (Started) { 54 Started = false; 55 TG->addTimerToPrint(*this); 56 } 57 TG->removeTimer(); 58 } 59} 60 61struct TimeRecord { 62 double Elapsed, UserTime, SystemTime; 63 unsigned long MaxRSS; 64}; 65 66static TimeRecord getTimeRecord() { 67 struct rusage RU; 68 struct timeval T; 69 gettimeofday(&T, 0); 70 if (getrusage(RUSAGE_SELF, &RU)) { 71 perror("getrusage call failed: -time-passes info incorrect!"); 72 } 73 74 TimeRecord Result; 75 Result.Elapsed = T.tv_sec + T.tv_usec/1000000.0; 76 Result.UserTime = RU.ru_utime.tv_sec + RU.ru_utime.tv_usec/1000000.0; 77 Result.SystemTime = RU.ru_stime.tv_sec + RU.ru_stime.tv_usec/1000000.0; 78 79#ifndef __sparc__ 80 struct mallinfo MI = mallinfo(); 81 Result.MaxRSS = MI.uordblks; 82#else 83 Result.MaxRSS = 0; 84#endif 85 86 return Result; 87} 88 89void Timer::startTimer() { 90 Started = true; 91 TimeRecord TR = getTimeRecord(); 92 Elapsed -= TR.Elapsed; 93 UserTime -= TR.UserTime; 94 SystemTime -= TR.SystemTime; 95 MaxRSS -= TR.MaxRSS; 96} 97 98void Timer::stopTimer() { 99 TimeRecord TR = getTimeRecord(); 100 Elapsed += TR.Elapsed; 101 UserTime += TR.UserTime; 102 SystemTime += TR.SystemTime; 103 MaxRSS += TR.MaxRSS; 104 if ((signed long)MaxRSS < 0) 105 MaxRSS = 0; 106} 107 108void Timer::sum(const Timer &T) { 109 Elapsed += T.Elapsed; 110 UserTime += T.UserTime; 111 SystemTime += T.SystemTime; 112 MaxRSS += T.MaxRSS; 113} 114 115//===----------------------------------------------------------------------===// 116// TimerGroup Implementation 117//===----------------------------------------------------------------------===// 118 119static void printVal(double Val, double Total) { 120 if (Total < 1e-7) // Avoid dividing by zero... 121 fprintf(stderr, " ----- "); 122 else 123 fprintf(stderr, " %7.4f (%5.1f%%)", Val, Val*100/Total); 124} 125 126void Timer::print(const Timer &Total) { 127 if (Total.UserTime) 128 printVal(UserTime, Total.UserTime); 129 if (Total.SystemTime) 130 printVal(SystemTime, Total.SystemTime); 131 if (Total.getProcessTime()) 132 printVal(getProcessTime(), Total.getProcessTime()); 133 printVal(Elapsed, Total.Elapsed); 134 135 fprintf(stderr, " "); 136 137 if (Total.MaxRSS) 138 fprintf(stderr, " %8ld ", MaxRSS); 139 std::cerr << Name << "\n"; 140 141 Started = false; // Once printed, don't print again 142} 143 144 145void TimerGroup::removeTimer() { 146 if (--NumTimers == 0 && !TimersToPrint.empty()) { // Print timing report... 147 // Sort the timers in descending order by amount of time taken... 148 std::sort(TimersToPrint.begin(), TimersToPrint.end(), 149 std::greater<Timer>()); 150 151 // Figure out how many spaces to indent TimerGroup name... 152 unsigned Padding = (80-Name.length())/2; 153 if (Padding > 80) Padding = 0; // Don't allow "negative" numbers 154 155 ++NumTimers; 156 { // Scope to contain Total timer... don't allow total timer to drop us to 157 // zero timers... 158 Timer Total("TOTAL"); 159 160 for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i) 161 Total.sum(TimersToPrint[i]); 162 163 // Print out timing header... 164 std::cerr << "===" << std::string(73, '-') << "===\n" 165 << std::string(Padding, ' ') << Name << "\n" 166 << "===" << std::string(73, '-') 167 << "===\n Total Execution Time: " << Total.getProcessTime() 168 << " seconds (" << Total.getWallTime() 169 << " wall clock)\n\n"; 170 171 if (Total.UserTime) 172 std::cerr << " ---User Time---"; 173 if (Total.SystemTime) 174 std::cerr << " --System Time--"; 175 if (Total.getProcessTime()) 176 std::cerr << " --User+System--"; 177 std::cerr << " ---Wall Time---"; 178 179 if (Total.getMaxRSS()) 180 std::cerr << " ---Mem---"; 181 std::cerr << " --- Name ---\n"; 182 183 // Loop through all of the timing data, printing it out... 184 for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i) 185 TimersToPrint[i].print(Total); 186 187 Total.print(Total); 188 std::cerr << std::endl; // Flush output 189 } 190 --NumTimers; 191 192 TimersToPrint.clear(); 193 } 194 195 // Delete default timer group! 196 if (NumTimers == 0 && this == DefaultTimerGroup) { 197 delete DefaultTimerGroup; 198 DefaultTimerGroup = 0; 199 } 200} 201