xref: /freebsd/contrib/llvm-project/llvm/lib/IR/PassTimingInfo.cpp (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
10b57cec5SDimitry Andric //===- PassTimingInfo.cpp - LLVM Pass Timing Implementation ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the LLVM Pass Timing infrastructure for both
100b57cec5SDimitry Andric // new and legacy pass managers.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric // PassTimingInfo Class - This class is used to calculate information about the
130b57cec5SDimitry Andric // amount of time each pass takes to execute.  This only happens when
140b57cec5SDimitry Andric // -time-passes is enabled on the command line.
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "llvm/IR/PassTimingInfo.h"
190b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
200b57cec5SDimitry Andric #include "llvm/IR/PassInstrumentation.h"
210b57cec5SDimitry Andric #include "llvm/Pass.h"
220b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
230b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
240b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
250b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h"
260b57cec5SDimitry Andric #include "llvm/Support/Mutex.h"
27*e8d8bef9SDimitry Andric #include "llvm/Support/TypeName.h"
280b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
290b57cec5SDimitry Andric #include <string>
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace llvm;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric #define DEBUG_TYPE "time-passes"
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric namespace llvm {
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric bool TimePassesIsEnabled = false;
38*e8d8bef9SDimitry Andric bool TimePassesPerRun = false;
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric static cl::opt<bool, true> EnableTiming(
410b57cec5SDimitry Andric     "time-passes", cl::location(TimePassesIsEnabled), cl::Hidden,
420b57cec5SDimitry Andric     cl::desc("Time each pass, printing elapsed time for each on exit"));
430b57cec5SDimitry Andric 
44*e8d8bef9SDimitry Andric static cl::opt<bool, true> EnableTimingPerRun(
45*e8d8bef9SDimitry Andric     "time-passes-per-run", cl::location(TimePassesPerRun), cl::Hidden,
46*e8d8bef9SDimitry Andric     cl::desc("Time each pass run, printing elapsed time for each run on exit"),
47*e8d8bef9SDimitry Andric     cl::callback([](const bool &) { TimePassesIsEnabled = true; }));
48*e8d8bef9SDimitry Andric 
490b57cec5SDimitry Andric namespace {
500b57cec5SDimitry Andric namespace legacy {
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
530b57cec5SDimitry Andric // Legacy pass manager's PassTimingInfo implementation
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric /// Provides an interface for collecting pass timing information.
560b57cec5SDimitry Andric ///
570b57cec5SDimitry Andric /// It was intended to be generic but now we decided to split
580b57cec5SDimitry Andric /// interfaces completely. This is now exclusively for legacy-pass-manager use.
590b57cec5SDimitry Andric class PassTimingInfo {
600b57cec5SDimitry Andric public:
610b57cec5SDimitry Andric   using PassInstanceID = void *;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric private:
640b57cec5SDimitry Andric   StringMap<unsigned> PassIDCountMap; ///< Map that counts instances of passes
650b57cec5SDimitry Andric   DenseMap<PassInstanceID, std::unique_ptr<Timer>> TimingData; ///< timers for pass instances
660b57cec5SDimitry Andric   TimerGroup TG;
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric public:
690b57cec5SDimitry Andric   /// Default constructor for yet-inactive timeinfo.
700b57cec5SDimitry Andric   /// Use \p init() to activate it.
710b57cec5SDimitry Andric   PassTimingInfo();
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   /// Print out timing information and release timers.
740b57cec5SDimitry Andric   ~PassTimingInfo();
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   /// Initializes the static \p TheTimeInfo member to a non-null value when
770b57cec5SDimitry Andric   /// -time-passes is enabled. Leaves it null otherwise.
780b57cec5SDimitry Andric   ///
790b57cec5SDimitry Andric   /// This method may be called multiple times.
800b57cec5SDimitry Andric   static void init();
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   /// Prints out timing information and then resets the timers.
830b57cec5SDimitry Andric   /// By default it uses the stream created by CreateInfoOutputFile().
840b57cec5SDimitry Andric   void print(raw_ostream *OutStream = nullptr);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   /// Returns the timer for the specified pass if it exists.
870b57cec5SDimitry Andric   Timer *getPassTimer(Pass *, PassInstanceID);
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   static PassTimingInfo *TheTimeInfo;
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric private:
920b57cec5SDimitry Andric   Timer *newPassTimer(StringRef PassID, StringRef PassDesc);
930b57cec5SDimitry Andric };
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex;
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric PassTimingInfo::PassTimingInfo()
980b57cec5SDimitry Andric     : TG("pass", "... Pass execution timing report ...") {}
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric PassTimingInfo::~PassTimingInfo() {
1010b57cec5SDimitry Andric   // Deleting the timers accumulates their info into the TG member.
1020b57cec5SDimitry Andric   // Then TG member is (implicitly) deleted, actually printing the report.
1030b57cec5SDimitry Andric   TimingData.clear();
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric void PassTimingInfo::init() {
1070b57cec5SDimitry Andric   if (!TimePassesIsEnabled || TheTimeInfo)
1080b57cec5SDimitry Andric     return;
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   // Constructed the first time this is called, iff -time-passes is enabled.
1110b57cec5SDimitry Andric   // This guarantees that the object will be constructed after static globals,
1120b57cec5SDimitry Andric   // thus it will be destroyed before them.
1130b57cec5SDimitry Andric   static ManagedStatic<PassTimingInfo> TTI;
1140b57cec5SDimitry Andric   TheTimeInfo = &*TTI;
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric /// Prints out timing information and then resets the timers.
1180b57cec5SDimitry Andric void PassTimingInfo::print(raw_ostream *OutStream) {
1190b57cec5SDimitry Andric   TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
1230b57cec5SDimitry Andric   unsigned &num = PassIDCountMap[PassID];
1240b57cec5SDimitry Andric   num++;
1250b57cec5SDimitry Andric   // Appending description with a pass-instance number for all but the first one
1260b57cec5SDimitry Andric   std::string PassDescNumbered =
1270b57cec5SDimitry Andric       num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
1280b57cec5SDimitry Andric   return new Timer(PassID, PassDescNumbered, TG);
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
1320b57cec5SDimitry Andric   if (P->getAsPMDataManager())
1330b57cec5SDimitry Andric     return nullptr;
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   init();
1360b57cec5SDimitry Andric   sys::SmartScopedLock<true> Lock(*TimingInfoMutex);
1370b57cec5SDimitry Andric   std::unique_ptr<Timer> &T = TimingData[Pass];
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   if (!T) {
1400b57cec5SDimitry Andric     StringRef PassName = P->getPassName();
1410b57cec5SDimitry Andric     StringRef PassArgument;
1420b57cec5SDimitry Andric     if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID()))
1430b57cec5SDimitry Andric       PassArgument = PI->getPassArgument();
1440b57cec5SDimitry Andric     T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName));
1450b57cec5SDimitry Andric   }
1460b57cec5SDimitry Andric   return T.get();
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric PassTimingInfo *PassTimingInfo::TheTimeInfo;
1500b57cec5SDimitry Andric } // namespace legacy
1510b57cec5SDimitry Andric } // namespace
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric Timer *getPassTimer(Pass *P) {
1540b57cec5SDimitry Andric   legacy::PassTimingInfo::init();
1550b57cec5SDimitry Andric   if (legacy::PassTimingInfo::TheTimeInfo)
1560b57cec5SDimitry Andric     return legacy::PassTimingInfo::TheTimeInfo->getPassTimer(P, P);
1570b57cec5SDimitry Andric   return nullptr;
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric /// If timing is enabled, report the times collected up to now and then reset
1610b57cec5SDimitry Andric /// them.
1620b57cec5SDimitry Andric void reportAndResetTimings(raw_ostream *OutStream) {
1630b57cec5SDimitry Andric   if (legacy::PassTimingInfo::TheTimeInfo)
1640b57cec5SDimitry Andric     legacy::PassTimingInfo::TheTimeInfo->print(OutStream);
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1680b57cec5SDimitry Andric // Pass timing handling for the New Pass Manager
1690b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric /// Returns the timer for the specified pass invocation of \p PassID.
1720b57cec5SDimitry Andric /// Each time it creates a new timer.
1730b57cec5SDimitry Andric Timer &TimePassesHandler::getPassTimer(StringRef PassID) {
174*e8d8bef9SDimitry Andric   if (!PerRun) {
175*e8d8bef9SDimitry Andric     TimerVector &Timers = TimingData[PassID];
176*e8d8bef9SDimitry Andric     if (Timers.size() == 0)
177*e8d8bef9SDimitry Andric       Timers.emplace_back(new Timer(PassID, PassID, TG));
178*e8d8bef9SDimitry Andric     return *Timers.front();
179*e8d8bef9SDimitry Andric   }
180*e8d8bef9SDimitry Andric 
1815ffd83dbSDimitry Andric   // Take a vector of Timers created for this \p PassID and append
1825ffd83dbSDimitry Andric   // one more timer to it.
1835ffd83dbSDimitry Andric   TimerVector &Timers = TimingData[PassID];
1845ffd83dbSDimitry Andric   unsigned Count = Timers.size() + 1;
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric   std::string FullDesc = formatv("{0} #{1}", PassID, Count).str();
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   Timer *T = new Timer(PassID, FullDesc, TG);
1895ffd83dbSDimitry Andric   Timers.emplace_back(T);
1905ffd83dbSDimitry Andric   assert(Count == Timers.size() && "sanity check");
1915ffd83dbSDimitry Andric 
1925ffd83dbSDimitry Andric   return *T;
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
195*e8d8bef9SDimitry Andric TimePassesHandler::TimePassesHandler(bool Enabled, bool PerRun)
196*e8d8bef9SDimitry Andric     : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled),
197*e8d8bef9SDimitry Andric       PerRun(PerRun) {}
198*e8d8bef9SDimitry Andric 
199*e8d8bef9SDimitry Andric TimePassesHandler::TimePassesHandler()
200*e8d8bef9SDimitry Andric     : TimePassesHandler(TimePassesIsEnabled, TimePassesPerRun) {}
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric void TimePassesHandler::setOutStream(raw_ostream &Out) {
2030b57cec5SDimitry Andric   OutStream = &Out;
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric void TimePassesHandler::print() {
2070b57cec5SDimitry Andric   if (!Enabled)
2080b57cec5SDimitry Andric     return;
2090b57cec5SDimitry Andric   TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
2100b57cec5SDimitry Andric }
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
2130b57cec5SDimitry Andric   dbgs() << "Dumping timers for " << getTypeName<TimePassesHandler>()
2140b57cec5SDimitry Andric          << ":\n\tRunning:\n";
2150b57cec5SDimitry Andric   for (auto &I : TimingData) {
2165ffd83dbSDimitry Andric     StringRef PassID = I.getKey();
2175ffd83dbSDimitry Andric     const TimerVector& MyTimers = I.getValue();
2185ffd83dbSDimitry Andric     for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
2195ffd83dbSDimitry Andric       const Timer* MyTimer = MyTimers[idx].get();
2205ffd83dbSDimitry Andric       if (MyTimer && MyTimer->isRunning())
2215ffd83dbSDimitry Andric         dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
2225ffd83dbSDimitry Andric     }
2230b57cec5SDimitry Andric   }
2240b57cec5SDimitry Andric   dbgs() << "\tTriggered:\n";
2250b57cec5SDimitry Andric   for (auto &I : TimingData) {
2265ffd83dbSDimitry Andric     StringRef PassID = I.getKey();
2275ffd83dbSDimitry Andric     const TimerVector& MyTimers = I.getValue();
2285ffd83dbSDimitry Andric     for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
2295ffd83dbSDimitry Andric       const Timer* MyTimer = MyTimers[idx].get();
2305ffd83dbSDimitry Andric       if (MyTimer && MyTimer->hasTriggered() && !MyTimer->isRunning())
2315ffd83dbSDimitry Andric         dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
2325ffd83dbSDimitry Andric     }
2330b57cec5SDimitry Andric   }
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric void TimePassesHandler::startTimer(StringRef PassID) {
2370b57cec5SDimitry Andric   Timer &MyTimer = getPassTimer(PassID);
2380b57cec5SDimitry Andric   TimerStack.push_back(&MyTimer);
2390b57cec5SDimitry Andric   if (!MyTimer.isRunning())
2400b57cec5SDimitry Andric     MyTimer.startTimer();
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric void TimePassesHandler::stopTimer(StringRef PassID) {
2440b57cec5SDimitry Andric   assert(TimerStack.size() > 0 && "empty stack in popTimer");
2450b57cec5SDimitry Andric   Timer *MyTimer = TimerStack.pop_back_val();
2460b57cec5SDimitry Andric   assert(MyTimer && "timer should be present");
2470b57cec5SDimitry Andric   if (MyTimer->isRunning())
2480b57cec5SDimitry Andric     MyTimer->stopTimer();
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
251*e8d8bef9SDimitry Andric void TimePassesHandler::runBeforePass(StringRef PassID) {
252*e8d8bef9SDimitry Andric   if (isSpecialPass(PassID,
253*e8d8bef9SDimitry Andric                     {"PassManager", "PassAdaptor", "AnalysisManagerProxy"}))
254*e8d8bef9SDimitry Andric     return;
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   startTimer(PassID);
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "after runBeforePass(" << PassID << ")\n");
2590b57cec5SDimitry Andric   LLVM_DEBUG(dump());
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric void TimePassesHandler::runAfterPass(StringRef PassID) {
263*e8d8bef9SDimitry Andric   if (isSpecialPass(PassID,
264*e8d8bef9SDimitry Andric                     {"PassManager", "PassAdaptor", "AnalysisManagerProxy"}))
2650b57cec5SDimitry Andric     return;
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric   stopTimer(PassID);
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "after runAfterPass(" << PassID << ")\n");
2700b57cec5SDimitry Andric   LLVM_DEBUG(dump());
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric void TimePassesHandler::registerCallbacks(PassInstrumentationCallbacks &PIC) {
2740b57cec5SDimitry Andric   if (!Enabled)
2750b57cec5SDimitry Andric     return;
2760b57cec5SDimitry Andric 
277*e8d8bef9SDimitry Andric   PIC.registerBeforeNonSkippedPassCallback(
278*e8d8bef9SDimitry Andric       [this](StringRef P, Any) { this->runBeforePass(P); });
2790b57cec5SDimitry Andric   PIC.registerAfterPassCallback(
280*e8d8bef9SDimitry Andric       [this](StringRef P, Any, const PreservedAnalyses &) {
281*e8d8bef9SDimitry Andric         this->runAfterPass(P);
282*e8d8bef9SDimitry Andric       });
2830b57cec5SDimitry Andric   PIC.registerAfterPassInvalidatedCallback(
284*e8d8bef9SDimitry Andric       [this](StringRef P, const PreservedAnalyses &) {
285*e8d8bef9SDimitry Andric         this->runAfterPass(P);
286*e8d8bef9SDimitry Andric       });
2870b57cec5SDimitry Andric   PIC.registerBeforeAnalysisCallback(
2880b57cec5SDimitry Andric       [this](StringRef P, Any) { this->runBeforePass(P); });
2890b57cec5SDimitry Andric   PIC.registerAfterAnalysisCallback(
2900b57cec5SDimitry Andric       [this](StringRef P, Any) { this->runAfterPass(P); });
2910b57cec5SDimitry Andric }
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric } // namespace llvm
294