MLIR 22.0.0git
PassTiming.cpp
Go to the documentation of this file.
1//===- PassTiming.cpp -----------------------------------------------------===//
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#include "PassDetail.h"
11#include "llvm/ADT/SmallVector.h"
12#include "llvm/Support/Threading.h"
13
14#include <optional>
15
16using namespace mlir;
17using namespace mlir::detail;
18
19//===----------------------------------------------------------------------===//
20// PassTiming
21//===----------------------------------------------------------------------===//
22
23namespace {
24struct PassTiming : public PassInstrumentation {
25 PassTiming(TimingScope &timingScope) : rootScope(timingScope) {}
26 PassTiming(std::unique_ptr<TimingManager> tm)
27 : ownedTimingManager(std::move(tm)),
28 ownedTimingScope(ownedTimingManager->getRootScope()),
29 rootScope(ownedTimingScope) {}
30
31 /// If a pass can spawn additional work on other threads, it records the
32 /// index to its currently active timer here. Passes that run on a
33 /// newly-forked thread will check this list to find the active timer of the
34 /// parent thread into which the new thread should be nested.
36
37 /// The timing manager owned by this instrumentation (in case timing was
38 /// enabled by the user on the pass manager without providing an external
39 /// timing manager). This *must* appear before the `ownedTimingScope` to
40 /// ensure the timing manager is destroyed *after* the scope, since the latter
41 /// may hold a timer that points into the former.
42 std::unique_ptr<TimingManager> ownedTimingManager;
43 TimingScope ownedTimingScope;
44
45 /// A stack of the currently active timing scopes per thread.
47
48 /// The root timing scope into which timing is reported.
49 TimingScope &rootScope;
50
51 //===--------------------------------------------------------------------===//
52 // Pipeline
53 //===--------------------------------------------------------------------===//
54
55 void runBeforePipeline(std::optional<OperationName> name,
56 const PipelineParentInfo &parentInfo) override {
57 auto tid = llvm::get_threadid();
58 auto &activeTimers = activeThreadTimers[tid];
59
60 // Find the parent scope, either using the parent info or the root scope
61 // (e.g. in the case of the top-level pipeline).
62 TimingScope *parentScope;
63 auto it = parentTimerIndices.find(parentInfo);
64 if (it != parentTimerIndices.end())
65 parentScope = &activeThreadTimers[parentInfo.parentThreadID][it->second];
66 else
67 parentScope = &rootScope;
68
69 // Use nullptr to anchor op-agnostic pipelines, otherwise use the name of
70 // the operation.
71 const void *timerId = name ? name->getAsOpaquePointer() : nullptr;
72 activeTimers.push_back(parentScope->nest(timerId, [name] {
73 return ("'" + (name ? name->getStringRef() : "any") + "' Pipeline").str();
74 }));
75 }
76
77 void runAfterPipeline(std::optional<OperationName>,
78 const PipelineParentInfo &) override {
79 auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
80 assert(!activeTimers.empty() && "expected active timer");
81 activeTimers.pop_back();
82 }
83
84 //===--------------------------------------------------------------------===//
85 // Pass
86 //===--------------------------------------------------------------------===//
87
88 void runBeforePass(Pass *pass, Operation *) override {
89 auto tid = llvm::get_threadid();
90 auto &activeTimers = activeThreadTimers[tid];
91 auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
92
93 if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass)) {
94 parentTimerIndices[{tid, pass}] = activeTimers.size();
95 auto scope =
96 parentScope.nest(pass->getThreadingSiblingOrThis(),
97 [adaptor]() { return adaptor->getAdaptorName(); });
98 if (adaptor->getPassManagers().size() <= 1)
99 scope.hide();
100 activeTimers.push_back(std::move(scope));
101 } else {
102 activeTimers.push_back(
103 parentScope.nest(pass->getThreadingSiblingOrThis(),
104 [pass]() { return std::string(pass->getName()); }));
105 }
106 }
107
108 void runAfterPass(Pass *pass, Operation *) override {
109 auto tid = llvm::get_threadid();
110 if (isa<OpToOpPassAdaptor>(pass))
111 parentTimerIndices.erase({tid, pass});
112 auto &activeTimers = activeThreadTimers[tid];
113 assert(!activeTimers.empty() && "expected active timer");
114 activeTimers.pop_back();
115 }
116
117 void runAfterPassFailed(Pass *pass, Operation *op) override {
118 runAfterPass(pass, op);
119 }
120
121 //===--------------------------------------------------------------------===//
122 // Analysis
123 //===--------------------------------------------------------------------===//
124
125 void runBeforeAnalysis(StringRef name, TypeID id, Operation *) override {
126 auto tid = llvm::get_threadid();
127 auto &activeTimers = activeThreadTimers[tid];
128 auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
129 activeTimers.push_back(parentScope.nest(
130 id.getAsOpaquePointer(), [name] { return "(A) " + name.str(); }));
131 }
132
133 void runAfterAnalysis(StringRef, TypeID, Operation *) override {
134 auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
135 assert(!activeTimers.empty() && "expected active timer");
136 activeTimers.pop_back();
137 }
138};
139} // namespace
140
141//===----------------------------------------------------------------------===//
142// PassManager
143//===----------------------------------------------------------------------===//
144
145/// Add an instrumentation to time the execution of passes and the computation
146/// of analyses.
148 if (!timingScope)
149 return;
150 addInstrumentation(std::make_unique<PassTiming>(timingScope));
151}
152
153/// Add an instrumentation to time the execution of passes and the computation
154/// of analyses.
155void PassManager::enableTiming(std::unique_ptr<TimingManager> tm) {
156 if (!tm->getRootTimer())
157 return; // no need to keep the timing manager around if it's disabled
158 addInstrumentation(std::make_unique<PassTiming>(std::move(tm)));
159}
160
161/// Add an instrumentation to time the execution of passes and the computation
162/// of analyses.
164 auto tm = std::make_unique<DefaultTimingManager>();
165 tm->setEnabled(true);
166 enableTiming(std::move(tm));
167}
PassInstrumentation provides several entry points into the pass manager infrastructure.
void enableTiming()
Add an instrumentation to time the execution of passes and the computation of analyses.
void addInstrumentation(std::unique_ptr< PassInstrumentation > pi)
Add the provided instrumentation to the pass manager.
Definition Pass.cpp:1108
const Pass * getThreadingSiblingOrThis() const
Returns the thread sibling of this pass, or the pass itself it has no sibling.
Definition Pass.h:158
An RAII-style wrapper around a timer that ensures the timer is properly started and stopped.
Definition Timing.h:272
TimingScope nest(Args... args)
Create a nested timing scope.
Definition Timing.h:311
void hide()
Hide the timer in timing reports and directly show its children.
Definition Timing.h:316
AttrTypeReplacer.
Include the generated interface declarations.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:126