123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- //===- PassTimingInfo.cpp - LLVM Pass Timing Implementation ---------------===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements the LLVM Pass Timing infrastructure for both
- // new and legacy pass managers.
- //
- // PassTimingInfo Class - This class is used to calculate information about the
- // amount of time each pass takes to execute. This only happens when
- // -time-passes is enabled on the command line.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/IR/PassTimingInfo.h"
- #include "llvm/ADT/Statistic.h"
- #include "llvm/IR/PassInstrumentation.h"
- #include "llvm/Pass.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/FormatVariadic.h"
- #include "llvm/Support/ManagedStatic.h"
- #include "llvm/Support/Mutex.h"
- #include "llvm/Support/TypeName.h"
- #include "llvm/Support/raw_ostream.h"
- #include <string>
- using namespace llvm;
- #define DEBUG_TYPE "time-passes"
- namespace llvm {
- bool TimePassesIsEnabled = false;
- bool TimePassesPerRun = false;
- static cl::opt<bool, true> EnableTiming(
- "time-passes", cl::location(TimePassesIsEnabled), cl::Hidden,
- cl::desc("Time each pass, printing elapsed time for each on exit"));
- static cl::opt<bool, true> EnableTimingPerRun(
- "time-passes-per-run", cl::location(TimePassesPerRun), cl::Hidden,
- cl::desc("Time each pass run, printing elapsed time for each run on exit"),
- cl::callback([](const bool &) { TimePassesIsEnabled = true; }));
- namespace {
- namespace legacy {
- //===----------------------------------------------------------------------===//
- // Legacy pass manager's PassTimingInfo implementation
- /// Provides an interface for collecting pass timing information.
- ///
- /// It was intended to be generic but now we decided to split
- /// interfaces completely. This is now exclusively for legacy-pass-manager use.
- class PassTimingInfo {
- public:
- using PassInstanceID = void *;
- private:
- StringMap<unsigned> PassIDCountMap; ///< Map that counts instances of passes
- DenseMap<PassInstanceID, std::unique_ptr<Timer>> TimingData; ///< timers for pass instances
- TimerGroup TG;
- public:
- /// Default constructor for yet-inactive timeinfo.
- /// Use \p init() to activate it.
- PassTimingInfo();
- /// Print out timing information and release timers.
- ~PassTimingInfo();
- /// Initializes the static \p TheTimeInfo member to a non-null value when
- /// -time-passes is enabled. Leaves it null otherwise.
- ///
- /// This method may be called multiple times.
- static void init();
- /// Prints out timing information and then resets the timers.
- /// By default it uses the stream created by CreateInfoOutputFile().
- void print(raw_ostream *OutStream = nullptr);
- /// Returns the timer for the specified pass if it exists.
- Timer *getPassTimer(Pass *, PassInstanceID);
- static PassTimingInfo *TheTimeInfo;
- private:
- Timer *newPassTimer(StringRef PassID, StringRef PassDesc);
- };
- static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex;
- PassTimingInfo::PassTimingInfo() : TG("pass", "Pass execution timing report") {}
- PassTimingInfo::~PassTimingInfo() {
- // Deleting the timers accumulates their info into the TG member.
- // Then TG member is (implicitly) deleted, actually printing the report.
- TimingData.clear();
- }
- void PassTimingInfo::init() {
- if (!TimePassesIsEnabled || TheTimeInfo)
- return;
- // Constructed the first time this is called, iff -time-passes is enabled.
- // This guarantees that the object will be constructed after static globals,
- // thus it will be destroyed before them.
- static ManagedStatic<PassTimingInfo> TTI;
- TheTimeInfo = &*TTI;
- }
- /// Prints out timing information and then resets the timers.
- void PassTimingInfo::print(raw_ostream *OutStream) {
- TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
- }
- Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
- unsigned &num = PassIDCountMap[PassID];
- num++;
- // Appending description with a pass-instance number for all but the first one
- std::string PassDescNumbered =
- num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
- return new Timer(PassID, PassDescNumbered, TG);
- }
- Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
- if (P->getAsPMDataManager())
- return nullptr;
- init();
- sys::SmartScopedLock<true> Lock(*TimingInfoMutex);
- std::unique_ptr<Timer> &T = TimingData[Pass];
- if (!T) {
- StringRef PassName = P->getPassName();
- StringRef PassArgument;
- if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID()))
- PassArgument = PI->getPassArgument();
- T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName));
- }
- return T.get();
- }
- PassTimingInfo *PassTimingInfo::TheTimeInfo;
- } // namespace legacy
- } // namespace
- Timer *getPassTimer(Pass *P) {
- legacy::PassTimingInfo::init();
- if (legacy::PassTimingInfo::TheTimeInfo)
- return legacy::PassTimingInfo::TheTimeInfo->getPassTimer(P, P);
- return nullptr;
- }
- /// If timing is enabled, report the times collected up to now and then reset
- /// them.
- void reportAndResetTimings(raw_ostream *OutStream) {
- if (legacy::PassTimingInfo::TheTimeInfo)
- legacy::PassTimingInfo::TheTimeInfo->print(OutStream);
- }
- //===----------------------------------------------------------------------===//
- // Pass timing handling for the New Pass Manager
- //===----------------------------------------------------------------------===//
- /// Returns the timer for the specified pass invocation of \p PassID.
- /// Each time it creates a new timer.
- Timer &TimePassesHandler::getPassTimer(StringRef PassID, bool IsPass) {
- TimerGroup &TG = IsPass ? PassTG : AnalysisTG;
- if (!PerRun) {
- TimerVector &Timers = TimingData[PassID];
- if (Timers.size() == 0)
- Timers.emplace_back(new Timer(PassID, PassID, TG));
- return *Timers.front();
- }
- // Take a vector of Timers created for this \p PassID and append
- // one more timer to it.
- TimerVector &Timers = TimingData[PassID];
- unsigned Count = Timers.size() + 1;
- std::string FullDesc = formatv("{0} #{1}", PassID, Count).str();
- Timer *T = new Timer(PassID, FullDesc, TG);
- Timers.emplace_back(T);
- assert(Count == Timers.size() && "Timers vector not adjusted correctly.");
- return *T;
- }
- TimePassesHandler::TimePassesHandler(bool Enabled, bool PerRun)
- : PassTG("pass", "Pass execution timing report"),
- AnalysisTG("analysis", "Analysis execution timing report"),
- Enabled(Enabled), PerRun(PerRun) {}
- TimePassesHandler::TimePassesHandler()
- : TimePassesHandler(TimePassesIsEnabled, TimePassesPerRun) {}
- void TimePassesHandler::setOutStream(raw_ostream &Out) {
- OutStream = &Out;
- }
- void TimePassesHandler::print() {
- if (!Enabled)
- return;
- std::unique_ptr<raw_ostream> MaybeCreated;
- raw_ostream *OS = OutStream;
- if (OutStream) {
- OS = OutStream;
- } else {
- MaybeCreated = CreateInfoOutputFile();
- OS = &*MaybeCreated;
- }
- PassTG.print(*OS, true);
- AnalysisTG.print(*OS, true);
- }
- LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
- dbgs() << "Dumping timers for " << getTypeName<TimePassesHandler>()
- << ":\n\tRunning:\n";
- for (auto &I : TimingData) {
- StringRef PassID = I.getKey();
- const TimerVector& MyTimers = I.getValue();
- for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
- const Timer* MyTimer = MyTimers[idx].get();
- if (MyTimer && MyTimer->isRunning())
- dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
- }
- }
- dbgs() << "\tTriggered:\n";
- for (auto &I : TimingData) {
- StringRef PassID = I.getKey();
- const TimerVector& MyTimers = I.getValue();
- for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
- const Timer* MyTimer = MyTimers[idx].get();
- if (MyTimer && MyTimer->hasTriggered() && !MyTimer->isRunning())
- dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
- }
- }
- }
- static bool shouldIgnorePass(StringRef PassID) {
- return isSpecialPass(PassID,
- {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
- "ModuleInlinerWrapperPass", "DevirtSCCRepeatedPass"});
- }
- void TimePassesHandler::startPassTimer(StringRef PassID) {
- if (shouldIgnorePass(PassID))
- return;
- assert(!ActivePassTimer && "should only have one pass timer at a time");
- Timer &MyTimer = getPassTimer(PassID, /*IsPass*/ true);
- ActivePassTimer = &MyTimer;
- assert(!MyTimer.isRunning());
- MyTimer.startTimer();
- }
- void TimePassesHandler::stopPassTimer(StringRef PassID) {
- if (shouldIgnorePass(PassID))
- return;
- assert(ActivePassTimer);
- assert(ActivePassTimer->isRunning());
- ActivePassTimer->stopTimer();
- ActivePassTimer = nullptr;
- }
- void TimePassesHandler::startAnalysisTimer(StringRef PassID) {
- // Stop the previous analysis timer to prevent double counting when an
- // analysis requests another analysis.
- if (!AnalysisActiveTimerStack.empty()) {
- assert(AnalysisActiveTimerStack.back()->isRunning());
- AnalysisActiveTimerStack.back()->stopTimer();
- }
- Timer &MyTimer = getPassTimer(PassID, /*IsPass*/ false);
- AnalysisActiveTimerStack.push_back(&MyTimer);
- if (!MyTimer.isRunning())
- MyTimer.startTimer();
- }
- void TimePassesHandler::stopAnalysisTimer(StringRef PassID) {
- assert(!AnalysisActiveTimerStack.empty() && "empty stack in popTimer");
- Timer *MyTimer = AnalysisActiveTimerStack.pop_back_val();
- assert(MyTimer && "timer should be present");
- if (MyTimer->isRunning())
- MyTimer->stopTimer();
- // Restart the previously stopped timer.
- if (!AnalysisActiveTimerStack.empty()) {
- assert(!AnalysisActiveTimerStack.back()->isRunning());
- AnalysisActiveTimerStack.back()->startTimer();
- }
- }
- void TimePassesHandler::registerCallbacks(PassInstrumentationCallbacks &PIC) {
- if (!Enabled)
- return;
- PIC.registerBeforeNonSkippedPassCallback(
- [this](StringRef P, Any) { this->startPassTimer(P); });
- PIC.registerAfterPassCallback(
- [this](StringRef P, Any, const PreservedAnalyses &) {
- this->stopPassTimer(P);
- });
- PIC.registerAfterPassInvalidatedCallback(
- [this](StringRef P, const PreservedAnalyses &) {
- this->stopPassTimer(P);
- });
- PIC.registerBeforeAnalysisCallback(
- [this](StringRef P, Any) { this->startAnalysisTimer(P); });
- PIC.registerAfterAnalysisCallback(
- [this](StringRef P, Any) { this->stopAnalysisTimer(P); });
- }
- } // namespace llvm
|