MLIR  22.0.0git
Timing.cpp
Go to the documentation of this file.
1 //===- Timing.cpp - Execution time measurement facilities -----------------===//
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 // Facilities to measure and provide statistics on execution time.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "mlir/Support/Timing.h"
15 #include "llvm/ADT/MapVector.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/ADT/StringMap.h"
18 #include "llvm/ADT/StringSet.h"
19 #include "llvm/Support/Allocator.h"
20 #include "llvm/Support/CommandLine.h"
21 #include "llvm/Support/Format.h"
22 #include "llvm/Support/ManagedStatic.h"
23 #include "llvm/Support/RWMutex.h"
24 #include "llvm/Support/Threading.h"
25 #include "llvm/Support/raw_ostream.h"
26 
27 #include <chrono>
28 #include <optional>
29 
30 using namespace mlir;
31 using namespace detail;
34 
35 constexpr llvm::StringLiteral kTimingDescription =
36  "... Execution time report ...";
37 
38 //===----------------------------------------------------------------------===//
39 // TimingManager
40 //===----------------------------------------------------------------------===//
41 
42 namespace mlir {
43 namespace detail {
44 /// Private implementation details of the `TimingManager`.
46 public:
47  // Identifier allocator, map, and mutex for thread safety.
48  llvm::BumpPtrAllocator identifierAllocator;
50  llvm::sys::SmartRWMutex<true> identifierMutex;
51 
52  /// A thread local cache of identifiers to reduce lock contention.
55 
56  TimingManagerImpl() : identifiers(identifierAllocator) {}
57 };
58 } // namespace detail
59 } // namespace mlir
60 
62 
64 
65 /// Get the root timer of this timing manager.
67  auto rt = rootTimer();
68  return rt ? Timer(*this, *rt) : Timer();
69 }
70 
71 /// Get the root timer of this timing manager wrapped in a `TimingScope`.
73  return TimingScope(getRootTimer());
74 }
75 
76 //===----------------------------------------------------------------------===//
77 // Identifier uniquing
78 //===----------------------------------------------------------------------===//
79 
80 /// Return an identifier for the specified string.
82  // Check for an existing instance in the local cache.
83  auto &impl = *tm.impl;
84  auto *&localEntry = (*impl.localIdentifierCache)[str];
85  if (localEntry)
86  return TimingIdentifier(localEntry);
87 
88  // Check for an existing identifier in read-only mode.
89  {
90  llvm::sys::SmartScopedReader<true> contextLock(impl.identifierMutex);
91  auto it = impl.identifiers.find(str);
92  if (it != impl.identifiers.end()) {
93  localEntry = &*it;
94  return TimingIdentifier(localEntry);
95  }
96  }
97 
98  // Acquire a writer-lock so that we can safely create the new instance.
99  llvm::sys::SmartScopedWriter<true> contextLock(impl.identifierMutex);
100  auto it = impl.identifiers.insert(str).first;
101  localEntry = &*it;
102  return TimingIdentifier(localEntry);
103 }
104 
105 //===----------------------------------------------------------------------===//
106 // Helpers for time record printing
107 //===----------------------------------------------------------------------===//
108 
109 namespace {
110 
111 class OutputTextStrategy : public OutputStrategy {
112 public:
113  OutputTextStrategy(raw_ostream &os) : OutputStrategy(os) {}
114 
115  void printHeader(const TimeRecord &total) override {
116  // Figure out how many spaces to description name.
117  unsigned padding = (80 - kTimingDescription.size()) / 2;
118  os << "===" << std::string(73, '-') << "===\n";
119  os.indent(padding) << kTimingDescription << '\n';
120  os << "===" << std::string(73, '-') << "===\n";
121 
122  // Print the total time followed by the section headers.
123  os << llvm::format(" Total Execution Time: %.4f seconds\n\n", total.wall);
124  if (total.user != total.wall)
125  os << " ----User Time----";
126  os << " ----Wall Time---- ----Name----\n";
127  }
128 
129  void printFooter() override { os.flush(); }
130 
131  void printTime(const TimeRecord &time, const TimeRecord &total) override {
132  if (total.user != total.wall) {
133  os << llvm::format(" %8.4f (%5.1f%%)", time.user,
134  100.0 * time.user / total.user);
135  }
136  os << llvm::format(" %8.4f (%5.1f%%) ", time.wall,
137  100.0 * time.wall / total.wall);
138  }
139 
140  void printListEntry(StringRef name, const TimeRecord &time,
141  const TimeRecord &total, bool lastEntry) override {
142  printTime(time, total);
143  os << name << "\n";
144  }
145 
146  void printTreeEntry(unsigned indent, StringRef name, const TimeRecord &time,
147  const TimeRecord &total) override {
148  printTime(time, total);
149  os.indent(indent) << name << "\n";
150  }
151 
152  void printTreeEntryEnd(unsigned indent, bool lastEntry) override {}
153 };
154 
155 class OutputJsonStrategy : public OutputStrategy {
156 public:
157  OutputJsonStrategy(raw_ostream &os) : OutputStrategy(os) {}
158 
159  void printHeader(const TimeRecord &total) override { os << "[" << "\n"; }
160 
161  void printFooter() override {
162  os << "]" << "\n";
163  os.flush();
164  }
165 
166  void printTime(const TimeRecord &time, const TimeRecord &total) override {
167  if (total.user != total.wall) {
168  os << "\"user\": {";
169  os << "\"duration\": " << llvm::format("%8.4f", time.user) << ", ";
170  os << "\"percentage\": "
171  << llvm::format("%5.1f", 100.0 * time.user / total.user);
172  os << "}, ";
173  }
174  os << "\"wall\": {";
175  os << "\"duration\": " << llvm::format("%8.4f", time.wall) << ", ";
176  os << "\"percentage\": "
177  << llvm::format("%5.1f", 100.0 * time.wall / total.wall);
178  os << "}";
179  }
180 
181  void printListEntry(StringRef name, const TimeRecord &time,
182  const TimeRecord &total, bool lastEntry) override {
183  os << "{";
184  printTime(time, total);
185  os << ", \"name\": " << "\"" << name << "\"";
186  os << "}";
187  if (!lastEntry)
188  os << ",";
189  os << "\n";
190  }
191 
192  void printTreeEntry(unsigned indent, StringRef name, const TimeRecord &time,
193  const TimeRecord &total) override {
194  os.indent(indent) << "{";
195  printTime(time, total);
196  os << ", \"name\": " << "\"" << name << "\"";
197  os << ", \"passes\": [" << "\n";
198  }
199 
200  void printTreeEntryEnd(unsigned indent, bool lastEntry) override {
201  os.indent(indent) << "{}]";
202  os << "}";
203  if (!lastEntry)
204  os << ",";
205  os << "\n";
206  }
207 };
208 
209 } // namespace
210 
211 //===----------------------------------------------------------------------===//
212 // Timer Implementation for DefaultTimingManager
213 //===----------------------------------------------------------------------===//
214 
215 namespace {
216 
217 /// A timer used to sample execution time.
218 ///
219 /// Separately tracks wall time and user time to account for parallel threads of
220 /// execution. Timers are intended to be started and stopped multiple times.
221 /// Each start and stop will add to the timer's wall and user time.
222 class TimerImpl {
223 public:
224  using ChildrenMap = llvm::MapVector<const void *, std::unique_ptr<TimerImpl>>;
225  using AsyncChildrenMap = llvm::DenseMap<uint64_t, ChildrenMap>;
226 
227  TimerImpl(std::string &&name, std::unique_ptr<OutputStrategy> &output)
228  : threadId(llvm::get_threadid()), name(name), output(output) {}
229 
230  /// Start the timer.
231  void start() { startTime = std::chrono::steady_clock::now(); }
232 
233  /// Stop the timer.
234  void stop() {
235  auto newTime = std::chrono::steady_clock::now() - startTime;
236  wallTime += newTime;
237  userTime += newTime;
238  }
239 
240  /// Create a child timer nested within this one. Multiple calls to this
241  /// function with the same unique identifier `id` will return the same child
242  /// timer.
243  ///
244  /// This function can be called from other threads, as long as this timer
245  /// outlives any uses of the child timer on the other thread.
246  TimerImpl *nest(const void *id, function_ref<std::string()> nameBuilder) {
247  auto tid = llvm::get_threadid();
248  if (tid == threadId)
249  return nestTail(children[id], nameBuilder);
250  std::unique_lock<std::mutex> lock(asyncMutex);
251  return nestTail(asyncChildren[tid][id], nameBuilder);
252  }
253 
254  /// Tail-called from `nest()`.
255  TimerImpl *nestTail(std::unique_ptr<TimerImpl> &child,
256  function_ref<std::string()> nameBuilder) {
257  if (!child)
258  child = std::make_unique<TimerImpl>(nameBuilder(), output);
259  return child.get();
260  }
261 
262  /// Finalize this timer and all its children.
263  ///
264  /// If this timer has async children, which happens if `nest()` was called
265  /// from another thread, this function merges the async childr timers into the
266  /// main list of child timers.
267  ///
268  /// Caution: Call this function only after all nested timers running on other
269  /// threads no longer need their timers!
270  void finalize() {
271  addAsyncUserTime();
272  mergeAsyncChildren();
273  }
274 
275  /// Add the user time of all async children to this timer's user time. This is
276  /// necessary since the user time already contains all regular child timers,
277  /// but not the asynchronous ones (by the nesting nature of the timers).
278  std::chrono::nanoseconds addAsyncUserTime() {
279  auto added = std::chrono::nanoseconds(0);
280  for (auto &child : children)
281  added += child.second->addAsyncUserTime();
282  for (auto &thread : asyncChildren) {
283  for (auto &child : thread.second) {
284  child.second->addAsyncUserTime();
285  added += child.second->userTime;
286  }
287  }
288  userTime += added;
289  return added;
290  }
291 
292  /// Ensure that this timer and recursively all its children have their async
293  /// children folded into the main map of children.
294  void mergeAsyncChildren() {
295  for (auto &child : children)
296  child.second->mergeAsyncChildren();
297  mergeChildren(std::move(asyncChildren));
298  assert(asyncChildren.empty());
299  }
300 
301  /// Merge multiple child timers into this timer.
302  ///
303  /// Children in `other` are added as children to this timer, or, if this timer
304  /// already contains a child with the corresponding unique identifier, are
305  /// merged into the existing child.
306  void mergeChildren(ChildrenMap &&other) {
307  if (children.empty()) {
308  children = std::move(other);
309  for (auto &child : children)
310  child.second->mergeAsyncChildren();
311  } else {
312  for (auto &child : other)
313  mergeChild(child.first, std::move(child.second));
314  other.clear();
315  }
316  }
317 
318  /// See above.
319  void mergeChildren(AsyncChildrenMap &&other) {
320  for (auto &thread : other) {
321  mergeChildren(std::move(thread.second));
322  assert(thread.second.empty());
323  }
324  other.clear();
325  }
326 
327  /// Merge a child timer into this timer for a given unique identifier.
328  ///
329  /// Moves all child and async child timers of `other` into this timer's child
330  /// for the given unique identifier.
331  void mergeChild(const void *id, std::unique_ptr<TimerImpl> &&other) {
332  auto &into = children[id];
333  if (!into) {
334  into = std::move(other);
335  into->mergeAsyncChildren();
336  } else {
337  into->wallTime = std::max(into->wallTime, other->wallTime);
338  into->userTime += other->userTime;
339  into->mergeChildren(std::move(other->children));
340  into->mergeChildren(std::move(other->asyncChildren));
341  other.reset();
342  }
343  }
344 
345  /// Dump a human-readable tree representation of the timer and its children.
346  /// This is useful for debugging the timing mechanisms and structure of the
347  /// timers.
348  void dump(raw_ostream &os, unsigned indent = 0, unsigned markThreadId = 0) {
349  auto time = getTimeRecord();
350  os << std::string(indent * 2, ' ') << name << " [" << threadId << "]"
351  << llvm::format(" %7.4f / %7.4f", time.user, time.wall);
352  if (threadId != markThreadId && markThreadId != 0)
353  os << " (*)";
354  os << "\n";
355  for (auto &child : children)
356  child.second->dump(os, indent + 1, threadId);
357  for (auto &thread : asyncChildren)
358  for (auto &child : thread.second)
359  child.second->dump(os, indent + 1, threadId);
360  }
361 
362  /// Returns the time for this timer in seconds.
363  TimeRecord getTimeRecord() {
364  return TimeRecord(
365  std::chrono::duration_cast<std::chrono::duration<double>>(wallTime)
366  .count(),
367  std::chrono::duration_cast<std::chrono::duration<double>>(userTime)
368  .count());
369  }
370 
371  /// Print the timing result in list mode.
372  void printAsList(TimeRecord total) {
373  // Flatten the leaf timers in the tree and merge them by name.
374  llvm::StringMap<TimeRecord> mergedTimers;
375  std::function<void(TimerImpl *)> addTimer = [&](TimerImpl *timer) {
376  mergedTimers[timer->name] += timer->getTimeRecord();
377  for (auto &children : timer->children)
378  addTimer(children.second.get());
379  };
380  addTimer(this);
381 
382  // Sort the timing information by wall time.
383  std::vector<std::pair<StringRef, TimeRecord>> timerNameAndTime;
384  for (auto &it : mergedTimers)
385  timerNameAndTime.emplace_back(it.first(), it.second);
386  llvm::array_pod_sort(timerNameAndTime.begin(), timerNameAndTime.end(),
387  [](const std::pair<StringRef, TimeRecord> *lhs,
388  const std::pair<StringRef, TimeRecord> *rhs) {
389  return llvm::array_pod_sort_comparator<double>(
390  &rhs->second.wall, &lhs->second.wall);
391  });
392 
393  // Print the timing information sequentially.
394  for (auto &timeData : timerNameAndTime)
395  output->printListEntry(timeData.first, timeData.second, total);
396  }
397 
398  /// Print the timing result in tree mode.
399  void printAsTree(TimeRecord total, unsigned indent = 0) {
400  unsigned childIndent = indent;
401  if (!hidden) {
402  output->printTreeEntry(indent, name, getTimeRecord(), total);
403  childIndent += 2;
404  }
405  for (auto &child : children) {
406  child.second->printAsTree(total, childIndent);
407  }
408  if (!hidden) {
409  output->printTreeEntryEnd(indent);
410  }
411  }
412 
413  /// Print the current timing information.
414  void print(DisplayMode displayMode) {
415  // Print the banner.
416  auto total = getTimeRecord();
417  output->printHeader(total);
418 
419  // Defer to a specialized printer for each display mode.
420  switch (displayMode) {
421  case DisplayMode::List:
422  printAsList(total);
423  break;
424  case DisplayMode::Tree:
425  printAsTree(total);
426  break;
427  }
428 
429  // Print the top-level time not accounted for by child timers, and the
430  // total.
431  auto rest = total;
432  for (auto &child : children)
433  rest -= child.second->getTimeRecord();
434  output->printListEntry("Rest", rest, total);
435  output->printListEntry("Total", total, total, /*lastEntry=*/true);
436  output->printFooter();
437  }
438 
439  /// The last time instant at which the timer was started.
440  std::chrono::time_point<std::chrono::steady_clock> startTime;
441 
442  /// Accumulated wall time. If multiple threads of execution are merged into
443  /// this timer, the wall time will hold the maximum wall time of each thread
444  /// of execution.
445  std::chrono::nanoseconds wallTime = std::chrono::nanoseconds(0);
446 
447  /// Accumulated user time. If multiple threads of execution are merged into
448  /// this timer, each thread's user time is added here.
449  std::chrono::nanoseconds userTime = std::chrono::nanoseconds(0);
450 
451  /// The thread on which this timer is running.
452  uint64_t threadId;
453 
454  /// A descriptive name for this timer.
455  std::string name;
456 
457  /// Whether to omit this timer from reports and directly show its children.
458  bool hidden = false;
459 
460  /// Child timers on the same thread the timer itself. We keep at most one
461  /// timer per unique identifier.
462  ChildrenMap children;
463 
464  /// Child timers on other threads. We keep at most one timer per unique
465  /// identifier.
466  AsyncChildrenMap asyncChildren;
467 
468  /// Mutex for the async children.
469  std::mutex asyncMutex;
470 
471  std::unique_ptr<OutputStrategy> &output;
472 };
473 
474 } // namespace
475 
476 //===----------------------------------------------------------------------===//
477 // DefaultTimingManager
478 //===----------------------------------------------------------------------===//
479 
480 namespace mlir {
481 namespace detail {
482 
483 /// Implementation details of the `DefaultTimingManager`.
485 public:
486  /// Whether we should do our work or not.
487  bool enabled = false;
488 
489  /// The configured display mode.
490  DisplayMode displayMode = DisplayMode::Tree;
491 
492  /// The root timer.
493  std::unique_ptr<TimerImpl> rootTimer;
494 };
495 
496 } // namespace detail
497 } // namespace mlir
498 
500  : impl(std::make_unique<DefaultTimingManagerImpl>()),
501  out(std::make_unique<OutputTextStrategy>(llvm::errs())) {
502  clear(); // initializes the root timer
503 }
504 
506 
507 /// Enable or disable execution time sampling.
508 void DefaultTimingManager::setEnabled(bool enabled) { impl->enabled = enabled; }
509 
510 /// Return whether execution time sampling is enabled.
511 bool DefaultTimingManager::isEnabled() const { return impl->enabled; }
512 
513 /// Change the display mode.
515  impl->displayMode = displayMode;
516 }
517 
518 /// Return the current display mode;
520  return impl->displayMode;
521 }
522 
523 /// Change the stream where the output will be printed to.
524 void DefaultTimingManager::setOutput(std::unique_ptr<OutputStrategy> output) {
525  out = std::move(output);
526 }
527 
528 /// Print and clear the timing results.
530  if (impl->enabled) {
531  impl->rootTimer->finalize();
532  impl->rootTimer->print(impl->displayMode);
533  }
534  clear();
535 }
536 
537 /// Clear the timing results.
539  impl->rootTimer = std::make_unique<TimerImpl>("root", out);
540  impl->rootTimer->hidden = true;
541 }
542 
543 /// Debug print the timer data structures to an output stream.
544 void DefaultTimingManager::dumpTimers(raw_ostream &os) {
545  impl->rootTimer->dump(os);
546 }
547 
548 /// Debug print the timers as a list.
549 void DefaultTimingManager::dumpAsList(raw_ostream &os) {
550  impl->rootTimer->finalize();
551  impl->rootTimer->print(DisplayMode::List);
552 }
553 
554 /// Debug print the timers as a tree.
555 void DefaultTimingManager::dumpAsTree(raw_ostream &os) {
556  impl->rootTimer->finalize();
557  impl->rootTimer->print(DisplayMode::Tree);
558 }
559 
560 std::optional<void *> DefaultTimingManager::rootTimer() {
561  if (impl->enabled)
562  return impl->rootTimer.get();
563  return std::nullopt;
564 }
565 
567  static_cast<TimerImpl *>(handle)->start();
568 }
569 
571  static_cast<TimerImpl *>(handle)->stop();
572 }
573 
574 void *DefaultTimingManager::nestTimer(void *handle, const void *id,
575  function_ref<std::string()> nameBuilder) {
576  return static_cast<TimerImpl *>(handle)->nest(id, nameBuilder);
577 }
578 
580  static_cast<TimerImpl *>(handle)->hidden = true;
581 }
582 
583 //===----------------------------------------------------------------------===//
584 // DefaultTimingManager Command Line Options
585 //===----------------------------------------------------------------------===//
586 
587 namespace {
588 struct DefaultTimingManagerOptions {
589  llvm::cl::opt<bool> timing{"mlir-timing",
590  llvm::cl::desc("Display execution times"),
591  llvm::cl::init(false)};
592  llvm::cl::opt<DisplayMode> displayMode{
593  "mlir-timing-display", llvm::cl::desc("Display method for timing data"),
594  llvm::cl::init(DisplayMode::Tree),
595  llvm::cl::values(
596  clEnumValN(DisplayMode::List, "list",
597  "display the results in a list sorted by total time"),
598  clEnumValN(DisplayMode::Tree, "tree",
599  "display the results ina with a nested tree view"))};
600  llvm::cl::opt<OutputFormat> outputFormat{
601  "mlir-output-format", llvm::cl::desc("Output format for timing data"),
602  llvm::cl::init(OutputFormat::Text),
603  llvm::cl::values(clEnumValN(OutputFormat::Text, "text",
604  "display the results in text format"),
605  clEnumValN(OutputFormat::Json, "json",
606  "display the results in JSON format"))};
607 };
608 } // namespace
609 
610 static llvm::ManagedStatic<DefaultTimingManagerOptions> options;
611 
613  // Make sure that the options struct has been constructed.
614  *options;
615 }
616 
618  if (!options.isConstructed())
619  return;
620  tm.setEnabled(options->timing);
621  tm.setDisplayMode(options->displayMode);
622 
623  std::unique_ptr<OutputStrategy> printer;
624  if (options->outputFormat == OutputFormat::Text)
625  printer = std::make_unique<OutputTextStrategy>(llvm::errs());
626  else if (options->outputFormat == OutputFormat::Json)
627  printer = std::make_unique<OutputJsonStrategy>(llvm::errs());
628  tm.setOutput(std::move(printer));
629 }
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static llvm::ManagedStatic< DefaultTimingManagerOptions > options
Definition: Timing.cpp:610
constexpr llvm::StringLiteral kTimingDescription
Definition: Timing.cpp:35
Facilities for time measurement and report printing to an output stream.
Definition: Timing.h:388
void setDisplayMode(DisplayMode displayMode)
Change the display mode.
Definition: Timing.cpp:514
void stopTimer(void *handle) override
Stop the timer with the given handle.
Definition: Timing.cpp:570
std::optional< void * > rootTimer() override
Return the root timer.
Definition: Timing.cpp:560
DisplayMode
The different display modes for printing the timers.
Definition: Timing.h:391
@ Tree
In this mode the results are displayed in a tree view, with child timers nested under their parents.
@ List
In this mode the results are displayed in a list sorted by total time, with timers aggregated into on...
void setOutput(std::unique_ptr< OutputStrategy > output)
Change the stream where the output will be printed to.
Definition: Timing.cpp:524
void dumpTimers(raw_ostream &os=llvm::errs())
Debug print the timer data structures to an output stream.
Definition: Timing.cpp:544
void * nestTimer(void *handle, const void *id, function_ref< std::string()> nameBuilder) override
Create a child timer nested within the one with the given handle.
Definition: Timing.cpp:574
void startTimer(void *handle) override
Start the timer with the given handle.
Definition: Timing.cpp:566
DisplayMode getDisplayMode() const
Return the current display mode;.
Definition: Timing.cpp:519
void dumpAsList(raw_ostream &os=llvm::errs())
Debug print the timers as a list.
Definition: Timing.cpp:549
void dumpAsTree(raw_ostream &os=llvm::errs())
Debug print the timers as a tree.
Definition: Timing.cpp:555
void clear()
Clear the timing results.
Definition: Timing.cpp:538
~DefaultTimingManager() override
Definition: Timing.cpp:505
void print()
Print and clear the timing results.
Definition: Timing.cpp:529
void setEnabled(bool enabled)
Enable or disable execution time sampling.
Definition: Timing.cpp:508
OutputFormat
The different output formats for printing the timers.
Definition: Timing.h:402
bool isEnabled() const
Return whether execution time sampling is enabled.
Definition: Timing.cpp:511
void hideTimer(void *handle) override
Hide the timer in timing reports and directly show its children.
Definition: Timing.cpp:579
Facilities for printing timing reports to various output formats.
Definition: Timing.h:351
This class provides support for defining a thread local object with non static storage duration.
A handle for a timer in a TimingManager.
Definition: Timing.h:186
This class represesents a uniqued string owned by a TimingManager.
Definition: Timing.h:46
std::string str() const
Return an std::string.
Definition: Timing.h:60
TimingIdentifier(const TimingIdentifier &)=default
static TimingIdentifier get(StringRef str, TimingManager &tm)
Return an identifier for the specified string.
Definition: Timing.cpp:81
This class represents facilities to measure execution time.
Definition: Timing.h:113
TimingScope getRootScope()
Get the root timer of this timing manager wrapped in a TimingScope for convenience.
Definition: Timing.cpp:72
friend class Timer
Definition: Timing.h:133
virtual ~TimingManager()
const std::unique_ptr< detail::TimingManagerImpl > impl
Definition: Timing.h:165
virtual std::optional< void * > rootTimer()=0
Return the root timer.
Timer getRootTimer()
Get the root timer of this timing manager.
Definition: Timing.cpp:66
An RAII-style wrapper around a timer that ensures the timer is properly started and stopped.
Definition: Timing.h:272
Implementation details of the DefaultTimingManager.
Definition: Timing.cpp:484
bool enabled
Whether we should do our work or not.
Definition: Timing.cpp:487
std::unique_ptr< TimerImpl > rootTimer
The root timer.
Definition: Timing.cpp:493
DisplayMode displayMode
The configured display mode.
Definition: Timing.cpp:490
Private implementation details of the TimingManager.
Definition: Timing.cpp:45
llvm::sys::SmartRWMutex< true > identifierMutex
Definition: Timing.cpp:50
ThreadLocalCache< llvm::StringMap< llvm::StringMapEntry< std::nullopt_t > * > > localIdentifierCache
A thread local cache of identifiers to reduce lock contention.
Definition: Timing.cpp:54
llvm::StringSet< llvm::BumpPtrAllocator & > identifiers
Definition: Timing.cpp:49
llvm::BumpPtrAllocator identifierAllocator
Definition: Timing.cpp:48
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition: CallGraph.h:229
Include the generated interface declarations.
void registerDefaultTimingManagerCLOptions()
Register a set of useful command-line options that can be used to configure a DefaultTimingManager.
Definition: Timing.cpp:612
void applyDefaultTimingManagerCLOptions(DefaultTimingManager &tm)
Apply any values that were registered with 'registerDefaultTimingManagerOptions' to a DefaultTimingMa...
Definition: Timing.cpp:617
Simple record class to record timing information.
Definition: Timing.h:328
double user
Definition: Timing.h:343
double wall
Definition: Timing.h:343