1//===-- Timer.cpp - Interval Timing Support -------------------------------===//
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
7//===----------------------------------------------------------------------===//
9/// \file Interval Timing implementation.
11//===----------------------------------------------------------------------===//
19#include "llvm/Config/config.h"
35#ifdef HAVE_PROC_PID_RUSAGE
41//===----------------------------------------------------------------------===//
42// Forward declarations for Managed Timer Globals getters.
44// Globals have been placed at the end of the file to restrict direct
45// access. Use of getters also has the benefit of making it a bit more explicit
46// that a global is being used.
47//===----------------------------------------------------------------------===//
62//===----------------------------------------------------------------------===//
64//===----------------------------------------------------------------------===//
69 return std::make_unique<raw_fd_ostream>(2,
false);
// stderr.
71 return std::make_unique<raw_fd_ostream>(1,
false);
// stdout.
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.
78 auto Result = std::make_unique<raw_fd_ostream>(
83 errs() <<
"Error opening info-output-file '"
85 return std::make_unique<raw_fd_ostream>(2,
false);
// stderr.
88//===----------------------------------------------------------------------===//
89// Timer Implementation
90//===----------------------------------------------------------------------===//
98 assert(!TG &&
"Timer already initialized");
99 Name.assign(TimerName.
begin(), TimerName.
end());
100 Description.assign(TimerDescription.
begin(), TimerDescription.
end());
101 Running = Triggered =
false;
107 if (!TG)
return;
// Never initialized, or already cleared.
108 TG->removeTimer(*
this);
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;
129 using Seconds = std::chrono::duration<double, std::ratio<1>>;
132 std::chrono::nanoseconds user,
sys;
144 Result.WallTime = Seconds(
now.time_since_epoch()).count();
145 Result.UserTime = Seconds(user).count();
146 Result.SystemTime = Seconds(
sys).count();
151 assert(!Running &&
"Cannot start a running timer");
152 Running = Triggered =
true;
153#if LLVM_SUPPORT_XCODE_SIGNPOSTS
160 assert(Running &&
"Cannot stop a paused timer");
164#if LLVM_SUPPORT_XCODE_SIGNPOSTS
170 Running = Triggered =
false;
180 if (
Total < 1e-7)
// Avoid dividing by zero.
183 OS <<
format(
" %7.4f (%5.1f%%)", Val, Val*100/
Total);
187 if (
Total.getUserTime())
189 if (
Total.getSystemTime())
191 if (
Total.getProcessTime())
197 if (
Total.getMemUsed())
199 if (
Total.getInstructionsExecuted())
204//===----------------------------------------------------------------------===//
205// NamedRegionTimer Implementation
206//===----------------------------------------------------------------------===//
217 I = Map.begin(), E = Map.end();
I != E; ++
I)
218 delete I->second.first;
225 std::pair<TimerGroup *, Name2TimerMap> &GroupEntry =
226 getGroupEntry(GroupName, GroupDescription);
227 Timer &
T = GroupEntry.second[Name];
228 if (!
T.isInitialized())
229 T.init(Name, Description, *GroupEntry.first);
233 TimerGroup &getTimerGroup(StringRef GroupName, StringRef GroupDescription) {
235 return *getGroupEntry(GroupName, GroupDescription).first;
239 std::pair<TimerGroup *, Name2TimerMap> &
240 getGroupEntry(StringRef GroupName, StringRef GroupDescription) {
241 std::pair<TimerGroup *, Name2TimerMap> &GroupEntry =
Map[GroupName];
242 if (!GroupEntry.first)
244 new TimerGroup(GroupName, GroupDescription,
/*PrintOnExit=*/true);
258 GroupDescription)) {}
265//===----------------------------------------------------------------------===//
266// TimerGroup Implementation
267//===----------------------------------------------------------------------===//
269/// This is the global list of TimerGroups, maintained by the TimerGroup
270/// ctor/dtor and is protected by the timerLock lock.
275 : Name(Name.begin(), Name.end()),
276 Description(Description.begin(), Description.end()),
278 // Add the group to TimerGroupList.
288 : TimerGroup(Name, Description,
timerLock(), PrintOnExit) {}
292 : TimerGroup(Name, Description, PrintOnExit) {
293 TimersToPrint.reserve(Records.
size());
294 for (
const auto &
P : Records)
295 TimersToPrint.emplace_back(
P.getValue(), std::string(
P.getKey()),
296 std::string(
P.getKey()));
297 assert(TimersToPrint.size() == Records.
size() &&
"Size mismatch");
301 // If the timer group is destroyed before the timers it owns, accumulate and
302 // print the timing data.
304 removeTimer(*FirstTimer);
306 if (!TimersToPrint.empty() && PrintOnExit) {
308 PrintQueuedTimers(*OutStream);
311 auto unlink = [&]() {
317 // TimerGlobals is always created implicity, through a call to timerLock(),
318 // when a TimeGroup is created. On CRT shutdown, the TimerGlobals instance
319 // might have been destroyed already. Avoid re-creating it if calling
326 // Remove the group from the TimerGroupList.
331void TimerGroup::removeTimer(
Timer &
T) {
334 // If the timer was started, move its data to TimersToPrint.
335 if (
T.hasTriggered())
336 TimersToPrint.emplace_back(
T.Time,
T.Name,
T.Description);
340 // Unlink the timer from our list.
343 T.Next->Prev =
T.Prev;
346void TimerGroup::addTimer(
Timer &
T) {
349 // Add the timer to our list.
351 FirstTimer->Prev = &
T.Next;
353 T.Prev = &FirstTimer;
357void TimerGroup::PrintQueuedTimers(
raw_ostream &OS) {
358 // Perhaps sort the timers in descending order by amount of time taken.
363 for (
const PrintRecord &Record : TimersToPrint)
364 Total += Record.Time;
366 // Print out timing header.
367 OS <<
"===" << std::string(73,
'-') <<
"===\n";
368 // Figure out how many spaces to indent TimerGroup name.
369 unsigned Padding = (80-Description.length())/2;
370 if (Padding > 80)
Padding = 0;
// Don't allow "negative" numbers
371 OS.
indent(Padding) << Description <<
'\n';
372 OS <<
"===" << std::string(73,
'-') <<
"===\n";
374 // If this is not an collection of ungrouped times, print the total time.
375 // Ungrouped timers don't really make sense to add up. We still print the
376 // TOTAL line to make the percentages make sense.
378 OS <<
format(
" Total Execution Time: %5.4f seconds (%5.4f wall clock)\n",
382 if (
Total.getUserTime())
383 OS <<
" ---User Time---";
384 if (
Total.getSystemTime())
385 OS <<
" --System Time--";
386 if (
Total.getProcessTime())
387 OS <<
" --User+System--";
388 OS <<
" ---Wall Time---";
389 if (
Total.getMemUsed())
391 if (
Total.getInstructionsExecuted())
392 OS <<
" ---Instr---";
393 OS <<
" --- Name ---\n";
395 // Loop through all of the timing data, printing it out.
396 for (
const PrintRecord &Record :
llvm::reverse(TimersToPrint)) {
397 Record.Time.print(
Total, OS);
398 OS << Record.Description <<
'\n';
405 TimersToPrint.clear();
408void TimerGroup::prepareToPrintList(
bool ResetTime) {
409 // See if any of our timers were started, if so add them to TimersToPrint.
410 for (
Timer *
T = FirstTimer;
T;
T =
T->Next) {
411 if (!
T->hasTriggered())
continue;
412 bool WasRunning =
T->isRunning();
416 TimersToPrint.emplace_back(
T->Time,
T->Name,
T->Description);
428 // After preparing the timers we can free the lock
430 prepareToPrintList(ResetAfterPrint);
433 // If any timers were started, print the group.
434 if (!TimersToPrint.empty())
435 PrintQueuedTimers(OS);
440 for (
Timer *
T = FirstTimer;
T;
T =
T->Next)
457void TimerGroup::printJSONValue(
raw_ostream &OS,
const PrintRecord &R,
458 const char *suffix,
double Value) {
459 constexpr auto max_digits10 = std::numeric_limits<double>::max_digits10;
460 OS <<
"\t\"time." << Name <<
'.' << R.Name << suffix
461 <<
"\": " <<
format(
"%.*e", max_digits10 - 1,
Value);
467 prepareToPrintList(
false);
468 for (
const PrintRecord &R : TimersToPrint) {
473 printJSONValue(OS, R,
".wall",
T.getWallTime());
475 printJSONValue(OS, R,
".user",
T.getUserTime());
477 printJSONValue(OS, R,
".sys",
T.getSystemTime());
478 if (
T.getMemUsed()) {
480 printJSONValue(OS, R,
".mem",
T.getMemUsed());
482 if (
T.getInstructionsExecuted()) {
484 printJSONValue(OS, R,
".instr",
T.getInstructionsExecuted());
487 TimersToPrint.clear();
494 delim = TG->printJSONValues(OS, delim);
498//===----------------------------------------------------------------------===//
501// Previously, these were independent ManagedStatics. This led to bugs because
502// there are dependencies between the globals, but no reliable mechanism to
503// control relative lifetimes.
505// Placing the globals within one class instance lets us control the lifetimes
506// of the various data members and ensure that no global uses another that has
509// Globals fall into two categories. First are simple data types and
510// command-line options. These are cheap to construct and/or required early
511// during launch. They are created when the ManagedTimerGlobals singleton is
512// constructed. Second are types that are more expensive to construct or not
513// needed until later during compilation. These are lazily constructed in order
514// to reduce launch time.
515//===----------------------------------------------------------------------===//
525 cl::desc(
"Enable -time-passes memory tracking (this may be slow)"),
529 cl::desc(
"In the report, sort the timers in each group in wall clock"
538 // Order of these members and initialization below is important. For example
539 // the defaultTimerGroup uses the timerLock. Most of these also depend on the
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the StringMap class.
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
static cl::opt< std::string > OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"), cl::init("-"))
Provides a library for accessing information about this process and other processes on the operating ...
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
static sys::SmartMutex< true > & timerLock()
static ManagedStatic< TimerGlobals > ManagedTimerGlobals
static TimerGroup & defaultTimerGroup()
static bool isTimerGlobalsConstructed()
static std::string & libSupportInfoOutputFilename()
static SignpostEmitter & signposts()
static size_t getMemUsage()
static void printVal(double Val, double Total, raw_ostream &OS)
static TimerGroup * TimerGroupList
This is the global list of TimerGroups, maintained by the TimerGroup ctor/dtor and is protected by th...
static uint64_t getCurInstructionsExecuted()
static Name2PairMap & namedGroupedTimers()
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
Manages the emission of signposts into the recording method supported by the OS.
LLVM_ABI void endInterval(const void *O, StringRef Name)
End a signposted interval for a given object.
LLVM_ABI void startInterval(const void *O, StringRef Name)
Begin a signposted interval for a given object.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
StringRef - Represent a constant reference to a string, i.e.
double getUserTime() const
double getProcessTime() const
static LLVM_ABI TimeRecord getCurrentTime(bool Start=true)
Get the current time and memory usage.
double getWallTime() const
ssize_t getMemUsed() const
double getSystemTime() const
LLVM_ABI 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.
uint64_t getInstructionsExecuted() const
cl::opt< std::string, true > InfoOutputFilename
cl::opt< bool > SortTimers
sys::SmartMutex< true > TimerLock
TimerGlobals & initDeferred()
std::string LibSupportInfoOutputFilename
TimerGroup DefaultTimerGroup
cl::opt< bool > TrackSpace
std::once_flag InitDeferredFlag
SignpostEmitter Signposts
std::optional< Name2PairMap > NamedGroupedTimersPtr
The TimerGroup class is used to group together related timers into a single report that is printed wh...
static LLVM_ABI void printAll(raw_ostream &OS)
This static method prints all timers.
LLVM_ABI void print(raw_ostream &OS, bool ResetAfterPrint=false)
Print any started timers in this group, optionally resetting timers after printing them.
static LLVM_ABI void clearAll()
Clear out all timers.
LLVM_ABI void clear()
Clear all timers in this group.
static LLVM_ABI void * acquireTimerGlobals()
This makes the timer globals unmanaged, and lets the user manage the lifetime.
static LLVM_ABI const char * printAllJSONValues(raw_ostream &OS, const char *delim)
Prints all timers as JSON key/value pairs.
LLVM_ABI const char * printJSONValues(raw_ostream &OS, const char *delim)
static LLVM_ABI void constructForStatistics()
Ensure global objects required for statistics printing are initialized.
This class is used to track the amount of time spent between invocations of its startTimer()/stopTime...
LLVM_ABI void yieldTo(Timer &)
Stop the timer and start another timer.
LLVM_ABI void stopTimer()
Stop the timer.
LLVM_ABI void init(StringRef TimerName, StringRef TimerDescription)
LLVM_ABI void clear()
Clear the timer state.
const std::string & getName() const
Timer(StringRef TimerName, StringRef TimerDescription)
LLVM_ABI void startTimer()
Start the timer running.
LLVM Value Representation.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
static LLVM_ABI 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 LLVM_ABI size_t GetMallocUsage()
Return process memory usage.
SmartMutex - A mutex with a compile time constant parameter that indicates whether this mutex should ...
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
@ OF_Append
The file should be opened in append mode.
std::lock_guard< SmartMutex< mt_only > > SmartScopedLock
std::chrono::time_point< std::chrono::system_clock, D > TimePoint
A time point on the system clock.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::unique_ptr< raw_ostream > CreateInfoOutputFile()
Return a stream to print our output on.
auto reverse(ContainerTy &&C)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
FunctionAddr VTableAddr Next
LLVM_ABI NamedRegionTimer(StringRef Name, StringRef Description, StringRef GroupName, StringRef GroupDescription, bool Enabled=true)
static LLVM_ABI TimerGroup & getNamedTimerGroup(StringRef GroupName, StringRef GroupDescription)