1 //===- PassTiming.cpp -----------------------------------------------------===//
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 #include "PassDetail.h"
10 #include "mlir/Pass/PassManager.h"
11 #include "llvm/ADT/SmallVector.h"
12 #include "llvm/Support/Threading.h"
18 using namespace mlir::detail
;
20 //===----------------------------------------------------------------------===//
22 //===----------------------------------------------------------------------===//
25 struct PassTiming
: public PassInstrumentation
{
26 PassTiming(TimingScope
&timingScope
) : rootScope(timingScope
) {}
27 PassTiming(std::unique_ptr
<TimingManager
> tm
)
28 : ownedTimingManager(std::move(tm
)),
29 ownedTimingScope(ownedTimingManager
->getRootScope()),
30 rootScope(ownedTimingScope
) {}
32 /// If a pass can spawn additional work on other threads, it records the
33 /// index to its currently active timer here. Passes that run on a
34 /// newly-forked thread will check this list to find the active timer of the
35 /// parent thread into which the new thread should be nested.
36 DenseMap
<PipelineParentInfo
, unsigned> parentTimerIndices
;
38 /// A stack of the currently active timing scopes per thread.
39 DenseMap
<uint64_t, SmallVector
<TimingScope
, 4>> activeThreadTimers
;
41 /// The timing manager owned by this instrumentation (in case timing was
42 /// enabled by the user on the pass manager without providing an external
43 /// timing manager). This *must* appear before the `ownedTimingScope` to
44 /// ensure the timing manager is destroyed *after* the scope, since the latter
45 /// may hold a timer that points into the former.
46 std::unique_ptr
<TimingManager
> ownedTimingManager
;
47 TimingScope ownedTimingScope
;
49 /// The root timing scope into which timing is reported.
50 TimingScope
&rootScope
;
52 //===--------------------------------------------------------------------===//
54 //===--------------------------------------------------------------------===//
56 void runBeforePipeline(std::optional
<OperationName
> name
,
57 const PipelineParentInfo
&parentInfo
) override
{
58 auto tid
= llvm::get_threadid();
59 auto &activeTimers
= activeThreadTimers
[tid
];
61 // Find the parent scope, either using the parent info or the root scope
62 // (e.g. in the case of the top-level pipeline).
63 TimingScope
*parentScope
;
64 auto it
= parentTimerIndices
.find(parentInfo
);
65 if (it
!= parentTimerIndices
.end())
66 parentScope
= &activeThreadTimers
[parentInfo
.parentThreadID
][it
->second
];
68 parentScope
= &rootScope
;
70 // Use nullptr to anchor op-agnostic pipelines, otherwise use the name of
72 const void *timerId
= name
? name
->getAsOpaquePointer() : nullptr;
73 activeTimers
.push_back(parentScope
->nest(timerId
, [name
] {
74 return ("'" + (name
? name
->getStringRef() : "any") + "' Pipeline").str();
78 void runAfterPipeline(std::optional
<OperationName
>,
79 const PipelineParentInfo
&) override
{
80 auto &activeTimers
= activeThreadTimers
[llvm::get_threadid()];
81 assert(!activeTimers
.empty() && "expected active timer");
82 activeTimers
.pop_back();
85 //===--------------------------------------------------------------------===//
87 //===--------------------------------------------------------------------===//
89 void runBeforePass(Pass
*pass
, Operation
*) override
{
90 auto tid
= llvm::get_threadid();
91 auto &activeTimers
= activeThreadTimers
[tid
];
92 auto &parentScope
= activeTimers
.empty() ? rootScope
: activeTimers
.back();
94 if (auto *adaptor
= dyn_cast
<OpToOpPassAdaptor
>(pass
)) {
95 parentTimerIndices
[{tid
, pass
}] = activeTimers
.size();
97 parentScope
.nest(pass
->getThreadingSiblingOrThis(),
98 [adaptor
]() { return adaptor
->getAdaptorName(); });
99 if (adaptor
->getPassManagers().size() <= 1)
101 activeTimers
.push_back(std::move(scope
));
103 activeTimers
.push_back(
104 parentScope
.nest(pass
->getThreadingSiblingOrThis(),
105 [pass
]() { return std::string(pass
->getName()); }));
109 void runAfterPass(Pass
*pass
, Operation
*) override
{
110 auto tid
= llvm::get_threadid();
111 if (isa
<OpToOpPassAdaptor
>(pass
))
112 parentTimerIndices
.erase({tid
, pass
});
113 auto &activeTimers
= activeThreadTimers
[tid
];
114 assert(!activeTimers
.empty() && "expected active timer");
115 activeTimers
.pop_back();
118 void runAfterPassFailed(Pass
*pass
, Operation
*op
) override
{
119 runAfterPass(pass
, op
);
122 //===--------------------------------------------------------------------===//
124 //===--------------------------------------------------------------------===//
126 void runBeforeAnalysis(StringRef name
, TypeID id
, Operation
*) override
{
127 auto tid
= llvm::get_threadid();
128 auto &activeTimers
= activeThreadTimers
[tid
];
129 auto &parentScope
= activeTimers
.empty() ? rootScope
: activeTimers
.back();
130 activeTimers
.push_back(parentScope
.nest(
131 id
.getAsOpaquePointer(), [name
] { return "(A) " + name
.str(); }));
134 void runAfterAnalysis(StringRef
, TypeID
, Operation
*) override
{
135 auto &activeTimers
= activeThreadTimers
[llvm::get_threadid()];
136 assert(!activeTimers
.empty() && "expected active timer");
137 activeTimers
.pop_back();
142 //===----------------------------------------------------------------------===//
144 //===----------------------------------------------------------------------===//
146 /// Add an instrumentation to time the execution of passes and the computation
148 void PassManager::enableTiming(TimingScope
&timingScope
) {
151 addInstrumentation(std::make_unique
<PassTiming
>(timingScope
));
154 /// Add an instrumentation to time the execution of passes and the computation
156 void PassManager::enableTiming(std::unique_ptr
<TimingManager
> tm
) {
157 if (!tm
->getRootTimer())
158 return; // no need to keep the timing manager around if it's disabled
159 addInstrumentation(std::make_unique
<PassTiming
>(std::move(tm
)));
162 /// Add an instrumentation to time the execution of passes and the computation
164 void PassManager::enableTiming() {
165 auto tm
= std::make_unique
<DefaultTimingManager
>();
166 tm
->setEnabled(true);
167 enableTiming(std::move(tm
));