1e46ba31cSRiver Riddle //===- PassTiming.cpp -----------------------------------------------------===//
2e46ba31cSRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e46ba31cSRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
8e46ba31cSRiver Riddle 
9e46ba31cSRiver Riddle #include "PassDetail.h"
106558f80cSRiver Riddle #include "mlir/Pass/PassManager.h"
11e46ba31cSRiver Riddle #include "llvm/ADT/SmallVector.h"
123a845be7SRiver Riddle #include "llvm/Support/Threading.h"
13*33f908c4SFabian Schuiki 
148e7b683dSRiver Riddle #include <chrono>
15e46ba31cSRiver Riddle 
16e46ba31cSRiver Riddle using namespace mlir;
17e46ba31cSRiver Riddle using namespace mlir::detail;
18e46ba31cSRiver Riddle 
19*33f908c4SFabian Schuiki //===----------------------------------------------------------------------===//
20*33f908c4SFabian Schuiki // PassTiming
21*33f908c4SFabian Schuiki //===----------------------------------------------------------------------===//
22e46ba31cSRiver Riddle 
236558f80cSRiver Riddle namespace {
246558f80cSRiver Riddle struct PassTiming : public PassInstrumentation {
25*33f908c4SFabian Schuiki   PassTiming(TimingScope &timingScope) : rootScope(timingScope) {}
26*33f908c4SFabian Schuiki   PassTiming(std::unique_ptr<TimingManager> tm)
27*33f908c4SFabian Schuiki       : ownedTimingManager(std::move(tm)),
28*33f908c4SFabian Schuiki         ownedTimingScope(ownedTimingManager->getRootScope()),
29*33f908c4SFabian Schuiki         rootScope(ownedTimingScope) {}
30e46ba31cSRiver Riddle 
31*33f908c4SFabian Schuiki   /// If a pass can spawn additional work on other threads, it records the
32*33f908c4SFabian Schuiki   /// index to its currently active timer here. Passes that run on a
33*33f908c4SFabian Schuiki   /// newly-forked thread will check this list to find the active timer of the
34*33f908c4SFabian Schuiki   /// parent thread into which the new thread should be nested.
35*33f908c4SFabian Schuiki   DenseMap<PipelineParentInfo, unsigned> parentTimerIndices;
36*33f908c4SFabian Schuiki 
37*33f908c4SFabian Schuiki   /// A stack of the currently active timing scopes per thread.
38*33f908c4SFabian Schuiki   DenseMap<uint64_t, SmallVector<TimingScope, 4>> activeThreadTimers;
39*33f908c4SFabian Schuiki 
40*33f908c4SFabian Schuiki   /// The timing manager owned by this instrumentation (in case timing was
41*33f908c4SFabian Schuiki   /// enabled by the user on the pass manager without providing an external
42*33f908c4SFabian Schuiki   /// timing manager). This *must* appear before the `ownedTimingScope` to
43*33f908c4SFabian Schuiki   /// ensure the timing manager is destroyed *after* the scope, since the latter
44*33f908c4SFabian Schuiki   /// may hold a timer that points into the former.
45*33f908c4SFabian Schuiki   std::unique_ptr<TimingManager> ownedTimingManager;
46*33f908c4SFabian Schuiki   TimingScope ownedTimingScope;
47*33f908c4SFabian Schuiki 
48*33f908c4SFabian Schuiki   /// The root timing scope into which timing is reported.
49*33f908c4SFabian Schuiki   TimingScope &rootScope;
50*33f908c4SFabian Schuiki 
51*33f908c4SFabian Schuiki   //===--------------------------------------------------------------------===//
52*33f908c4SFabian Schuiki   // Pipeline
53*33f908c4SFabian Schuiki   //===--------------------------------------------------------------------===//
54*33f908c4SFabian Schuiki 
551284dc34SMehdi Amini   void runBeforePipeline(Identifier name,
56*33f908c4SFabian Schuiki                          const PipelineParentInfo &parentInfo) override {
57120509a6SRiver Riddle     auto tid = llvm::get_threadid();
58120509a6SRiver Riddle     auto &activeTimers = activeThreadTimers[tid];
596558f80cSRiver Riddle 
60*33f908c4SFabian Schuiki     TimingScope *parentScope;
613a845be7SRiver Riddle     if (activeTimers.empty()) {
62*33f908c4SFabian Schuiki       auto it = parentTimerIndices.find(parentInfo);
63*33f908c4SFabian Schuiki       if (it != parentTimerIndices.end())
64*33f908c4SFabian Schuiki         parentScope =
65*33f908c4SFabian Schuiki             &activeThreadTimers[parentInfo.parentThreadID][it->second];
66*33f908c4SFabian Schuiki       else
67*33f908c4SFabian Schuiki         parentScope = &rootScope;
68120509a6SRiver Riddle     } else {
69*33f908c4SFabian Schuiki       parentScope = &activeTimers.back();
70*33f908c4SFabian Schuiki     }
71*33f908c4SFabian Schuiki     activeTimers.push_back(parentScope->nest(name.getAsOpaquePointer(), [name] {
72*33f908c4SFabian Schuiki       return ("'" + name.strref() + "' Pipeline").str();
73*33f908c4SFabian Schuiki     }));
748e7b683dSRiver Riddle   }
756558f80cSRiver Riddle 
76*33f908c4SFabian Schuiki   void runAfterPipeline(Identifier, const PipelineParentInfo &) override {
77*33f908c4SFabian Schuiki     auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
78*33f908c4SFabian Schuiki     assert(!activeTimers.empty() && "expected active timer");
79*33f908c4SFabian Schuiki     activeTimers.pop_back();
803a845be7SRiver Riddle   }
816558f80cSRiver Riddle 
82*33f908c4SFabian Schuiki   //===--------------------------------------------------------------------===//
83*33f908c4SFabian Schuiki   // Pass
84*33f908c4SFabian Schuiki   //===--------------------------------------------------------------------===//
853a845be7SRiver Riddle 
86*33f908c4SFabian Schuiki   void runBeforePass(Pass *pass, Operation *) override {
87120509a6SRiver Riddle     auto tid = llvm::get_threadid();
88120509a6SRiver Riddle     auto &activeTimers = activeThreadTimers[tid];
89*33f908c4SFabian Schuiki     auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
90*33f908c4SFabian Schuiki 
91*33f908c4SFabian Schuiki     if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass)) {
92*33f908c4SFabian Schuiki       parentTimerIndices[{tid, pass}] = activeTimers.size();
93*33f908c4SFabian Schuiki       auto scope =
94*33f908c4SFabian Schuiki           parentScope.nest(pass->getThreadingSiblingOrThis(),
95*33f908c4SFabian Schuiki                            [adaptor]() { return adaptor->getAdaptorName(); });
96*33f908c4SFabian Schuiki       if (adaptor->getPassManagers().size() <= 1)
97*33f908c4SFabian Schuiki         scope.hide();
98*33f908c4SFabian Schuiki       activeTimers.push_back(std::move(scope));
99*33f908c4SFabian Schuiki     } else {
100*33f908c4SFabian Schuiki       activeTimers.push_back(
101*33f908c4SFabian Schuiki           parentScope.nest(pass->getThreadingSiblingOrThis(),
102*33f908c4SFabian Schuiki                            [pass]() { return std::string(pass->getName()); }));
103*33f908c4SFabian Schuiki     }
104*33f908c4SFabian Schuiki   }
105*33f908c4SFabian Schuiki 
106*33f908c4SFabian Schuiki   void runAfterPass(Pass *pass, Operation *) override {
107*33f908c4SFabian Schuiki     auto tid = llvm::get_threadid();
108*33f908c4SFabian Schuiki     if (isa<OpToOpPassAdaptor>(pass))
109*33f908c4SFabian Schuiki       parentTimerIndices.erase({tid, pass});
110*33f908c4SFabian Schuiki     auto &activeTimers = activeThreadTimers[tid];
111120509a6SRiver Riddle     assert(!activeTimers.empty() && "expected active timer");
112120509a6SRiver Riddle     activeTimers.pop_back();
113120509a6SRiver Riddle   }
114120509a6SRiver Riddle 
115*33f908c4SFabian Schuiki   void runAfterPassFailed(Pass *pass, Operation *op) override {
116*33f908c4SFabian Schuiki     runAfterPass(pass, op);
117e46ba31cSRiver Riddle   }
118e46ba31cSRiver Riddle 
119*33f908c4SFabian Schuiki   //===--------------------------------------------------------------------===//
120*33f908c4SFabian Schuiki   // Analysis
121*33f908c4SFabian Schuiki   //===--------------------------------------------------------------------===//
122*33f908c4SFabian Schuiki 
123*33f908c4SFabian Schuiki   void runBeforeAnalysis(StringRef name, TypeID id, Operation *) override {
124*33f908c4SFabian Schuiki     auto tid = llvm::get_threadid();
125*33f908c4SFabian Schuiki     auto &activeTimers = activeThreadTimers[tid];
126*33f908c4SFabian Schuiki     auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
127*33f908c4SFabian Schuiki     activeTimers.push_back(parentScope.nest(
128*33f908c4SFabian Schuiki         id.getAsOpaquePointer(), [name] { return "(A) " + name.str(); }));
129e46ba31cSRiver Riddle   }
130e46ba31cSRiver Riddle 
131*33f908c4SFabian Schuiki   void runAfterAnalysis(StringRef, TypeID, Operation *) override {
132*33f908c4SFabian Schuiki     auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
133*33f908c4SFabian Schuiki     assert(!activeTimers.empty() && "expected active timer");
134*33f908c4SFabian Schuiki     activeTimers.pop_back();
1353a845be7SRiver Riddle   }
136f65a3f7cSMehdi Amini };
137*33f908c4SFabian Schuiki } // namespace
138f65a3f7cSMehdi Amini 
1396558f80cSRiver Riddle //===----------------------------------------------------------------------===//
1406558f80cSRiver Riddle // PassManager
1416558f80cSRiver Riddle //===----------------------------------------------------------------------===//
1426558f80cSRiver Riddle 
1436558f80cSRiver Riddle /// Add an instrumentation to time the execution of passes and the computation
1446558f80cSRiver Riddle /// of analyses.
145*33f908c4SFabian Schuiki void PassManager::enableTiming(TimingScope &timingScope) {
146*33f908c4SFabian Schuiki   if (!timingScope)
1476558f80cSRiver Riddle     return;
148*33f908c4SFabian Schuiki   addInstrumentation(std::make_unique<PassTiming>(timingScope));
149*33f908c4SFabian Schuiki }
150*33f908c4SFabian Schuiki 
151*33f908c4SFabian Schuiki /// Add an instrumentation to time the execution of passes and the computation
152*33f908c4SFabian Schuiki /// of analyses.
153*33f908c4SFabian Schuiki void PassManager::enableTiming(std::unique_ptr<TimingManager> tm) {
154*33f908c4SFabian Schuiki   if (!tm->getRootTimer())
155*33f908c4SFabian Schuiki     return; // no need to keep the timing manager around if it's disabled
156*33f908c4SFabian Schuiki   addInstrumentation(std::make_unique<PassTiming>(std::move(tm)));
157*33f908c4SFabian Schuiki }
158*33f908c4SFabian Schuiki 
159*33f908c4SFabian Schuiki /// Add an instrumentation to time the execution of passes and the computation
160*33f908c4SFabian Schuiki /// of analyses.
161*33f908c4SFabian Schuiki void PassManager::enableTiming() {
162*33f908c4SFabian Schuiki   auto tm = std::make_unique<DefaultTimingManager>();
163*33f908c4SFabian Schuiki   tm->setEnabled(true);
164*33f908c4SFabian Schuiki   enableTiming(std::move(tm));
1656558f80cSRiver Riddle }
166