blob: 4b88be2b094749ead52cc1270ef0e4927e66049e [file] [log] [blame]
Chris Lattner6c38a792002-10-01 19:36:54 +00001//===-- Timer.cpp - Interval Timing Support -------------------------------===//
John Criswellb576c942003-10-20 19:43:21 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by the LLVM research group and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Chris Lattner6c38a792002-10-01 19:36:54 +00009//
10// Interval Timing implementation.
11//
12//===----------------------------------------------------------------------===//
13
Reid Spencer551ccae2004-09-01 22:55:40 +000014#include "llvm/Support/Timer.h"
15#include "llvm/Support/CommandLine.h"
Chris Lattnerb4db5f32004-06-07 19:34:51 +000016#include <algorithm>
17#include <iostream>
18#include <functional>
19#include <fstream>
20#include <map>
Reid Spencer551ccae2004-09-01 22:55:40 +000021#include "llvm/Config/sys/resource.h"
22#include "llvm/Config/sys/time.h"
23#include "llvm/Config/unistd.h"
24#include "llvm/Config/malloc.h"
25#include "llvm/Config/windows.h"
Chris Lattnerb6d465f2003-12-14 21:27:33 +000026using namespace llvm;
Chris Lattnerf205fec2003-05-09 20:05:44 +000027
Chris Lattnerb4db5f32004-06-07 19:34:51 +000028// GetLibSupportInfoOutputFile - Return a file stream to print our output on.
Chris Lattnerb6d465f2003-12-14 21:27:33 +000029namespace llvm { extern std::ostream *GetLibSupportInfoOutputFile(); }
Brian Gaeked0fde302003-11-11 22:41:34 +000030
Chris Lattner71336a92003-07-31 19:38:34 +000031// getLibSupportInfoOutputFilename - This ugly hack is brought to you courtesy
32// of constructor/destructor ordering being unspecified by C++. Basically the
33// problem is that a Statistic<> object gets destroyed, which ends up calling
34// 'GetLibSupportInfoOutputFile()' (below), which calls this function.
35// LibSupportInfoOutputFilename used to be a global variable, but sometimes it
Reid Spencer4af3da62004-12-13 16:04:04 +000036// would get destroyed before the Statistic, causing havoc to ensue.
Chris Lattner71336a92003-07-31 19:38:34 +000037static std::string &getLibSupportInfoOutputFilename() {
Reid Spencer4af3da62004-12-13 16:04:04 +000038 static std::string LibSupportInfoOutputFilename;
39 return LibSupportInfoOutputFilename;
Chris Lattner71336a92003-07-31 19:38:34 +000040}
Chris Lattner6c38a792002-10-01 19:36:54 +000041
Chris Lattner3f398492003-01-30 23:08:50 +000042namespace {
John Criswell7a73b802003-06-30 21:59:07 +000043#ifdef HAVE_MALLINFO
Chris Lattner3f398492003-01-30 23:08:50 +000044 cl::opt<bool>
45 TrackSpace("track-memory", cl::desc("Enable -time-passes memory "
46 "tracking (this may be slow)"),
47 cl::Hidden);
John Criswell7a73b802003-06-30 21:59:07 +000048#endif
Chris Lattnerf205fec2003-05-09 20:05:44 +000049
50 cl::opt<std::string, true>
Chris Lattner96a54db2003-08-01 22:15:15 +000051 InfoOutputFilename("info-output-file", cl::value_desc("filename"),
Chris Lattnerf205fec2003-05-09 20:05:44 +000052 cl::desc("File to append -stats and -timer output to"),
Chris Lattner71336a92003-07-31 19:38:34 +000053 cl::Hidden, cl::location(getLibSupportInfoOutputFilename()));
Chris Lattner3f398492003-01-30 23:08:50 +000054}
55
Chris Lattner6c38a792002-10-01 19:36:54 +000056static TimerGroup *DefaultTimerGroup = 0;
57static TimerGroup *getDefaultTimerGroup() {
58 if (DefaultTimerGroup) return DefaultTimerGroup;
59 return DefaultTimerGroup = new TimerGroup("Miscellaneous Ungrouped Timers");
60}
61
62Timer::Timer(const std::string &N)
Chris Lattner8f0d8242002-11-18 21:47:09 +000063 : Elapsed(0), UserTime(0), SystemTime(0), MemUsed(0), PeakMem(0), Name(N),
Chris Lattner6c38a792002-10-01 19:36:54 +000064 Started(false), TG(getDefaultTimerGroup()) {
65 TG->addTimer();
66}
67
68Timer::Timer(const std::string &N, TimerGroup &tg)
Chris Lattner8f0d8242002-11-18 21:47:09 +000069 : Elapsed(0), UserTime(0), SystemTime(0), MemUsed(0), PeakMem(0), Name(N),
Chris Lattner6c38a792002-10-01 19:36:54 +000070 Started(false), TG(&tg) {
71 TG->addTimer();
72}
73
74Timer::Timer(const Timer &T) {
75 TG = T.TG;
76 if (TG) TG->addTimer();
77 operator=(T);
78}
79
80
81// Copy ctor, initialize with no TG member.
82Timer::Timer(bool, const Timer &T) {
83 TG = T.TG; // Avoid assertion in operator=
84 operator=(T); // Copy contents
85 TG = 0;
86}
87
88
89Timer::~Timer() {
90 if (TG) {
91 if (Started) {
92 Started = false;
93 TG->addTimerToPrint(*this);
94 }
95 TG->removeTimer();
96 }
97}
98
Chris Lattner8f0d8242002-11-18 21:47:09 +000099static long getMemUsage() {
John Criswell7a73b802003-06-30 21:59:07 +0000100#ifdef HAVE_MALLINFO
Chris Lattner3f398492003-01-30 23:08:50 +0000101 if (TrackSpace) {
102 struct mallinfo MI = mallinfo();
Chris Lattnere040f972003-02-13 05:07:53 +0000103 return MI.uordblks/*+MI.hblkhd*/;
Chris Lattner3f398492003-01-30 23:08:50 +0000104 }
John Criswell7a73b802003-06-30 21:59:07 +0000105#endif
Brian Gaeke8c638832003-06-17 19:54:00 +0000106 return 0;
Chris Lattner8f0d8242002-11-18 21:47:09 +0000107}
108
Chris Lattner6c38a792002-10-01 19:36:54 +0000109struct TimeRecord {
110 double Elapsed, UserTime, SystemTime;
Chris Lattner18eba912002-11-04 19:19:36 +0000111 long MemUsed;
Chris Lattner6c38a792002-10-01 19:36:54 +0000112};
113
Chris Lattner8f0d8242002-11-18 21:47:09 +0000114static TimeRecord getTimeRecord(bool Start) {
Chris Lattnerb4db5f32004-06-07 19:34:51 +0000115#if defined(HAVE_WINDOWS_H)
116 unsigned __int64 ProcCreate, ProcExit, KernelTime, UserTime, CurTime;
117
118 GetProcessTimes(GetCurrentProcess(), (FILETIME*)&ProcCreate,
119 (FILETIME*)&ProcExit, (FILETIME*)&KernelTime,
120 (FILETIME*)&UserTime);
121 GetSystemTimeAsFileTime((FILETIME*)&CurTime);
122
123 // FILETIME's are # of 100 nanosecond ticks.
124 double ScaleFactor = 1.0/(10*1000*1000);
125
126 TimeRecord Result;
127 Result.Elapsed = (CurTime-ProcCreate)*ScaleFactor; // Wall time
128 Result.UserTime = UserTime*ScaleFactor;
129 Result.SystemTime = KernelTime*ScaleFactor;
130 return Result;
131#elif defined(HAVE_GETRUSAGE)
Chris Lattner6c38a792002-10-01 19:36:54 +0000132 struct rusage RU;
133 struct timeval T;
Chris Lattnerbbe5ac12003-02-05 21:44:28 +0000134 long MemUsed = 0;
Chris Lattner8f0d8242002-11-18 21:47:09 +0000135 if (Start) {
136 MemUsed = getMemUsage();
137 if (getrusage(RUSAGE_SELF, &RU))
138 perror("getrusage call failed: -time-passes info incorrect!");
139 }
Chris Lattner6c38a792002-10-01 19:36:54 +0000140 gettimeofday(&T, 0);
Chris Lattner8f0d8242002-11-18 21:47:09 +0000141
142 if (!Start) {
Chris Lattner8f0d8242002-11-18 21:47:09 +0000143 if (getrusage(RUSAGE_SELF, &RU))
144 perror("getrusage call failed: -time-passes info incorrect!");
Chris Lattnerb6d465f2003-12-14 21:27:33 +0000145 MemUsed = getMemUsage();
Chris Lattner6c38a792002-10-01 19:36:54 +0000146 }
147
148 TimeRecord Result;
Reid Spencer6475b8d2004-11-19 04:59:07 +0000149 Result.Elapsed = T.tv_sec + T.tv_usec/1000000.0;
Chris Lattner6c38a792002-10-01 19:36:54 +0000150 Result.UserTime = RU.ru_utime.tv_sec + RU.ru_utime.tv_usec/1000000.0;
151 Result.SystemTime = RU.ru_stime.tv_sec + RU.ru_stime.tv_usec/1000000.0;
Chris Lattner8f0d8242002-11-18 21:47:09 +0000152 Result.MemUsed = MemUsed;
Chris Lattner6c38a792002-10-01 19:36:54 +0000153 return Result;
Chris Lattnerb4db5f32004-06-07 19:34:51 +0000154#else
155 // Can't get resource usage.
156 return TimeRecord();
157#endif
Chris Lattner6c38a792002-10-01 19:36:54 +0000158}
159
Chris Lattner8f0d8242002-11-18 21:47:09 +0000160static std::vector<Timer*> ActiveTimers;
161
Chris Lattner6c38a792002-10-01 19:36:54 +0000162void Timer::startTimer() {
163 Started = true;
Chris Lattner8f0d8242002-11-18 21:47:09 +0000164 TimeRecord TR = getTimeRecord(true);
Chris Lattner6c38a792002-10-01 19:36:54 +0000165 Elapsed -= TR.Elapsed;
166 UserTime -= TR.UserTime;
167 SystemTime -= TR.SystemTime;
Chris Lattner18eba912002-11-04 19:19:36 +0000168 MemUsed -= TR.MemUsed;
Chris Lattner8f0d8242002-11-18 21:47:09 +0000169 PeakMemBase = TR.MemUsed;
170 ActiveTimers.push_back(this);
Chris Lattner6c38a792002-10-01 19:36:54 +0000171}
172
173void Timer::stopTimer() {
Chris Lattner8f0d8242002-11-18 21:47:09 +0000174 TimeRecord TR = getTimeRecord(false);
Chris Lattner6c38a792002-10-01 19:36:54 +0000175 Elapsed += TR.Elapsed;
176 UserTime += TR.UserTime;
177 SystemTime += TR.SystemTime;
Chris Lattner18eba912002-11-04 19:19:36 +0000178 MemUsed += TR.MemUsed;
Chris Lattner8f0d8242002-11-18 21:47:09 +0000179
180 if (ActiveTimers.back() == this) {
181 ActiveTimers.pop_back();
182 } else {
183 std::vector<Timer*>::iterator I =
184 std::find(ActiveTimers.begin(), ActiveTimers.end(), this);
185 assert(I != ActiveTimers.end() && "stop but no startTimer?");
186 ActiveTimers.erase(I);
187 }
Chris Lattner6c38a792002-10-01 19:36:54 +0000188}
189
190void Timer::sum(const Timer &T) {
191 Elapsed += T.Elapsed;
192 UserTime += T.UserTime;
193 SystemTime += T.SystemTime;
Chris Lattner18eba912002-11-04 19:19:36 +0000194 MemUsed += T.MemUsed;
Chris Lattner8f0d8242002-11-18 21:47:09 +0000195 PeakMem += T.PeakMem;
Chris Lattner6c38a792002-10-01 19:36:54 +0000196}
197
Chris Lattner8f0d8242002-11-18 21:47:09 +0000198/// addPeakMemoryMeasurement - This method should be called whenever memory
199/// usage needs to be checked. It adds a peak memory measurement to the
200/// currently active timers, which will be printed when the timer group prints
201///
202void Timer::addPeakMemoryMeasurement() {
203 long MemUsed = getMemUsage();
204
205 for (std::vector<Timer*>::iterator I = ActiveTimers.begin(),
206 E = ActiveTimers.end(); I != E; ++I)
207 (*I)->PeakMem = std::max((*I)->PeakMem, MemUsed-(*I)->PeakMemBase);
208}
209
Chris Lattnerd5a310e2003-10-06 15:02:31 +0000210//===----------------------------------------------------------------------===//
211// NamedRegionTimer Implementation
212//===----------------------------------------------------------------------===//
213
214static Timer &getNamedRegionTimer(const std::string &Name) {
215 static std::map<std::string, Timer> NamedTimers;
216
217 std::map<std::string, Timer>::iterator I = NamedTimers.lower_bound(Name);
218 if (I != NamedTimers.end() && I->first == Name)
219 return I->second;
220
221 return NamedTimers.insert(I, std::make_pair(Name, Timer(Name)))->second;
222}
223
224NamedRegionTimer::NamedRegionTimer(const std::string &Name)
225 : TimeRegion(getNamedRegionTimer(Name)) {}
226
Chris Lattner8f0d8242002-11-18 21:47:09 +0000227
Chris Lattner6c38a792002-10-01 19:36:54 +0000228//===----------------------------------------------------------------------===//
229// TimerGroup Implementation
230//===----------------------------------------------------------------------===//
231
Chris Lattnerf205fec2003-05-09 20:05:44 +0000232// printAlignedFP - Simulate the printf "%A.Bf" format, where A is the
233// TotalWidth size, and B is the AfterDec size.
234//
235static void printAlignedFP(double Val, unsigned AfterDec, unsigned TotalWidth,
236 std::ostream &OS) {
237 assert(TotalWidth >= AfterDec+1 && "Bad FP Format!");
238 OS.width(TotalWidth-AfterDec-1);
239 char OldFill = OS.fill();
240 OS.fill(' ');
241 OS << (int)Val; // Integer part;
242 OS << ".";
243 OS.width(AfterDec);
244 OS.fill('0');
245 unsigned ResultFieldSize = 1;
246 while (AfterDec--) ResultFieldSize *= 10;
247 OS << (int)(Val*ResultFieldSize) % ResultFieldSize;
248 OS.fill(OldFill);
Chris Lattner6c38a792002-10-01 19:36:54 +0000249}
250
Chris Lattnerf205fec2003-05-09 20:05:44 +0000251static void printVal(double Val, double Total, std::ostream &OS) {
252 if (Total < 1e-7) // Avoid dividing by zero...
253 OS << " ----- ";
254 else {
255 OS << " ";
256 printAlignedFP(Val, 4, 7, OS);
257 OS << " (";
258 printAlignedFP(Val*100/Total, 1, 5, OS);
259 OS << "%)";
Chris Lattner8f0d8242002-11-18 21:47:09 +0000260 }
Chris Lattnerf205fec2003-05-09 20:05:44 +0000261}
262
263void Timer::print(const Timer &Total, std::ostream &OS) {
264 if (Total.UserTime)
265 printVal(UserTime, Total.UserTime, OS);
266 if (Total.SystemTime)
267 printVal(SystemTime, Total.SystemTime, OS);
268 if (Total.getProcessTime())
269 printVal(getProcessTime(), Total.getProcessTime(), OS);
270 printVal(Elapsed, Total.Elapsed, OS);
271
272 OS << " ";
273
274 if (Total.MemUsed) {
275 OS.width(9);
276 OS << MemUsed << " ";
277 }
278 if (Total.PeakMem) {
279 if (PeakMem) {
280 OS.width(9);
281 OS << PeakMem << " ";
282 } else
283 OS << " ";
284 }
285 OS << Name << "\n";
Chris Lattner6c38a792002-10-01 19:36:54 +0000286
287 Started = false; // Once printed, don't print again
288}
289
Chris Lattnerf205fec2003-05-09 20:05:44 +0000290// GetLibSupportInfoOutputFile - Return a file stream to print our output on...
Brian Gaeked0fde302003-11-11 22:41:34 +0000291std::ostream *
Chris Lattnerb6d465f2003-12-14 21:27:33 +0000292llvm::GetLibSupportInfoOutputFile() {
Chris Lattner71336a92003-07-31 19:38:34 +0000293 std::string &LibSupportInfoOutputFilename = getLibSupportInfoOutputFilename();
Chris Lattnerf205fec2003-05-09 20:05:44 +0000294 if (LibSupportInfoOutputFilename.empty())
295 return &std::cerr;
296 if (LibSupportInfoOutputFilename == "-")
297 return &std::cout;
298
299 std::ostream *Result = new std::ofstream(LibSupportInfoOutputFilename.c_str(),
Chris Lattner903c2d12003-06-06 22:13:01 +0000300 std::ios::app);
Chris Lattnerf205fec2003-05-09 20:05:44 +0000301 if (!Result->good()) {
302 std::cerr << "Error opening info-output-file '"
303 << LibSupportInfoOutputFilename << " for appending!\n";
304 delete Result;
305 return &std::cerr;
306 }
307 return Result;
308}
309
Chris Lattner6c38a792002-10-01 19:36:54 +0000310
311void TimerGroup::removeTimer() {
312 if (--NumTimers == 0 && !TimersToPrint.empty()) { // Print timing report...
313 // Sort the timers in descending order by amount of time taken...
314 std::sort(TimersToPrint.begin(), TimersToPrint.end(),
315 std::greater<Timer>());
316
317 // Figure out how many spaces to indent TimerGroup name...
318 unsigned Padding = (80-Name.length())/2;
319 if (Padding > 80) Padding = 0; // Don't allow "negative" numbers
320
Chris Lattnerf205fec2003-05-09 20:05:44 +0000321 std::ostream *OutStream = GetLibSupportInfoOutputFile();
322
Chris Lattner6c38a792002-10-01 19:36:54 +0000323 ++NumTimers;
324 { // Scope to contain Total timer... don't allow total timer to drop us to
325 // zero timers...
326 Timer Total("TOTAL");
327
328 for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i)
329 Total.sum(TimersToPrint[i]);
330
331 // Print out timing header...
Chris Lattnerf205fec2003-05-09 20:05:44 +0000332 *OutStream << "===" << std::string(73, '-') << "===\n"
333 << std::string(Padding, ' ') << Name << "\n"
334 << "===" << std::string(73, '-')
335 << "===\n Total Execution Time: ";
Chris Lattner8166b7c2003-02-13 16:25:28 +0000336
Chris Lattnerf205fec2003-05-09 20:05:44 +0000337 printAlignedFP(Total.getProcessTime(), 4, 5, *OutStream);
338 *OutStream << " seconds (";
339 printAlignedFP(Total.getWallTime(), 4, 5, *OutStream);
340 *OutStream << " wall clock)\n\n";
Chris Lattner6c38a792002-10-01 19:36:54 +0000341
342 if (Total.UserTime)
Chris Lattnerf205fec2003-05-09 20:05:44 +0000343 *OutStream << " ---User Time---";
Chris Lattner6c38a792002-10-01 19:36:54 +0000344 if (Total.SystemTime)
Chris Lattnerf205fec2003-05-09 20:05:44 +0000345 *OutStream << " --System Time--";
Chris Lattner6c38a792002-10-01 19:36:54 +0000346 if (Total.getProcessTime())
Chris Lattnerf205fec2003-05-09 20:05:44 +0000347 *OutStream << " --User+System--";
348 *OutStream << " ---Wall Time---";
Chris Lattner18eba912002-11-04 19:19:36 +0000349 if (Total.getMemUsed())
Chris Lattnerf205fec2003-05-09 20:05:44 +0000350 *OutStream << " ---Mem---";
Chris Lattner8f0d8242002-11-18 21:47:09 +0000351 if (Total.getPeakMem())
Chris Lattnerf205fec2003-05-09 20:05:44 +0000352 *OutStream << " -PeakMem-";
353 *OutStream << " --- Name ---\n";
Chris Lattner6c38a792002-10-01 19:36:54 +0000354
355 // Loop through all of the timing data, printing it out...
356 for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i)
Chris Lattnerf205fec2003-05-09 20:05:44 +0000357 TimersToPrint[i].print(Total, *OutStream);
Chris Lattner6c38a792002-10-01 19:36:54 +0000358
Chris Lattnerf205fec2003-05-09 20:05:44 +0000359 Total.print(Total, *OutStream);
360 *OutStream << std::endl; // Flush output
Chris Lattner6c38a792002-10-01 19:36:54 +0000361 }
362 --NumTimers;
363
364 TimersToPrint.clear();
Chris Lattnerf205fec2003-05-09 20:05:44 +0000365
366 if (OutStream != &std::cerr && OutStream != &std::cout)
367 delete OutStream; // Close the file...
Chris Lattner6c38a792002-10-01 19:36:54 +0000368 }
369
370 // Delete default timer group!
371 if (NumTimers == 0 && this == DefaultTimerGroup) {
372 delete DefaultTimerGroup;
373 DefaultTimerGroup = 0;
374 }
375}
Brian Gaeked0fde302003-11-11 22:41:34 +0000376