LLVM 20.0.0git
Timer.cpp
Go to the documentation of this file.
1//===-- Timer.cpp - Interval Timing Support -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file Interval Timing implementation.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/Support/Timer.h"
14
15#include "DebugOptions.h"
16
17#include "llvm/ADT/Statistic.h"
18#include "llvm/ADT/StringMap.h"
19#include "llvm/Config/config.h"
22#include "llvm/Support/Format.h"
24#include "llvm/Support/Mutex.h"
29#include <limits>
30#include <optional>
31
32#if HAVE_UNISTD_H
33#include <unistd.h>
34#endif
35
36#ifdef HAVE_PROC_PID_RUSAGE
37#include <libproc.h>
38#endif
39
40using namespace llvm;
41
42//===----------------------------------------------------------------------===//
43// Forward declarations for Managed Timer Globals getters.
44//
45// Globals have been placed at the end of the file to restrict direct
46// access. Use of getters also has the benefit of making it a bit more explicit
47// that a global is being used.
48//===----------------------------------------------------------------------===//
49namespace {
50class Name2PairMap;
51}
52
53static std::string &libSupportInfoOutputFilename();
54static bool trackSpace();
55static bool sortTimers();
56[[maybe_unused]]
60static Name2PairMap &namedGroupedTimers();
61
62//===----------------------------------------------------------------------===//
63//
64//===----------------------------------------------------------------------===//
65
66std::unique_ptr<raw_ostream> llvm::CreateInfoOutputFile() {
67 const std::string &OutputFilename = libSupportInfoOutputFilename();
68 if (OutputFilename.empty())
69 return std::make_unique<raw_fd_ostream>(2, false); // stderr.
70 if (OutputFilename == "-")
71 return std::make_unique<raw_fd_ostream>(1, false); // stdout.
72
73 // Append mode is used because the info output file is opened and closed
74 // each time -stats or -time-passes wants to print output to it. To
75 // compensate for this, the test-suite Makefiles have code to delete the
76 // info output file before running commands which write to it.
77 std::error_code EC;
78 auto Result = std::make_unique<raw_fd_ostream>(
80 if (!EC)
81 return Result;
82
83 errs() << "Error opening info-output-file '"
84 << OutputFilename << " for appending!\n";
85 return std::make_unique<raw_fd_ostream>(2, false); // stderr.
86}
87
88//===----------------------------------------------------------------------===//
89// Timer Implementation
90//===----------------------------------------------------------------------===//
91
92void Timer::init(StringRef TimerName, StringRef TimerDescription) {
93 init(TimerName, TimerDescription, defaultTimerGroup());
94}
95
96void Timer::init(StringRef TimerName, StringRef TimerDescription,
97 TimerGroup &tg) {
98 assert(!TG && "Timer already initialized");
99 Name.assign(TimerName.begin(), TimerName.end());
100 Description.assign(TimerDescription.begin(), TimerDescription.end());
101 Running = Triggered = false;
102 TG = &tg;
103 TG->addTimer(*this);
104}
105
107 if (!TG) return; // Never initialized, or already cleared.
108 TG->removeTimer(*this);
109}
110
111static inline size_t getMemUsage() {
112 if (!trackSpace())
113 return 0;
115}
116
118#if defined(HAVE_UNISTD_H) && defined(HAVE_PROC_PID_RUSAGE) && \
119 defined(RUSAGE_INFO_V4)
120 struct rusage_info_v4 ru;
121 if (proc_pid_rusage(getpid(), RUSAGE_INFO_V4, (rusage_info_t *)&ru) == 0) {
122 return ru.ri_instructions;
123 }
124#endif
125 return 0;
126}
127
129 using Seconds = std::chrono::duration<double, std::ratio<1>>;
130 TimeRecord Result;
132 std::chrono::nanoseconds user, sys;
133
134 if (Start) {
135 Result.MemUsed = getMemUsage();
136 Result.InstructionsExecuted = getCurInstructionsExecuted();
138 } else {
140 Result.InstructionsExecuted = getCurInstructionsExecuted();
141 Result.MemUsed = getMemUsage();
142 }
143
144 Result.WallTime = Seconds(now.time_since_epoch()).count();
145 Result.UserTime = Seconds(user).count();
146 Result.SystemTime = Seconds(sys).count();
147 return Result;
148}
149
151 assert(!Running && "Cannot start a running timer");
152 Running = Triggered = true;
153#if LLVM_SUPPORT_XCODE_SIGNPOSTS
155#endif
156 StartTime = TimeRecord::getCurrentTime(true);
157}
158
160 assert(Running && "Cannot stop a paused timer");
161 Running = false;
162 Time += TimeRecord::getCurrentTime(false);
163 Time -= StartTime;
164#if LLVM_SUPPORT_XCODE_SIGNPOSTS
165 signposts().endInterval(this, getName());
166#endif
167}
168
170 Running = Triggered = false;
171 Time = StartTime = TimeRecord();
172}
173
175 stopTimer();
176 O.startTimer();
177}
178
179static void printVal(double Val, double Total, raw_ostream &OS) {
180 if (Total < 1e-7) // Avoid dividing by zero.
181 OS << " ----- ";
182 else
183 OS << format(" %7.4f (%5.1f%%)", Val, Val*100/Total);
184}
185
187 if (Total.getUserTime())
188 printVal(getUserTime(), Total.getUserTime(), OS);
189 if (Total.getSystemTime())
190 printVal(getSystemTime(), Total.getSystemTime(), OS);
191 if (Total.getProcessTime())
192 printVal(getProcessTime(), Total.getProcessTime(), OS);
193 printVal(getWallTime(), Total.getWallTime(), OS);
194
195 OS << " ";
196
197 if (Total.getMemUsed())
198 OS << format("%9" PRId64 " ", (int64_t)getMemUsed());
199 if (Total.getInstructionsExecuted())
200 OS << format("%9" PRId64 " ", (int64_t)getInstructionsExecuted());
201}
202
203
204//===----------------------------------------------------------------------===//
205// NamedRegionTimer Implementation
206//===----------------------------------------------------------------------===//
207
208namespace {
209
210typedef StringMap<Timer> Name2TimerMap;
211
212class Name2PairMap {
214public:
215 ~Name2PairMap() {
216 for (StringMap<std::pair<TimerGroup*, Name2TimerMap> >::iterator
217 I = Map.begin(), E = Map.end(); I != E; ++I)
218 delete I->second.first;
219 }
220
221 Timer &get(StringRef Name, StringRef Description, StringRef GroupName,
222 StringRef GroupDescription) {
224
225 std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName];
226
227 if (!GroupEntry.first)
228 GroupEntry.first = new TimerGroup(GroupName, GroupDescription);
229
230 Timer &T = GroupEntry.second[Name];
231 if (!T.isInitialized())
232 T.init(Name, Description, *GroupEntry.first);
233 return T;
234 }
235};
236
237}
238
240 StringRef GroupName,
241 StringRef GroupDescription, bool Enabled)
243 ? nullptr
244 : &namedGroupedTimers().get(Name, Description, GroupName,
245 GroupDescription)) {}
246
247//===----------------------------------------------------------------------===//
248// TimerGroup Implementation
249//===----------------------------------------------------------------------===//
250
251/// This is the global list of TimerGroups, maintained by the TimerGroup
252/// ctor/dtor and is protected by the timerLock lock.
253static TimerGroup *TimerGroupList = nullptr;
254
255TimerGroup::TimerGroup(StringRef Name, StringRef Description,
257 : Name(Name.begin(), Name.end()),
258 Description(Description.begin(), Description.end()) {
259 // Add the group to TimerGroupList.
261 if (TimerGroupList)
262 TimerGroupList->Prev = &Next;
263 Next = TimerGroupList;
264 Prev = &TimerGroupList;
265 TimerGroupList = this;
266}
267
268TimerGroup::TimerGroup(StringRef Name, StringRef Description)
269 : TimerGroup(Name, Description, timerLock()) {}
270
271TimerGroup::TimerGroup(StringRef Name, StringRef Description,
272 const StringMap<TimeRecord> &Records)
273 : TimerGroup(Name, Description) {
274 TimersToPrint.reserve(Records.size());
275 for (const auto &P : Records)
276 TimersToPrint.emplace_back(P.getValue(), std::string(P.getKey()),
277 std::string(P.getKey()));
278 assert(TimersToPrint.size() == Records.size() && "Size mismatch");
279}
280
282 // If the timer group is destroyed before the timers it owns, accumulate and
283 // print the timing data.
284 while (FirstTimer)
285 removeTimer(*FirstTimer);
286
287 // Remove the group from the TimerGroupList.
289 *Prev = Next;
290 if (Next)
291 Next->Prev = Prev;
292}
293
294
295void TimerGroup::removeTimer(Timer &T) {
297
298 // If the timer was started, move its data to TimersToPrint.
299 if (T.hasTriggered())
300 TimersToPrint.emplace_back(T.Time, T.Name, T.Description);
301
302 T.TG = nullptr;
303
304 // Unlink the timer from our list.
305 *T.Prev = T.Next;
306 if (T.Next)
307 T.Next->Prev = T.Prev;
308
309 // Print the report when all timers in this group are destroyed if some of
310 // them were started.
311 if (FirstTimer || TimersToPrint.empty())
312 return;
313
314 std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
315 PrintQueuedTimers(*OutStream);
316}
317
318void TimerGroup::addTimer(Timer &T) {
320
321 // Add the timer to our list.
322 if (FirstTimer)
323 FirstTimer->Prev = &T.Next;
324 T.Next = FirstTimer;
325 T.Prev = &FirstTimer;
326 FirstTimer = &T;
327}
328
329void TimerGroup::PrintQueuedTimers(raw_ostream &OS) {
330 // Perhaps sort the timers in descending order by amount of time taken.
331 if (sortTimers())
332 llvm::sort(TimersToPrint);
333
335 for (const PrintRecord &Record : TimersToPrint)
336 Total += Record.Time;
337
338 // Print out timing header.
339 OS << "===" << std::string(73, '-') << "===\n";
340 // Figure out how many spaces to indent TimerGroup name.
341 unsigned Padding = (80-Description.length())/2;
342 if (Padding > 80) Padding = 0; // Don't allow "negative" numbers
343 OS.indent(Padding) << Description << '\n';
344 OS << "===" << std::string(73, '-') << "===\n";
345
346 // If this is not an collection of ungrouped times, print the total time.
347 // Ungrouped timers don't really make sense to add up. We still print the
348 // TOTAL line to make the percentages make sense.
349 if (this != &defaultTimerGroup())
350 OS << format(" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
351 Total.getProcessTime(), Total.getWallTime());
352 OS << '\n';
353
354 if (Total.getUserTime())
355 OS << " ---User Time---";
356 if (Total.getSystemTime())
357 OS << " --System Time--";
358 if (Total.getProcessTime())
359 OS << " --User+System--";
360 OS << " ---Wall Time---";
361 if (Total.getMemUsed())
362 OS << " ---Mem---";
363 if (Total.getInstructionsExecuted())
364 OS << " ---Instr---";
365 OS << " --- Name ---\n";
366
367 // Loop through all of the timing data, printing it out.
368 for (const PrintRecord &Record : llvm::reverse(TimersToPrint)) {
369 Record.Time.print(Total, OS);
370 OS << Record.Description << '\n';
371 }
372
373 Total.print(Total, OS);
374 OS << "Total\n\n";
375 OS.flush();
376
377 TimersToPrint.clear();
378}
379
380void TimerGroup::prepareToPrintList(bool ResetTime) {
381 // See if any of our timers were started, if so add them to TimersToPrint.
382 for (Timer *T = FirstTimer; T; T = T->Next) {
383 if (!T->hasTriggered()) continue;
384 bool WasRunning = T->isRunning();
385 if (WasRunning)
386 T->stopTimer();
387
388 TimersToPrint.emplace_back(T->Time, T->Name, T->Description);
389
390 if (ResetTime)
391 T->clear();
392
393 if (WasRunning)
394 T->startTimer();
395 }
396}
397
398void TimerGroup::print(raw_ostream &OS, bool ResetAfterPrint) {
399 {
400 // After preparing the timers we can free the lock
402 prepareToPrintList(ResetAfterPrint);
403 }
404
405 // If any timers were started, print the group.
406 if (!TimersToPrint.empty())
407 PrintQueuedTimers(OS);
408}
409
412 for (Timer *T = FirstTimer; T; T = T->Next)
413 T->clear();
414}
415
418
419 for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
420 TG->print(OS);
421}
422
425 for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
426 TG->clear();
427}
428
429void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
430 const char *suffix, double Value) {
431 assert(yaml::needsQuotes(Name) == yaml::QuotingType::None &&
432 "TimerGroup name should not need quotes");
433 assert(yaml::needsQuotes(R.Name) == yaml::QuotingType::None &&
434 "Timer name should not need quotes");
435 constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10;
436 OS << "\t\"time." << Name << '.' << R.Name << suffix
437 << "\": " << format("%.*e", max_digits10 - 1, Value);
438}
439
440const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
442
443 prepareToPrintList(false);
444 for (const PrintRecord &R : TimersToPrint) {
445 OS << delim;
446 delim = ",\n";
447
448 const TimeRecord &T = R.Time;
449 printJSONValue(OS, R, ".wall", T.getWallTime());
450 OS << delim;
451 printJSONValue(OS, R, ".user", T.getUserTime());
452 OS << delim;
453 printJSONValue(OS, R, ".sys", T.getSystemTime());
454 if (T.getMemUsed()) {
455 OS << delim;
456 printJSONValue(OS, R, ".mem", T.getMemUsed());
457 }
458 if (T.getInstructionsExecuted()) {
459 OS << delim;
460 printJSONValue(OS, R, ".instr", T.getInstructionsExecuted());
461 }
462 }
463 TimersToPrint.clear();
464 return delim;
465}
466
467const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
469 for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
470 delim = TG->printJSONValues(OS, delim);
471 return delim;
472}
473
474//===----------------------------------------------------------------------===//
475// Timer Globals
476//
477// Previously, these were independent ManagedStatics. This led to bugs because
478// there are dependencies between the globals, but no reliable mechanism to
479// control relative lifetimes.
480//
481// Placing the globals within one class instance lets us control the lifetimes
482// of the various data members and ensure that no global uses another that has
483// been deleted.
484//
485// Globals fall into two categories. First are simple data types and
486// command-line options. These are cheap to construct and/or required early
487// during launch. They are created when the ManagedTimerGlobals singleton is
488// constructed. Second are types that are more expensive to construct or not
489// needed until later during compilation. These are lazily constructed in order
490// to reduce launch time.
491//===----------------------------------------------------------------------===//
493public:
496 "info-output-file", cl::value_desc("filename"),
497 cl::desc("File to append -stats and -timer output to"), cl::Hidden,
500 "track-memory",
501 cl::desc("Enable -time-passes memory tracking (this may be slow)"),
502 cl::Hidden};
504 "sort-timers",
505 cl::desc("In the report, sort the timers in each group in wall clock"
506 " time order"),
507 cl::init(true), cl::Hidden};
508
510 TimerGroup DefaultTimerGroup{"misc", "Miscellaneous Ungrouped Timers",
511 TimerLock};
513
514 // Order of these members and initialization below is important. For example
515 // the defaultTimerGroup uses the timerLock. Most of these also depend on the
516 // options above.
517 std::once_flag InitDeferredFlag;
518 std::optional<Name2PairMap> NamedGroupedTimersPtr;
519
521 std::call_once(InitDeferredFlag,
522 [this]() { NamedGroupedTimersPtr.emplace(); });
523 return *this;
524 }
525};
526
528
529static std::string &libSupportInfoOutputFilename() {
530 return ManagedTimerGlobals->LibSupportInfoOutputFilename;
531}
532static bool trackSpace() { return ManagedTimerGlobals->TrackSpace; }
533static bool sortTimers() { return ManagedTimerGlobals->SortTimers; }
534static SignpostEmitter &signposts() { return ManagedTimerGlobals->Signposts; }
536 return ManagedTimerGlobals->TimerLock;
537}
539 return ManagedTimerGlobals->DefaultTimerGroup;
540}
541static Name2PairMap &namedGroupedTimers() {
542 return *ManagedTimerGlobals->initDeferred().NamedGroupedTimersPtr;
543}
544
547 ManagedTimerGlobals->initDeferred();
548}
549
This file defines the StringMap class.
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::string Name
#define I(x, y, z)
Definition: MD5.cpp:58
static cl::opt< std::string > OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"), cl::init("-"))
#define T
#define P(N)
Provides a library for accessing information about this process and other processes on the operating ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
static bool Enabled
Definition: Statistic.cpp:46
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
static sys::SmartMutex< true > & timerLock()
Definition: Timer.cpp:535
static ManagedStatic< TimerGlobals > ManagedTimerGlobals
Definition: Timer.cpp:527
static TimerGroup & defaultTimerGroup()
Definition: Timer.cpp:538
static std::string & libSupportInfoOutputFilename()
Definition: Timer.cpp:529
static bool trackSpace()
Definition: Timer.cpp:532
static SignpostEmitter & signposts()
Definition: Timer.cpp:534
static bool sortTimers()
Definition: Timer.cpp:533
static size_t getMemUsage()
Definition: Timer.cpp:111
static void printVal(double Val, double Total, raw_ostream &OS)
Definition: Timer.cpp:179
static TimerGroup * TimerGroupList
This is the global list of TimerGroups, maintained by the TimerGroup ctor/dtor and is protected by th...
Definition: Timer.cpp:253
static uint64_t getCurInstructionsExecuted()
Definition: Timer.cpp:117
static Name2PairMap & namedGroupedTimers()
Definition: Timer.cpp:541
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
Definition: ManagedStatic.h:83
Manages the emission of signposts into the recording method supported by the OS.
Definition: Signposts.h:27
void endInterval(const void *O, StringRef Name)
End a signposted interval for a given object.
Definition: Signposts.cpp:127
void startInterval(const void *O, StringRef Name)
Begin a signposted interval for a given object.
Definition: Signposts.cpp:119
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:128
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
iterator begin() const
Definition: StringRef.h:116
iterator end() const
Definition: StringRef.h:118
double getUserTime() const
Definition: Timer.h:43
double getProcessTime() const
Definition: Timer.h:42
static TimeRecord getCurrentTime(bool Start=true)
Get the current time and memory usage.
Definition: Timer.cpp:128
double getWallTime() const
Definition: Timer.h:45
ssize_t getMemUsed() const
Definition: Timer.h:46
double getSystemTime() const
Definition: Timer.h:44
void print(const TimeRecord &Total, raw_ostream &OS) const
Print the current time record to OS, with a breakdown showing contributions to the Total time record.
Definition: Timer.cpp:186
uint64_t getInstructionsExecuted() const
Definition: Timer.h:47
The TimeRegion class is used as a helper class to call the startTimer() and stopTimer() methods of th...
Definition: Timer.h:148
cl::opt< std::string, true > InfoOutputFilename
Definition: Timer.cpp:495
cl::opt< bool > SortTimers
Definition: Timer.cpp:503
sys::SmartMutex< true > TimerLock
Definition: Timer.cpp:509
TimerGlobals & initDeferred()
Definition: Timer.cpp:520
std::string LibSupportInfoOutputFilename
Definition: Timer.cpp:494
TimerGroup DefaultTimerGroup
Definition: Timer.cpp:510
cl::opt< bool > TrackSpace
Definition: Timer.cpp:499
std::once_flag InitDeferredFlag
Definition: Timer.cpp:517
SignpostEmitter Signposts
Definition: Timer.cpp:512
std::optional< Name2PairMap > NamedGroupedTimersPtr
Definition: Timer.cpp:518
The TimerGroup class is used to group together related timers into a single report that is printed wh...
Definition: Timer.h:178
static void printAll(raw_ostream &OS)
This static method prints all timers.
Definition: Timer.cpp:416
void print(raw_ostream &OS, bool ResetAfterPrint=false)
Print any started timers in this group, optionally resetting timers after printing them.
Definition: Timer.cpp:398
static void clearAll()
Clear out all timers.
Definition: Timer.cpp:423
void clear()
Clear all timers in this group.
Definition: Timer.cpp:410
static void * acquireTimerGlobals()
This makes the timer globals unmanaged, and lets the user manage the lifetime.
Definition: Timer.cpp:550
static const char * printAllJSONValues(raw_ostream &OS, const char *delim)
Prints all timers as JSON key/value pairs.
Definition: Timer.cpp:467
const char * printJSONValues(raw_ostream &OS, const char *delim)
Definition: Timer.cpp:440
static void constructForStatistics()
Ensure global objects required for statistics printing are initialized.
Definition: Timer.cpp:546
This class is used to track the amount of time spent between invocations of its startTimer()/stopTime...
Definition: Timer.h:81
void yieldTo(Timer &)
Stop the timer and start another timer.
Definition: Timer.cpp:174
void stopTimer()
Stop the timer.
Definition: Timer.cpp:159
void init(StringRef TimerName, StringRef TimerDescription)
Definition: Timer.cpp:92
void clear()
Clear the timer state.
Definition: Timer.cpp:169
const std::string & getName() const
Definition: Timer.h:113
void startTimer()
Start the timer running.
Definition: Timer.cpp:150
LLVM Value Representation.
Definition: Value.h:74
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
static void GetTimeUsage(TimePoint<> &elapsed, std::chrono::nanoseconds &user_time, std::chrono::nanoseconds &sys_time)
This static function will set user_time to the amount of CPU time spent in user (non-kernel) mode and...
static size_t GetMallocUsage()
Return process memory usage.
SmartMutex - A mutex with a compile time constant parameter that indicates whether this mutex should ...
Definition: Mutex.h:28
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:443
LocationClass< Ty > location(Ty &L)
Definition: CommandLine.h:463
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
Definition: FileSystem.h:767
@ OF_Append
The file should be opened in append mode.
Definition: FileSystem.h:770
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
Definition: Chrono.h:34
std::lock_guard< SmartMutex< mt_only > > SmartScopedLock
Definition: Mutex.h:69
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::unique_ptr< raw_ostream > CreateInfoOutputFile()
Return a stream to print our output on.
Definition: Timer.cpp:66
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1664
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
void initTimerOptions()
Definition: Timer.cpp:545
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
NamedRegionTimer(StringRef Name, StringRef Description, StringRef GroupName, StringRef GroupDescription, bool Enabled=true)
Definition: Timer.cpp:239