#include "PassDetail.h"
#include "mlir/Pass/PassManager.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Threading.h"
#include <chrono>
#include <optional>
using namespace mlir;
using namespace mlir::detail;
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) {}
DenseMap<PipelineParentInfo, unsigned> parentTimerIndices;
DenseMap<uint64_t, SmallVector<TimingScope, 4>> activeThreadTimers;
std::unique_ptr<TimingManager> ownedTimingManager;
TimingScope ownedTimingScope;
TimingScope &rootScope;
void runBeforePipeline(std::optional<OperationName> name,
const PipelineParentInfo &parentInfo) override {
auto tid = llvm::get_threadid();
auto &activeTimers = activeThreadTimers[tid];
TimingScope *parentScope;
auto it = parentTimerIndices.find(parentInfo);
if (it != parentTimerIndices.end())
parentScope = &activeThreadTimers[parentInfo.parentThreadID][it->second];
else
parentScope = &rootScope;
const void *timerId = name ? name->getAsOpaquePointer() : nullptr;
activeTimers.push_back(parentScope->nest(timerId, [name] {
return ("'" + (name ? name->getStringRef() : "any") + "' Pipeline").str();
}));
}
void runAfterPipeline(std::optional<OperationName>,
const PipelineParentInfo &) override {
auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
assert(!activeTimers.empty() && "expected active timer");
activeTimers.pop_back();
}
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);
}
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();
}
};
}
void PassManager::enableTiming(TimingScope &timingScope) {
if (!timingScope)
return;
addInstrumentation(std::make_unique<PassTiming>(timingScope));
}
void PassManager::enableTiming(std::unique_ptr<TimingManager> tm) {
if (!tm->getRootTimer())
return;
addInstrumentation(std::make_unique<PassTiming>(std::move(tm)));
}
void PassManager::enableTiming() {
auto tm = std::make_unique<DefaultTimingManager>();
tm->setEnabled(true);
enableTiming(std::move(tm));
}