1 //===- PassTimingInfo.cpp - LLVM Pass Timing Implementation ---------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the LLVM Pass Timing infrastructure for both 10 // new and legacy pass managers. 11 // 12 // PassTimingInfo Class - This class is used to calculate information about the 13 // amount of time each pass takes to execute. This only happens when 14 // -time-passes is enabled on the command line. 15 // 16 //===----------------------------------------------------------------------===// 17 18 #include "llvm/IR/PassTimingInfo.h" 19 #include "llvm/ADT/Statistic.h" 20 #include "llvm/IR/PassInstrumentation.h" 21 #include "llvm/Pass.h" 22 #include "llvm/Support/CommandLine.h" 23 #include "llvm/Support/Debug.h" 24 #include "llvm/Support/FormatVariadic.h" 25 #include "llvm/Support/ManagedStatic.h" 26 #include "llvm/Support/Mutex.h" 27 #include "llvm/Support/TypeName.h" 28 #include "llvm/Support/raw_ostream.h" 29 #include <string> 30 31 using namespace llvm; 32 33 #define DEBUG_TYPE "time-passes" 34 35 namespace llvm { 36 37 bool TimePassesIsEnabled = false; 38 39 static cl::opt<bool, true> EnableTiming( 40 "time-passes", cl::location(TimePassesIsEnabled), cl::Hidden, 41 cl::desc("Time each pass, printing elapsed time for each on exit")); 42 43 namespace { 44 namespace legacy { 45 46 //===----------------------------------------------------------------------===// 47 // Legacy pass manager's PassTimingInfo implementation 48 49 /// Provides an interface for collecting pass timing information. 50 /// 51 /// It was intended to be generic but now we decided to split 52 /// interfaces completely. This is now exclusively for legacy-pass-manager use. 53 class PassTimingInfo { 54 public: 55 using PassInstanceID = void *; 56 57 private: 58 StringMap<unsigned> PassIDCountMap; ///< Map that counts instances of passes 59 DenseMap<PassInstanceID, std::unique_ptr<Timer>> TimingData; ///< timers for pass instances 60 TimerGroup TG; 61 62 public: 63 /// Default constructor for yet-inactive timeinfo. 64 /// Use \p init() to activate it. 65 PassTimingInfo(); 66 67 /// Print out timing information and release timers. 68 ~PassTimingInfo(); 69 70 /// Initializes the static \p TheTimeInfo member to a non-null value when 71 /// -time-passes is enabled. Leaves it null otherwise. 72 /// 73 /// This method may be called multiple times. 74 static void init(); 75 76 /// Prints out timing information and then resets the timers. 77 /// By default it uses the stream created by CreateInfoOutputFile(). 78 void print(raw_ostream *OutStream = nullptr); 79 80 /// Returns the timer for the specified pass if it exists. 81 Timer *getPassTimer(Pass *, PassInstanceID); 82 83 static PassTimingInfo *TheTimeInfo; 84 85 private: 86 Timer *newPassTimer(StringRef PassID, StringRef PassDesc); 87 }; 88 89 static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex; 90 91 PassTimingInfo::PassTimingInfo() 92 : TG("pass", "... Pass execution timing report ...") {} 93 94 PassTimingInfo::~PassTimingInfo() { 95 // Deleting the timers accumulates their info into the TG member. 96 // Then TG member is (implicitly) deleted, actually printing the report. 97 TimingData.clear(); 98 } 99 100 void PassTimingInfo::init() { 101 if (!TimePassesIsEnabled || TheTimeInfo) 102 return; 103 104 // Constructed the first time this is called, iff -time-passes is enabled. 105 // This guarantees that the object will be constructed after static globals, 106 // thus it will be destroyed before them. 107 static ManagedStatic<PassTimingInfo> TTI; 108 TheTimeInfo = &*TTI; 109 } 110 111 /// Prints out timing information and then resets the timers. 112 void PassTimingInfo::print(raw_ostream *OutStream) { 113 TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true); 114 } 115 116 Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) { 117 unsigned &num = PassIDCountMap[PassID]; 118 num++; 119 // Appending description with a pass-instance number for all but the first one 120 std::string PassDescNumbered = 121 num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str(); 122 return new Timer(PassID, PassDescNumbered, TG); 123 } 124 125 Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) { 126 if (P->getAsPMDataManager()) 127 return nullptr; 128 129 init(); 130 sys::SmartScopedLock<true> Lock(*TimingInfoMutex); 131 std::unique_ptr<Timer> &T = TimingData[Pass]; 132 133 if (!T) { 134 StringRef PassName = P->getPassName(); 135 StringRef PassArgument; 136 if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID())) 137 PassArgument = PI->getPassArgument(); 138 T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName)); 139 } 140 return T.get(); 141 } 142 143 PassTimingInfo *PassTimingInfo::TheTimeInfo; 144 } // namespace legacy 145 } // namespace 146 147 Timer *getPassTimer(Pass *P) { 148 legacy::PassTimingInfo::init(); 149 if (legacy::PassTimingInfo::TheTimeInfo) 150 return legacy::PassTimingInfo::TheTimeInfo->getPassTimer(P, P); 151 return nullptr; 152 } 153 154 /// If timing is enabled, report the times collected up to now and then reset 155 /// them. 156 void reportAndResetTimings(raw_ostream *OutStream) { 157 if (legacy::PassTimingInfo::TheTimeInfo) 158 legacy::PassTimingInfo::TheTimeInfo->print(OutStream); 159 } 160 161 //===----------------------------------------------------------------------===// 162 // Pass timing handling for the New Pass Manager 163 //===----------------------------------------------------------------------===// 164 165 /// Returns the timer for the specified pass invocation of \p PassID. 166 /// Each time it creates a new timer. 167 Timer &TimePassesHandler::getPassTimer(StringRef PassID) { 168 // Take a vector of Timers created for this \p PassID and append 169 // one more timer to it. 170 TimerVector &Timers = TimingData[PassID]; 171 unsigned Count = Timers.size() + 1; 172 173 std::string FullDesc = formatv("{0} #{1}", PassID, Count).str(); 174 175 Timer *T = new Timer(PassID, FullDesc, TG); 176 Timers.emplace_back(T); 177 assert(Count == Timers.size() && "sanity check"); 178 179 return *T; 180 } 181 182 TimePassesHandler::TimePassesHandler(bool Enabled) 183 : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled) {} 184 185 void TimePassesHandler::setOutStream(raw_ostream &Out) { 186 OutStream = &Out; 187 } 188 189 void TimePassesHandler::print() { 190 if (!Enabled) 191 return; 192 TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true); 193 } 194 195 LLVM_DUMP_METHOD void TimePassesHandler::dump() const { 196 dbgs() << "Dumping timers for " << getTypeName<TimePassesHandler>() 197 << ":\n\tRunning:\n"; 198 for (auto &I : TimingData) { 199 StringRef PassID = I.getKey(); 200 const TimerVector& MyTimers = I.getValue(); 201 for (unsigned idx = 0; idx < MyTimers.size(); idx++) { 202 const Timer* MyTimer = MyTimers[idx].get(); 203 if (MyTimer && MyTimer->isRunning()) 204 dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n"; 205 } 206 } 207 dbgs() << "\tTriggered:\n"; 208 for (auto &I : TimingData) { 209 StringRef PassID = I.getKey(); 210 const TimerVector& MyTimers = I.getValue(); 211 for (unsigned idx = 0; idx < MyTimers.size(); idx++) { 212 const Timer* MyTimer = MyTimers[idx].get(); 213 if (MyTimer && MyTimer->hasTriggered() && !MyTimer->isRunning()) 214 dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n"; 215 } 216 } 217 } 218 219 void TimePassesHandler::startTimer(StringRef PassID) { 220 Timer &MyTimer = getPassTimer(PassID); 221 TimerStack.push_back(&MyTimer); 222 if (!MyTimer.isRunning()) 223 MyTimer.startTimer(); 224 } 225 226 void TimePassesHandler::stopTimer(StringRef PassID) { 227 assert(TimerStack.size() > 0 && "empty stack in popTimer"); 228 Timer *MyTimer = TimerStack.pop_back_val(); 229 assert(MyTimer && "timer should be present"); 230 if (MyTimer->isRunning()) 231 MyTimer->stopTimer(); 232 } 233 234 void TimePassesHandler::runBeforePass(StringRef PassID) { 235 if (isSpecialPass(PassID, 236 {"PassManager", "PassAdaptor", "AnalysisManagerProxy"})) 237 return; 238 239 startTimer(PassID); 240 241 LLVM_DEBUG(dbgs() << "after runBeforePass(" << PassID << ")\n"); 242 LLVM_DEBUG(dump()); 243 } 244 245 void TimePassesHandler::runAfterPass(StringRef PassID) { 246 if (isSpecialPass(PassID, 247 {"PassManager", "PassAdaptor", "AnalysisManagerProxy"})) 248 return; 249 250 stopTimer(PassID); 251 252 LLVM_DEBUG(dbgs() << "after runAfterPass(" << PassID << ")\n"); 253 LLVM_DEBUG(dump()); 254 } 255 256 void TimePassesHandler::registerCallbacks(PassInstrumentationCallbacks &PIC) { 257 if (!Enabled) 258 return; 259 260 PIC.registerBeforeNonSkippedPassCallback( 261 [this](StringRef P, Any) { this->runBeforePass(P); }); 262 PIC.registerAfterPassCallback( 263 [this](StringRef P, Any, const PreservedAnalyses &) { 264 this->runAfterPass(P); 265 }); 266 PIC.registerAfterPassInvalidatedCallback( 267 [this](StringRef P, const PreservedAnalyses &) { 268 this->runAfterPass(P); 269 }); 270 PIC.registerBeforeAnalysisCallback( 271 [this](StringRef P, Any) { this->runBeforePass(P); }); 272 PIC.registerAfterAnalysisCallback( 273 [this](StringRef P, Any) { this->runAfterPass(P); }); 274 } 275 276 } // namespace llvm 277