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