xref: /freebsd/contrib/llvm-project/llvm/lib/IR/PassTimingInfo.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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/DenseMap.h"
200b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
210b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
220b57cec5SDimitry Andric #include "llvm/IR/PassInstrumentation.h"
230b57cec5SDimitry Andric #include "llvm/Pass.h"
240b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
250b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
260b57cec5SDimitry Andric #include "llvm/Support/FormatVariadic.h"
270b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h"
280b57cec5SDimitry Andric #include "llvm/Support/Mutex.h"
290b57cec5SDimitry Andric #include "llvm/Support/Timer.h"
300b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
310b57cec5SDimitry Andric #include <memory>
320b57cec5SDimitry Andric #include <string>
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric using namespace llvm;
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric #define DEBUG_TYPE "time-passes"
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric namespace llvm {
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric bool TimePassesIsEnabled = false;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric static cl::opt<bool, true> EnableTiming(
430b57cec5SDimitry Andric     "time-passes", cl::location(TimePassesIsEnabled), cl::Hidden,
440b57cec5SDimitry Andric     cl::desc("Time each pass, printing elapsed time for each on exit"));
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric namespace {
470b57cec5SDimitry Andric namespace legacy {
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
500b57cec5SDimitry Andric // Legacy pass manager's PassTimingInfo implementation
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric /// Provides an interface for collecting pass timing information.
530b57cec5SDimitry Andric ///
540b57cec5SDimitry Andric /// It was intended to be generic but now we decided to split
550b57cec5SDimitry Andric /// interfaces completely. This is now exclusively for legacy-pass-manager use.
560b57cec5SDimitry Andric class PassTimingInfo {
570b57cec5SDimitry Andric public:
580b57cec5SDimitry Andric   using PassInstanceID = void *;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric private:
610b57cec5SDimitry Andric   StringMap<unsigned> PassIDCountMap; ///< Map that counts instances of passes
620b57cec5SDimitry Andric   DenseMap<PassInstanceID, std::unique_ptr<Timer>> TimingData; ///< timers for pass instances
630b57cec5SDimitry Andric   TimerGroup TG;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric public:
660b57cec5SDimitry Andric   /// Default constructor for yet-inactive timeinfo.
670b57cec5SDimitry Andric   /// Use \p init() to activate it.
680b57cec5SDimitry Andric   PassTimingInfo();
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric   /// Print out timing information and release timers.
710b57cec5SDimitry Andric   ~PassTimingInfo();
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   /// Initializes the static \p TheTimeInfo member to a non-null value when
740b57cec5SDimitry Andric   /// -time-passes is enabled. Leaves it null otherwise.
750b57cec5SDimitry Andric   ///
760b57cec5SDimitry Andric   /// This method may be called multiple times.
770b57cec5SDimitry Andric   static void init();
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   /// Prints out timing information and then resets the timers.
800b57cec5SDimitry Andric   /// By default it uses the stream created by CreateInfoOutputFile().
810b57cec5SDimitry Andric   void print(raw_ostream *OutStream = nullptr);
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   /// Returns the timer for the specified pass if it exists.
840b57cec5SDimitry Andric   Timer *getPassTimer(Pass *, PassInstanceID);
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   static PassTimingInfo *TheTimeInfo;
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric private:
890b57cec5SDimitry Andric   Timer *newPassTimer(StringRef PassID, StringRef PassDesc);
900b57cec5SDimitry Andric };
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex;
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric PassTimingInfo::PassTimingInfo()
950b57cec5SDimitry Andric     : TG("pass", "... Pass execution timing report ...") {}
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric PassTimingInfo::~PassTimingInfo() {
980b57cec5SDimitry Andric   // Deleting the timers accumulates their info into the TG member.
990b57cec5SDimitry Andric   // Then TG member is (implicitly) deleted, actually printing the report.
1000b57cec5SDimitry Andric   TimingData.clear();
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric void PassTimingInfo::init() {
1040b57cec5SDimitry Andric   if (!TimePassesIsEnabled || TheTimeInfo)
1050b57cec5SDimitry Andric     return;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   // Constructed the first time this is called, iff -time-passes is enabled.
1080b57cec5SDimitry Andric   // This guarantees that the object will be constructed after static globals,
1090b57cec5SDimitry Andric   // thus it will be destroyed before them.
1100b57cec5SDimitry Andric   static ManagedStatic<PassTimingInfo> TTI;
1110b57cec5SDimitry Andric   TheTimeInfo = &*TTI;
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric /// Prints out timing information and then resets the timers.
1150b57cec5SDimitry Andric void PassTimingInfo::print(raw_ostream *OutStream) {
1160b57cec5SDimitry Andric   TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
1200b57cec5SDimitry Andric   unsigned &num = PassIDCountMap[PassID];
1210b57cec5SDimitry Andric   num++;
1220b57cec5SDimitry Andric   // Appending description with a pass-instance number for all but the first one
1230b57cec5SDimitry Andric   std::string PassDescNumbered =
1240b57cec5SDimitry Andric       num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
1250b57cec5SDimitry Andric   return new Timer(PassID, PassDescNumbered, TG);
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
1290b57cec5SDimitry Andric   if (P->getAsPMDataManager())
1300b57cec5SDimitry Andric     return nullptr;
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric   init();
1330b57cec5SDimitry Andric   sys::SmartScopedLock<true> Lock(*TimingInfoMutex);
1340b57cec5SDimitry Andric   std::unique_ptr<Timer> &T = TimingData[Pass];
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric   if (!T) {
1370b57cec5SDimitry Andric     StringRef PassName = P->getPassName();
1380b57cec5SDimitry Andric     StringRef PassArgument;
1390b57cec5SDimitry Andric     if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID()))
1400b57cec5SDimitry Andric       PassArgument = PI->getPassArgument();
1410b57cec5SDimitry Andric     T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName));
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric   return T.get();
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric PassTimingInfo *PassTimingInfo::TheTimeInfo;
1470b57cec5SDimitry Andric } // namespace legacy
1480b57cec5SDimitry Andric } // namespace
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric Timer *getPassTimer(Pass *P) {
1510b57cec5SDimitry Andric   legacy::PassTimingInfo::init();
1520b57cec5SDimitry Andric   if (legacy::PassTimingInfo::TheTimeInfo)
1530b57cec5SDimitry Andric     return legacy::PassTimingInfo::TheTimeInfo->getPassTimer(P, P);
1540b57cec5SDimitry Andric   return nullptr;
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric /// If timing is enabled, report the times collected up to now and then reset
1580b57cec5SDimitry Andric /// them.
1590b57cec5SDimitry Andric void reportAndResetTimings(raw_ostream *OutStream) {
1600b57cec5SDimitry Andric   if (legacy::PassTimingInfo::TheTimeInfo)
1610b57cec5SDimitry Andric     legacy::PassTimingInfo::TheTimeInfo->print(OutStream);
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1650b57cec5SDimitry Andric // Pass timing handling for the New Pass Manager
1660b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric /// Returns the timer for the specified pass invocation of \p PassID.
1690b57cec5SDimitry Andric /// Each time it creates a new timer.
1700b57cec5SDimitry Andric Timer &TimePassesHandler::getPassTimer(StringRef PassID) {
171*5ffd83dbSDimitry Andric   // Take a vector of Timers created for this \p PassID and append
172*5ffd83dbSDimitry Andric   // one more timer to it.
173*5ffd83dbSDimitry Andric   TimerVector &Timers = TimingData[PassID];
174*5ffd83dbSDimitry Andric   unsigned Count = Timers.size() + 1;
1750b57cec5SDimitry Andric 
1760b57cec5SDimitry Andric   std::string FullDesc = formatv("{0} #{1}", PassID, Count).str();
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric   Timer *T = new Timer(PassID, FullDesc, TG);
179*5ffd83dbSDimitry Andric   Timers.emplace_back(T);
180*5ffd83dbSDimitry Andric   assert(Count == Timers.size() && "sanity check");
181*5ffd83dbSDimitry Andric 
182*5ffd83dbSDimitry Andric   return *T;
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric TimePassesHandler::TimePassesHandler(bool Enabled)
1860b57cec5SDimitry Andric     : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled) {}
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric void TimePassesHandler::setOutStream(raw_ostream &Out) {
1890b57cec5SDimitry Andric   OutStream = &Out;
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric void TimePassesHandler::print() {
1930b57cec5SDimitry Andric   if (!Enabled)
1940b57cec5SDimitry Andric     return;
1950b57cec5SDimitry Andric   TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
1990b57cec5SDimitry Andric   dbgs() << "Dumping timers for " << getTypeName<TimePassesHandler>()
2000b57cec5SDimitry Andric          << ":\n\tRunning:\n";
2010b57cec5SDimitry Andric   for (auto &I : TimingData) {
202*5ffd83dbSDimitry Andric     StringRef PassID = I.getKey();
203*5ffd83dbSDimitry Andric     const TimerVector& MyTimers = I.getValue();
204*5ffd83dbSDimitry Andric     for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
205*5ffd83dbSDimitry Andric       const Timer* MyTimer = MyTimers[idx].get();
206*5ffd83dbSDimitry Andric       if (MyTimer && MyTimer->isRunning())
207*5ffd83dbSDimitry Andric         dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
208*5ffd83dbSDimitry Andric     }
2090b57cec5SDimitry Andric   }
2100b57cec5SDimitry Andric   dbgs() << "\tTriggered:\n";
2110b57cec5SDimitry Andric   for (auto &I : TimingData) {
212*5ffd83dbSDimitry Andric     StringRef PassID = I.getKey();
213*5ffd83dbSDimitry Andric     const TimerVector& MyTimers = I.getValue();
214*5ffd83dbSDimitry Andric     for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
215*5ffd83dbSDimitry Andric       const Timer* MyTimer = MyTimers[idx].get();
216*5ffd83dbSDimitry Andric       if (MyTimer && MyTimer->hasTriggered() && !MyTimer->isRunning())
217*5ffd83dbSDimitry Andric         dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
218*5ffd83dbSDimitry Andric     }
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric void TimePassesHandler::startTimer(StringRef PassID) {
2230b57cec5SDimitry Andric   Timer &MyTimer = getPassTimer(PassID);
2240b57cec5SDimitry Andric   TimerStack.push_back(&MyTimer);
2250b57cec5SDimitry Andric   if (!MyTimer.isRunning())
2260b57cec5SDimitry Andric     MyTimer.startTimer();
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric void TimePassesHandler::stopTimer(StringRef PassID) {
2300b57cec5SDimitry Andric   assert(TimerStack.size() > 0 && "empty stack in popTimer");
2310b57cec5SDimitry Andric   Timer *MyTimer = TimerStack.pop_back_val();
2320b57cec5SDimitry Andric   assert(MyTimer && "timer should be present");
2330b57cec5SDimitry Andric   if (MyTimer->isRunning())
2340b57cec5SDimitry Andric     MyTimer->stopTimer();
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric static bool matchPassManager(StringRef PassID) {
2380b57cec5SDimitry Andric   size_t prefix_pos = PassID.find('<');
2390b57cec5SDimitry Andric   if (prefix_pos == StringRef::npos)
2400b57cec5SDimitry Andric     return false;
2410b57cec5SDimitry Andric   StringRef Prefix = PassID.substr(0, prefix_pos);
2420b57cec5SDimitry Andric   return Prefix.endswith("PassManager") || Prefix.endswith("PassAdaptor") ||
2430b57cec5SDimitry Andric          Prefix.endswith("AnalysisManagerProxy");
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric bool TimePassesHandler::runBeforePass(StringRef PassID) {
2470b57cec5SDimitry Andric   if (matchPassManager(PassID))
2480b57cec5SDimitry Andric     return true;
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   startTimer(PassID);
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "after runBeforePass(" << PassID << ")\n");
2530b57cec5SDimitry Andric   LLVM_DEBUG(dump());
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   // we are not going to skip this pass, thus return true.
2560b57cec5SDimitry Andric   return true;
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric void TimePassesHandler::runAfterPass(StringRef PassID) {
2600b57cec5SDimitry Andric   if (matchPassManager(PassID))
2610b57cec5SDimitry Andric     return;
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric   stopTimer(PassID);
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "after runAfterPass(" << PassID << ")\n");
2660b57cec5SDimitry Andric   LLVM_DEBUG(dump());
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric void TimePassesHandler::registerCallbacks(PassInstrumentationCallbacks &PIC) {
2700b57cec5SDimitry Andric   if (!Enabled)
2710b57cec5SDimitry Andric     return;
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric   PIC.registerBeforePassCallback(
2740b57cec5SDimitry Andric       [this](StringRef P, Any) { return this->runBeforePass(P); });
2750b57cec5SDimitry Andric   PIC.registerAfterPassCallback(
2760b57cec5SDimitry Andric       [this](StringRef P, Any) { this->runAfterPass(P); });
2770b57cec5SDimitry Andric   PIC.registerAfterPassInvalidatedCallback(
2780b57cec5SDimitry Andric       [this](StringRef P) { this->runAfterPass(P); });
2790b57cec5SDimitry Andric   PIC.registerBeforeAnalysisCallback(
2800b57cec5SDimitry Andric       [this](StringRef P, Any) { this->runBeforePass(P); });
2810b57cec5SDimitry Andric   PIC.registerAfterAnalysisCallback(
2820b57cec5SDimitry Andric       [this](StringRef P, Any) { this->runAfterPass(P); });
2830b57cec5SDimitry Andric }
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric } // namespace llvm
286