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