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