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"
1333f908c4SFabian Schuiki
148e7b683dSRiver Riddle #include <chrono>
15e46ba31cSRiver Riddle
16e46ba31cSRiver Riddle using namespace mlir;
17e46ba31cSRiver Riddle using namespace mlir::detail;
18e46ba31cSRiver Riddle
1933f908c4SFabian Schuiki //===----------------------------------------------------------------------===//
2033f908c4SFabian Schuiki // PassTiming
2133f908c4SFabian Schuiki //===----------------------------------------------------------------------===//
22e46ba31cSRiver Riddle
236558f80cSRiver Riddle namespace {
246558f80cSRiver Riddle struct PassTiming : public PassInstrumentation {
PassTiming__anon2e0843fe0111::PassTiming2533f908c4SFabian Schuiki PassTiming(TimingScope &timingScope) : rootScope(timingScope) {}
PassTiming__anon2e0843fe0111::PassTiming2633f908c4SFabian Schuiki PassTiming(std::unique_ptr<TimingManager> tm)
2733f908c4SFabian Schuiki : ownedTimingManager(std::move(tm)),
2833f908c4SFabian Schuiki ownedTimingScope(ownedTimingManager->getRootScope()),
2933f908c4SFabian Schuiki rootScope(ownedTimingScope) {}
30e46ba31cSRiver Riddle
3133f908c4SFabian Schuiki /// If a pass can spawn additional work on other threads, it records the
3233f908c4SFabian Schuiki /// index to its currently active timer here. Passes that run on a
3333f908c4SFabian Schuiki /// newly-forked thread will check this list to find the active timer of the
3433f908c4SFabian Schuiki /// parent thread into which the new thread should be nested.
3533f908c4SFabian Schuiki DenseMap<PipelineParentInfo, unsigned> parentTimerIndices;
3633f908c4SFabian Schuiki
3733f908c4SFabian Schuiki /// A stack of the currently active timing scopes per thread.
3833f908c4SFabian Schuiki DenseMap<uint64_t, SmallVector<TimingScope, 4>> activeThreadTimers;
3933f908c4SFabian Schuiki
4033f908c4SFabian Schuiki /// The timing manager owned by this instrumentation (in case timing was
4133f908c4SFabian Schuiki /// enabled by the user on the pass manager without providing an external
4233f908c4SFabian Schuiki /// timing manager). This *must* appear before the `ownedTimingScope` to
4333f908c4SFabian Schuiki /// ensure the timing manager is destroyed *after* the scope, since the latter
4433f908c4SFabian Schuiki /// may hold a timer that points into the former.
4533f908c4SFabian Schuiki std::unique_ptr<TimingManager> ownedTimingManager;
4633f908c4SFabian Schuiki TimingScope ownedTimingScope;
4733f908c4SFabian Schuiki
4833f908c4SFabian Schuiki /// The root timing scope into which timing is reported.
4933f908c4SFabian Schuiki TimingScope &rootScope;
5033f908c4SFabian Schuiki
5133f908c4SFabian Schuiki //===--------------------------------------------------------------------===//
5233f908c4SFabian Schuiki // Pipeline
5333f908c4SFabian Schuiki //===--------------------------------------------------------------------===//
5433f908c4SFabian Schuiki
runBeforePipeline__anon2e0843fe0111::PassTiming55*c2fb9c29SRiver Riddle void runBeforePipeline(Optional<OperationName> name,
5633f908c4SFabian Schuiki const PipelineParentInfo &parentInfo) override {
57120509a6SRiver Riddle auto tid = llvm::get_threadid();
58120509a6SRiver Riddle auto &activeTimers = activeThreadTimers[tid];
596558f80cSRiver Riddle
6033f908c4SFabian Schuiki TimingScope *parentScope;
613a845be7SRiver Riddle if (activeTimers.empty()) {
6233f908c4SFabian Schuiki auto it = parentTimerIndices.find(parentInfo);
6333f908c4SFabian Schuiki if (it != parentTimerIndices.end())
6433f908c4SFabian Schuiki parentScope =
6533f908c4SFabian Schuiki &activeThreadTimers[parentInfo.parentThreadID][it->second];
6633f908c4SFabian Schuiki else
6733f908c4SFabian Schuiki parentScope = &rootScope;
68120509a6SRiver Riddle } else {
6933f908c4SFabian Schuiki parentScope = &activeTimers.back();
7033f908c4SFabian Schuiki }
71*c2fb9c29SRiver Riddle
72*c2fb9c29SRiver Riddle // Use nullptr to anchor op-agnostic pipelines, otherwise use the name of
73*c2fb9c29SRiver Riddle // the operation.
74*c2fb9c29SRiver Riddle const void *timerId = name ? name->getAsOpaquePointer() : nullptr;
75*c2fb9c29SRiver Riddle activeTimers.push_back(parentScope->nest(timerId, [name] {
76*c2fb9c29SRiver Riddle return ("'" + (name ? name->getStringRef() : "any") + "' Pipeline").str();
7733f908c4SFabian Schuiki }));
788e7b683dSRiver Riddle }
796558f80cSRiver Riddle
runAfterPipeline__anon2e0843fe0111::PassTiming80*c2fb9c29SRiver Riddle void runAfterPipeline(Optional<OperationName>,
81*c2fb9c29SRiver Riddle const PipelineParentInfo &) override {
8233f908c4SFabian Schuiki auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
8333f908c4SFabian Schuiki assert(!activeTimers.empty() && "expected active timer");
8433f908c4SFabian Schuiki activeTimers.pop_back();
853a845be7SRiver Riddle }
866558f80cSRiver Riddle
8733f908c4SFabian Schuiki //===--------------------------------------------------------------------===//
8833f908c4SFabian Schuiki // Pass
8933f908c4SFabian Schuiki //===--------------------------------------------------------------------===//
903a845be7SRiver Riddle
runBeforePass__anon2e0843fe0111::PassTiming9133f908c4SFabian Schuiki void runBeforePass(Pass *pass, Operation *) override {
92120509a6SRiver Riddle auto tid = llvm::get_threadid();
93120509a6SRiver Riddle auto &activeTimers = activeThreadTimers[tid];
9433f908c4SFabian Schuiki auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
9533f908c4SFabian Schuiki
9633f908c4SFabian Schuiki if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass)) {
9733f908c4SFabian Schuiki parentTimerIndices[{tid, pass}] = activeTimers.size();
9833f908c4SFabian Schuiki auto scope =
9933f908c4SFabian Schuiki parentScope.nest(pass->getThreadingSiblingOrThis(),
10033f908c4SFabian Schuiki [adaptor]() { return adaptor->getAdaptorName(); });
10133f908c4SFabian Schuiki if (adaptor->getPassManagers().size() <= 1)
10233f908c4SFabian Schuiki scope.hide();
10333f908c4SFabian Schuiki activeTimers.push_back(std::move(scope));
10433f908c4SFabian Schuiki } else {
10533f908c4SFabian Schuiki activeTimers.push_back(
10633f908c4SFabian Schuiki parentScope.nest(pass->getThreadingSiblingOrThis(),
10733f908c4SFabian Schuiki [pass]() { return std::string(pass->getName()); }));
10833f908c4SFabian Schuiki }
10933f908c4SFabian Schuiki }
11033f908c4SFabian Schuiki
runAfterPass__anon2e0843fe0111::PassTiming11133f908c4SFabian Schuiki void runAfterPass(Pass *pass, Operation *) override {
11233f908c4SFabian Schuiki auto tid = llvm::get_threadid();
11333f908c4SFabian Schuiki if (isa<OpToOpPassAdaptor>(pass))
11433f908c4SFabian Schuiki parentTimerIndices.erase({tid, pass});
11533f908c4SFabian Schuiki auto &activeTimers = activeThreadTimers[tid];
116120509a6SRiver Riddle assert(!activeTimers.empty() && "expected active timer");
117120509a6SRiver Riddle activeTimers.pop_back();
118120509a6SRiver Riddle }
119120509a6SRiver Riddle
runAfterPassFailed__anon2e0843fe0111::PassTiming12033f908c4SFabian Schuiki void runAfterPassFailed(Pass *pass, Operation *op) override {
12133f908c4SFabian Schuiki runAfterPass(pass, op);
122e46ba31cSRiver Riddle }
123e46ba31cSRiver Riddle
12433f908c4SFabian Schuiki //===--------------------------------------------------------------------===//
12533f908c4SFabian Schuiki // Analysis
12633f908c4SFabian Schuiki //===--------------------------------------------------------------------===//
12733f908c4SFabian Schuiki
runBeforeAnalysis__anon2e0843fe0111::PassTiming12833f908c4SFabian Schuiki void runBeforeAnalysis(StringRef name, TypeID id, Operation *) override {
12933f908c4SFabian Schuiki auto tid = llvm::get_threadid();
13033f908c4SFabian Schuiki auto &activeTimers = activeThreadTimers[tid];
13133f908c4SFabian Schuiki auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
13233f908c4SFabian Schuiki activeTimers.push_back(parentScope.nest(
13333f908c4SFabian Schuiki id.getAsOpaquePointer(), [name] { return "(A) " + name.str(); }));
134e46ba31cSRiver Riddle }
135e46ba31cSRiver Riddle
runAfterAnalysis__anon2e0843fe0111::PassTiming13633f908c4SFabian Schuiki void runAfterAnalysis(StringRef, TypeID, Operation *) override {
13733f908c4SFabian Schuiki auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
13833f908c4SFabian Schuiki assert(!activeTimers.empty() && "expected active timer");
13933f908c4SFabian Schuiki activeTimers.pop_back();
1403a845be7SRiver Riddle }
141f65a3f7cSMehdi Amini };
14233f908c4SFabian Schuiki } // namespace
143f65a3f7cSMehdi Amini
1446558f80cSRiver Riddle //===----------------------------------------------------------------------===//
1456558f80cSRiver Riddle // PassManager
1466558f80cSRiver Riddle //===----------------------------------------------------------------------===//
1476558f80cSRiver Riddle
1486558f80cSRiver Riddle /// Add an instrumentation to time the execution of passes and the computation
1496558f80cSRiver Riddle /// of analyses.
enableTiming(TimingScope & timingScope)15033f908c4SFabian Schuiki void PassManager::enableTiming(TimingScope &timingScope) {
15133f908c4SFabian Schuiki if (!timingScope)
1526558f80cSRiver Riddle return;
15333f908c4SFabian Schuiki addInstrumentation(std::make_unique<PassTiming>(timingScope));
15433f908c4SFabian Schuiki }
15533f908c4SFabian Schuiki
15633f908c4SFabian Schuiki /// Add an instrumentation to time the execution of passes and the computation
15733f908c4SFabian Schuiki /// of analyses.
enableTiming(std::unique_ptr<TimingManager> tm)15833f908c4SFabian Schuiki void PassManager::enableTiming(std::unique_ptr<TimingManager> tm) {
15933f908c4SFabian Schuiki if (!tm->getRootTimer())
16033f908c4SFabian Schuiki return; // no need to keep the timing manager around if it's disabled
16133f908c4SFabian Schuiki addInstrumentation(std::make_unique<PassTiming>(std::move(tm)));
16233f908c4SFabian Schuiki }
16333f908c4SFabian Schuiki
16433f908c4SFabian Schuiki /// Add an instrumentation to time the execution of passes and the computation
16533f908c4SFabian Schuiki /// of analyses.
enableTiming()16633f908c4SFabian Schuiki void PassManager::enableTiming() {
16733f908c4SFabian Schuiki auto tm = std::make_unique<DefaultTimingManager>();
16833f908c4SFabian Schuiki tm->setEnabled(true);
16933f908c4SFabian Schuiki enableTiming(std::move(tm));
1706558f80cSRiver Riddle }
171