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"
36 "... Execution time report ...";
54 llvm::StringMap<llvm::StringMapEntry<llvm::EmptyStringSetTag> *>>
85 auto *&localEntry = (*
impl.localIdentifierCache)[
str];
91 llvm::sys::SmartScopedReader<true> contextLock(
impl.identifierMutex);
92 auto it =
impl.identifiers.find(
str);
93 if (it !=
impl.identifiers.end()) {
100 llvm::sys::SmartScopedWriter<true> contextLock(
impl.identifierMutex);
101 auto it =
impl.identifiers.insert(
str).first;
116 void printHeader(
const TimeRecord &total)
override {
119 os <<
"===" << std::string(73,
'-') <<
"===\n";
121 os <<
"===" << std::string(73,
'-') <<
"===\n";
124 os << llvm::format(
" Total Execution Time: %.4f seconds\n\n", total.
wall);
126 os <<
" ----User Time----";
127 os <<
" ----Wall Time---- ----Name----\n";
130 void printFooter()
override { os.flush(); }
132 void printTime(
const TimeRecord &time,
const TimeRecord &total)
override {
134 os << llvm::format(
" %8.4f (%5.1f%%)", time.
user,
137 os << llvm::format(
" %8.4f (%5.1f%%) ", time.
wall,
141 void printListEntry(StringRef name,
const TimeRecord &time,
142 const TimeRecord &total,
bool lastEntry)
override {
143 printTime(time, total);
147 void printTreeEntry(
unsigned indent, StringRef name,
const TimeRecord &time,
148 const TimeRecord &total)
override {
149 printTime(time, total);
150 os.indent(indent) << name <<
"\n";
153 void printTreeEntryEnd(
unsigned indent,
bool lastEntry)
override {}
158 OutputJsonStrategy(raw_ostream &os) : OutputStrategy(os) {}
160 void printHeader(
const TimeRecord &total)
override { os <<
"[" <<
"\n"; }
162 void printFooter()
override {
167 void printTime(
const TimeRecord &time,
const TimeRecord &total)
override {
170 os <<
"\"duration\": " << llvm::format(
"%8.4f", time.
user) <<
", ";
171 os <<
"\"percentage\": "
172 << llvm::format(
"%5.1f", 100.0 * time.
user / total.
user);
176 os <<
"\"duration\": " << llvm::format(
"%8.4f", time.
wall) <<
", ";
177 os <<
"\"percentage\": "
178 << llvm::format(
"%5.1f", 100.0 * time.
wall / total.
wall);
182 void printListEntry(StringRef name,
const TimeRecord &time,
183 const TimeRecord &total,
bool lastEntry)
override {
185 printTime(time, total);
186 os <<
", \"name\": " <<
"\"" << name <<
"\"";
193 void printTreeEntry(
unsigned indent, StringRef name,
const TimeRecord &time,
194 const TimeRecord &total)
override {
195 os.indent(indent) <<
"{";
196 printTime(time, total);
197 os <<
", \"name\": " <<
"\"" << name <<
"\"";
198 os <<
", \"passes\": [" <<
"\n";
201 void printTreeEntryEnd(
unsigned indent,
bool lastEntry)
override {
202 os.indent(indent) <<
"{}]";
225 using ChildrenMap = llvm::MapVector<const void *, std::unique_ptr<TimerImpl>>;
226 using AsyncChildrenMap = llvm::DenseMap<uint64_t, ChildrenMap>;
228 TimerImpl(std::string &&name, std::unique_ptr<OutputStrategy> &output)
229 : threadId(llvm::get_threadid()), name(name), output(output) {}
232 void start() { startTime = std::chrono::steady_clock::now(); }
236 auto newTime = std::chrono::steady_clock::now() - startTime;
247 TimerImpl *nest(
const void *
id,
function_ref<std::string()> nameBuilder) {
248 auto tid = llvm::get_threadid();
250 return nestTail(children[
id], nameBuilder);
251 std::unique_lock<std::mutex> lock(asyncMutex);
252 return nestTail(asyncChildren[tid][
id], nameBuilder);
256 TimerImpl *nestTail(std::unique_ptr<TimerImpl> &child,
259 child = std::make_unique<TimerImpl>(nameBuilder(), output);
273 mergeAsyncChildren();
279 std::chrono::nanoseconds addAsyncUserTime() {
280 auto added = std::chrono::nanoseconds(0);
281 for (
auto &child : children)
282 added += child.second->addAsyncUserTime();
283 for (
auto &thread : asyncChildren) {
284 for (
auto &child : thread.second) {
285 child.second->addAsyncUserTime();
286 added += child.second->userTime;
295 void mergeAsyncChildren() {
296 for (
auto &child : children)
297 child.second->mergeAsyncChildren();
298 mergeChildren(std::move(asyncChildren));
299 assert(asyncChildren.empty());
307 void mergeChildren(ChildrenMap &&other) {
308 if (children.empty()) {
309 children = std::move(other);
310 for (
auto &child : children)
311 child.second->mergeAsyncChildren();
313 for (
auto &child : other)
314 mergeChild(child.first, std::move(child.second));
320 void mergeChildren(AsyncChildrenMap &&other) {
321 for (
auto &thread : other) {
322 mergeChildren(std::move(thread.second));
331 void mergeChild(
const void *
id, std::unique_ptr<TimerImpl> &&other) {
332 auto &into = children[id];
334 into = std::move(other);
335 into->mergeAsyncChildren();
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));
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)
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);
363 TimeRecord getTimeRecord() {
365 std::chrono::duration_cast<std::chrono::duration<double>>(wallTime)
367 std::chrono::duration_cast<std::chrono::duration<double>>(userTime)
372 void printAsList(TimeRecord total) {
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());
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);
394 for (
auto &timeData : timerNameAndTime)
395 output->printListEntry(timeData.first, timeData.second, total);
399 void printAsTree(TimeRecord total,
unsigned indent = 0) {
400 unsigned childIndent = indent;
402 output->printTreeEntry(indent, name, getTimeRecord(), total);
405 for (
auto &child : children) {
406 child.second->printAsTree(total, childIndent);
409 output->printTreeEntryEnd(indent);
416 auto total = getTimeRecord();
417 output->printHeader(total);
420 switch (displayMode) {
421 case DisplayMode::List:
424 case DisplayMode::Tree:
432 for (
auto &child : children)
433 rest -= child.second->getTimeRecord();
434 output->printListEntry(
"Rest", rest, total);
435 output->printListEntry(
"Total", total, total,
true);
436 output->printFooter();
440 std::chrono::time_point<std::chrono::steady_clock> startTime;
445 std::chrono::nanoseconds wallTime = std::chrono::nanoseconds(0);
449 std::chrono::nanoseconds userTime = std::chrono::nanoseconds(0);
462 ChildrenMap children;
466 AsyncChildrenMap asyncChildren;
469 std::mutex asyncMutex;
471 std::unique_ptr<OutputStrategy> &output;
501 out(std::make_unique<OutputTextStrategy>(
llvm::errs())) {
515 impl->displayMode = displayMode;
520 return impl->displayMode;
525 out = std::move(output);
531 impl->rootTimer->finalize();
532 impl->rootTimer->print(
impl->displayMode);
539 impl->rootTimer = std::make_unique<TimerImpl>(
"root", out);
540 impl->rootTimer->hidden =
true;
545 impl->rootTimer->dump(os);
550 impl->rootTimer->finalize();
551 impl->rootTimer->print(DisplayMode::List);
556 impl->rootTimer->finalize();
557 impl->rootTimer->print(DisplayMode::Tree);
562 return impl->rootTimer.get();
567 static_cast<TimerImpl *
>(handle)->start();
571 static_cast<TimerImpl *
>(handle)->stop();
576 return static_cast<TimerImpl *
>(handle)->nest(
id, nameBuilder);
580 static_cast<TimerImpl *
>(handle)->hidden =
true;
588struct 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),
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"))};
610static llvm::ManagedStatic<DefaultTimingManagerOptions>
options;
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());
static llvm::ManagedStatic< PassManagerOptions > options
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
DefaultTimingManager::OutputFormat OutputFormat
constexpr llvm::StringLiteral kTimingDescription
DefaultTimingManager::DisplayMode DisplayMode
Facilities for time measurement and report printing to an output stream.
void setDisplayMode(DisplayMode displayMode)
Change the display mode.
void stopTimer(void *handle) override
Stop the timer with the given handle.
std::optional< void * > rootTimer() override
Return the root timer.
DisplayMode
The different display modes for printing the timers.
void setOutput(std::unique_ptr< OutputStrategy > output)
Change the stream where the output will be printed to.
void dumpTimers(raw_ostream &os=llvm::errs())
Debug print the timer data structures to an output stream.
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.
void startTimer(void *handle) override
Start the timer with the given handle.
DisplayMode getDisplayMode() const
Return the current display mode;.
void dumpAsList(raw_ostream &os=llvm::errs())
Debug print the timers as a list.
void dumpAsTree(raw_ostream &os=llvm::errs())
Debug print the timers as a tree.
void clear()
Clear the timing results.
~DefaultTimingManager() override
void print()
Print and clear the timing results.
void setEnabled(bool enabled)
Enable or disable execution time sampling.
OutputFormat
The different output formats for printing the timers.
bool isEnabled() const
Return whether execution time sampling is enabled.
void hideTimer(void *handle) override
Hide the timer in timing reports and directly show its children.
Facilities for printing timing reports to various output formats.
This class provides support for defining a thread local object with non static storage duration.
std::string str() const
Return an std::string.
TimingIdentifier(const TimingIdentifier &)=default
static TimingIdentifier get(StringRef str, TimingManager &tm)
Return an identifier for the specified string.
This class represents facilities to measure execution time.
virtual std::optional< void * > rootTimer()=0
Return the root timer.
TimingScope getRootScope()
Get the root timer of this timing manager wrapped in a TimingScope for convenience.
const std::unique_ptr< detail::TimingManagerImpl > impl
Timer getRootTimer()
Get the root timer of this timing manager.
An RAII-style wrapper around a timer that ensures the timer is properly started and stopped.
Implementation details of the DefaultTimingManager.
bool enabled
Whether we should do our work or not.
std::unique_ptr< TimerImpl > rootTimer
The root timer.
DisplayMode displayMode
The configured display mode.
Private implementation details of the TimingManager.
ThreadLocalCache< llvm::StringMap< llvm::StringMapEntry< llvm::EmptyStringSetTag > * > > localIdentifierCache
A thread local cache of identifiers to reduce lock contention.
llvm::sys::SmartRWMutex< true > identifierMutex
llvm::StringSet< llvm::BumpPtrAllocator & > identifiers
llvm::BumpPtrAllocator identifierAllocator
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Include the generated interface declarations.
void registerDefaultTimingManagerCLOptions()
Register a set of useful command-line options that can be used to configure a DefaultTimingManager.
void applyDefaultTimingManagerCLOptions(DefaultTimingManager &tm)
Apply any values that were registered with 'registerDefaultTimingManagerOptions' to a DefaultTimingMa...
llvm::function_ref< Fn > function_ref
Simple record class to record timing information.