forked from OSchip/llvm-project
166 lines
6.3 KiB
C++
166 lines
6.3 KiB
C++
//===- PassTiming.cpp -----------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "PassDetail.h"
|
|
#include "mlir/Pass/PassManager.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/Support/Threading.h"
|
|
|
|
#include <chrono>
|
|
|
|
using namespace mlir;
|
|
using namespace mlir::detail;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// PassTiming
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
struct PassTiming : public PassInstrumentation {
|
|
PassTiming(TimingScope &timingScope) : rootScope(timingScope) {}
|
|
PassTiming(std::unique_ptr<TimingManager> tm)
|
|
: ownedTimingManager(std::move(tm)),
|
|
ownedTimingScope(ownedTimingManager->getRootScope()),
|
|
rootScope(ownedTimingScope) {}
|
|
|
|
/// If a pass can spawn additional work on other threads, it records the
|
|
/// index to its currently active timer here. Passes that run on a
|
|
/// newly-forked thread will check this list to find the active timer of the
|
|
/// parent thread into which the new thread should be nested.
|
|
DenseMap<PipelineParentInfo, unsigned> parentTimerIndices;
|
|
|
|
/// A stack of the currently active timing scopes per thread.
|
|
DenseMap<uint64_t, SmallVector<TimingScope, 4>> activeThreadTimers;
|
|
|
|
/// The timing manager owned by this instrumentation (in case timing was
|
|
/// enabled by the user on the pass manager without providing an external
|
|
/// timing manager). This *must* appear before the `ownedTimingScope` to
|
|
/// ensure the timing manager is destroyed *after* the scope, since the latter
|
|
/// may hold a timer that points into the former.
|
|
std::unique_ptr<TimingManager> ownedTimingManager;
|
|
TimingScope ownedTimingScope;
|
|
|
|
/// The root timing scope into which timing is reported.
|
|
TimingScope &rootScope;
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Pipeline
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
void runBeforePipeline(StringAttr name,
|
|
const PipelineParentInfo &parentInfo) override {
|
|
auto tid = llvm::get_threadid();
|
|
auto &activeTimers = activeThreadTimers[tid];
|
|
|
|
TimingScope *parentScope;
|
|
if (activeTimers.empty()) {
|
|
auto it = parentTimerIndices.find(parentInfo);
|
|
if (it != parentTimerIndices.end())
|
|
parentScope =
|
|
&activeThreadTimers[parentInfo.parentThreadID][it->second];
|
|
else
|
|
parentScope = &rootScope;
|
|
} else {
|
|
parentScope = &activeTimers.back();
|
|
}
|
|
activeTimers.push_back(parentScope->nest(name.getAsOpaquePointer(), [name] {
|
|
return ("'" + name.strref() + "' Pipeline").str();
|
|
}));
|
|
}
|
|
|
|
void runAfterPipeline(StringAttr, const PipelineParentInfo &) override {
|
|
auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
|
|
assert(!activeTimers.empty() && "expected active timer");
|
|
activeTimers.pop_back();
|
|
}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Pass
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
void runBeforePass(Pass *pass, Operation *) override {
|
|
auto tid = llvm::get_threadid();
|
|
auto &activeTimers = activeThreadTimers[tid];
|
|
auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
|
|
|
|
if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass)) {
|
|
parentTimerIndices[{tid, pass}] = activeTimers.size();
|
|
auto scope =
|
|
parentScope.nest(pass->getThreadingSiblingOrThis(),
|
|
[adaptor]() { return adaptor->getAdaptorName(); });
|
|
if (adaptor->getPassManagers().size() <= 1)
|
|
scope.hide();
|
|
activeTimers.push_back(std::move(scope));
|
|
} else {
|
|
activeTimers.push_back(
|
|
parentScope.nest(pass->getThreadingSiblingOrThis(),
|
|
[pass]() { return std::string(pass->getName()); }));
|
|
}
|
|
}
|
|
|
|
void runAfterPass(Pass *pass, Operation *) override {
|
|
auto tid = llvm::get_threadid();
|
|
if (isa<OpToOpPassAdaptor>(pass))
|
|
parentTimerIndices.erase({tid, pass});
|
|
auto &activeTimers = activeThreadTimers[tid];
|
|
assert(!activeTimers.empty() && "expected active timer");
|
|
activeTimers.pop_back();
|
|
}
|
|
|
|
void runAfterPassFailed(Pass *pass, Operation *op) override {
|
|
runAfterPass(pass, op);
|
|
}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Analysis
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
void runBeforeAnalysis(StringRef name, TypeID id, Operation *) override {
|
|
auto tid = llvm::get_threadid();
|
|
auto &activeTimers = activeThreadTimers[tid];
|
|
auto &parentScope = activeTimers.empty() ? rootScope : activeTimers.back();
|
|
activeTimers.push_back(parentScope.nest(
|
|
id.getAsOpaquePointer(), [name] { return "(A) " + name.str(); }));
|
|
}
|
|
|
|
void runAfterAnalysis(StringRef, TypeID, Operation *) override {
|
|
auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
|
|
assert(!activeTimers.empty() && "expected active timer");
|
|
activeTimers.pop_back();
|
|
}
|
|
};
|
|
} // namespace
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// PassManager
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// Add an instrumentation to time the execution of passes and the computation
|
|
/// of analyses.
|
|
void PassManager::enableTiming(TimingScope &timingScope) {
|
|
if (!timingScope)
|
|
return;
|
|
addInstrumentation(std::make_unique<PassTiming>(timingScope));
|
|
}
|
|
|
|
/// Add an instrumentation to time the execution of passes and the computation
|
|
/// of analyses.
|
|
void PassManager::enableTiming(std::unique_ptr<TimingManager> tm) {
|
|
if (!tm->getRootTimer())
|
|
return; // no need to keep the timing manager around if it's disabled
|
|
addInstrumentation(std::make_unique<PassTiming>(std::move(tm)));
|
|
}
|
|
|
|
/// Add an instrumentation to time the execution of passes and the computation
|
|
/// of analyses.
|
|
void PassManager::enableTiming() {
|
|
auto tm = std::make_unique<DefaultTimingManager>();
|
|
tm->setEnabled(true);
|
|
enableTiming(std::move(tm));
|
|
}
|