12#include "llvm/Support/RWMutex.h"
13#include "llvm/Support/Threading.h"
27 PassTiming(TimingScope &timingScope) : rootScope(timingScope) {}
28 PassTiming(std::unique_ptr<TimingManager> tm)
29 : ownedTimingManager(std::move(tm)),
30 ownedTimingScope(ownedTimingManager->getRootScope()),
31 rootScope(ownedTimingScope) {}
33 bool isThreadSafe()
const override {
return rootScope.isThreadSafe(); }
39 llvm::sys::SmartRWMutex<true> parentScopesMutex;
46 std::unique_ptr<TimingManager> ownedTimingManager;
47 TimingScope ownedTimingScope;
50 ThreadLocalCache<std::deque<TimingScope>> activeThreadTimers;
53 TimingScope &rootScope;
59 void runBeforePipeline(std::optional<OperationName> name,
60 const PipelineParentInfo &parentInfo)
override {
61 auto &activeTimers = *activeThreadTimers;
65 TimingScope *parentScope = &rootScope;
67 llvm::sys::SmartScopedReader<true> lock(parentScopesMutex);
68 auto it = parentScopes.find(parentInfo);
69 if (it != parentScopes.end())
70 parentScope = it->second;
75 const void *timerId = name ? name->getAsOpaquePointer() :
nullptr;
76 activeTimers.push_back(parentScope->
nest(timerId, [name] {
77 return (
"'" + (name ? name->getStringRef() :
"any") +
"' Pipeline").str();
81 void runAfterPipeline(std::optional<OperationName>,
82 const PipelineParentInfo &)
override {
83 auto &activeTimers = *activeThreadTimers;
84 assert(!activeTimers.empty() &&
"expected active timer");
85 activeTimers.pop_back();
92 void runBeforePass(Pass *pass, Operation *)
override {
93 auto &activeTimers = *activeThreadTimers;
94 auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
96 if (
auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass)) {
99 [adaptor]() { return adaptor->getAdaptorName(); });
100 if (adaptor->getPassManagers().size() <= 1)
102 activeTimers.push_back(std::move(scope));
103 llvm::sys::SmartScopedWriter<true> lock(parentScopesMutex);
104 parentScopes[{llvm::get_threadid(), pass}] = &activeTimers.back();
106 activeTimers.push_back(
108 [pass]() { return std::string(pass->getName()); }));
112 void runAfterPass(Pass *pass, Operation *)
override {
113 if (isa<OpToOpPassAdaptor>(pass)) {
114 llvm::sys::SmartScopedWriter<true> lock(parentScopesMutex);
115 parentScopes.erase({llvm::get_threadid(), pass});
117 auto &activeTimers = *activeThreadTimers;
118 assert(!activeTimers.empty() &&
"expected active timer");
119 activeTimers.pop_back();
122 void runAfterPassFailed(Pass *pass, Operation *op)
override {
123 runAfterPass(pass, op);
130 void runBeforeAnalysis(StringRef name, TypeID
id, Operation *)
override {
131 auto &activeTimers = *activeThreadTimers;
132 auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
133 activeTimers.push_back(parentScope.
nest(
134 id.getAsOpaquePointer(), [name] { return
"(A) " + name.str(); }));
137 void runAfterAnalysis(StringRef, TypeID, Operation *)
override {
138 auto &activeTimers = *activeThreadTimers;
139 assert(!activeTimers.empty() &&
"expected active timer");
140 activeTimers.pop_back();
160 if (!tm->getRootTimer())
168 auto tm = std::make_unique<DefaultTimingManager>();
169 tm->setEnabled(
true);
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.
const Pass * getThreadingSiblingOrThis() const
Returns the thread sibling of this pass, or the pass itself it has no sibling.
An RAII-style wrapper around a timer that ensures the timer is properly started and stopped.
TimingScope nest(Args... args)
Create a nested timing scope.
void hide()
Hide the timer in timing reports and directly show its children.
Include the generated interface declarations.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap