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"
27e8d8bef9SDimitry 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;
38e8d8bef9SDimitry 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 
44e8d8bef9SDimitry Andric static cl::opt<bool, true> EnableTimingPerRun(
45e8d8bef9SDimitry Andric     "time-passes-per-run", cl::location(TimePassesPerRun), cl::Hidden,
46e8d8bef9SDimitry Andric     cl::desc("Time each pass run, printing elapsed time for each run on exit"),
__anonf236114d0102(const bool &) 47e8d8bef9SDimitry Andric     cl::callback([](const bool &) { TimePassesIsEnabled = true; }));
48e8d8bef9SDimitry 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 
PassTimingInfo()97bdd1243dSDimitry Andric PassTimingInfo::PassTimingInfo() : TG("pass", "Pass execution timing report") {}
980b57cec5SDimitry Andric 
~PassTimingInfo()990b57cec5SDimitry Andric PassTimingInfo::~PassTimingInfo() {
1000b57cec5SDimitry Andric   // Deleting the timers accumulates their info into the TG member.
1010b57cec5SDimitry Andric   // Then TG member is (implicitly) deleted, actually printing the report.
1020b57cec5SDimitry Andric   TimingData.clear();
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
init()1050b57cec5SDimitry Andric void PassTimingInfo::init() {
1060b57cec5SDimitry Andric   if (!TimePassesIsEnabled || TheTimeInfo)
1070b57cec5SDimitry Andric     return;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   // Constructed the first time this is called, iff -time-passes is enabled.
1100b57cec5SDimitry Andric   // This guarantees that the object will be constructed after static globals,
1110b57cec5SDimitry Andric   // thus it will be destroyed before them.
1120b57cec5SDimitry Andric   static ManagedStatic<PassTimingInfo> TTI;
1130b57cec5SDimitry Andric   TheTimeInfo = &*TTI;
1140b57cec5SDimitry Andric }
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric /// Prints out timing information and then resets the timers.
print(raw_ostream * OutStream)1170b57cec5SDimitry Andric void PassTimingInfo::print(raw_ostream *OutStream) {
1180b57cec5SDimitry Andric   TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
newPassTimer(StringRef PassID,StringRef PassDesc)1210b57cec5SDimitry Andric Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
1220b57cec5SDimitry Andric   unsigned &num = PassIDCountMap[PassID];
1230b57cec5SDimitry Andric   num++;
1240b57cec5SDimitry Andric   // Appending description with a pass-instance number for all but the first one
1250b57cec5SDimitry Andric   std::string PassDescNumbered =
1260b57cec5SDimitry Andric       num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
1270b57cec5SDimitry Andric   return new Timer(PassID, PassDescNumbered, TG);
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
getPassTimer(Pass * P,PassInstanceID Pass)1300b57cec5SDimitry Andric Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
1310b57cec5SDimitry Andric   if (P->getAsPMDataManager())
1320b57cec5SDimitry Andric     return nullptr;
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   init();
1350b57cec5SDimitry Andric   sys::SmartScopedLock<true> Lock(*TimingInfoMutex);
1360b57cec5SDimitry Andric   std::unique_ptr<Timer> &T = TimingData[Pass];
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   if (!T) {
1390b57cec5SDimitry Andric     StringRef PassName = P->getPassName();
1400b57cec5SDimitry Andric     StringRef PassArgument;
1410b57cec5SDimitry Andric     if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID()))
1420b57cec5SDimitry Andric       PassArgument = PI->getPassArgument();
1430b57cec5SDimitry Andric     T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName));
1440b57cec5SDimitry Andric   }
1450b57cec5SDimitry Andric   return T.get();
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric PassTimingInfo *PassTimingInfo::TheTimeInfo;
1490b57cec5SDimitry Andric } // namespace legacy
1500b57cec5SDimitry Andric } // namespace
1510b57cec5SDimitry Andric 
getPassTimer(Pass * P)1520b57cec5SDimitry Andric Timer *getPassTimer(Pass *P) {
1530b57cec5SDimitry Andric   legacy::PassTimingInfo::init();
1540b57cec5SDimitry Andric   if (legacy::PassTimingInfo::TheTimeInfo)
1550b57cec5SDimitry Andric     return legacy::PassTimingInfo::TheTimeInfo->getPassTimer(P, P);
1560b57cec5SDimitry Andric   return nullptr;
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric /// If timing is enabled, report the times collected up to now and then reset
1600b57cec5SDimitry Andric /// them.
reportAndResetTimings(raw_ostream * OutStream)1610b57cec5SDimitry Andric void reportAndResetTimings(raw_ostream *OutStream) {
1620b57cec5SDimitry Andric   if (legacy::PassTimingInfo::TheTimeInfo)
1630b57cec5SDimitry Andric     legacy::PassTimingInfo::TheTimeInfo->print(OutStream);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1670b57cec5SDimitry Andric // Pass timing handling for the New Pass Manager
1680b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric /// Returns the timer for the specified pass invocation of \p PassID.
1710b57cec5SDimitry Andric /// Each time it creates a new timer.
getPassTimer(StringRef PassID,bool IsPass)172bdd1243dSDimitry Andric Timer &TimePassesHandler::getPassTimer(StringRef PassID, bool IsPass) {
173bdd1243dSDimitry Andric   TimerGroup &TG = IsPass ? PassTG : AnalysisTG;
174e8d8bef9SDimitry Andric   if (!PerRun) {
175e8d8bef9SDimitry Andric     TimerVector &Timers = TimingData[PassID];
176e8d8bef9SDimitry Andric     if (Timers.size() == 0)
177e8d8bef9SDimitry Andric       Timers.emplace_back(new Timer(PassID, PassID, TG));
178e8d8bef9SDimitry Andric     return *Timers.front();
179e8d8bef9SDimitry Andric   }
180e8d8bef9SDimitry 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);
1904824e7fdSDimitry Andric   assert(Count == Timers.size() && "Timers vector not adjusted correctly.");
1915ffd83dbSDimitry Andric 
1925ffd83dbSDimitry Andric   return *T;
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric 
TimePassesHandler(bool Enabled,bool PerRun)195e8d8bef9SDimitry Andric TimePassesHandler::TimePassesHandler(bool Enabled, bool PerRun)
196bdd1243dSDimitry Andric     : PassTG("pass", "Pass execution timing report"),
197bdd1243dSDimitry Andric       AnalysisTG("analysis", "Analysis execution timing report"),
198bdd1243dSDimitry Andric       Enabled(Enabled), PerRun(PerRun) {}
199e8d8bef9SDimitry Andric 
TimePassesHandler()200e8d8bef9SDimitry Andric TimePassesHandler::TimePassesHandler()
201e8d8bef9SDimitry Andric     : TimePassesHandler(TimePassesIsEnabled, TimePassesPerRun) {}
2020b57cec5SDimitry Andric 
setOutStream(raw_ostream & Out)2030b57cec5SDimitry Andric void TimePassesHandler::setOutStream(raw_ostream &Out) {
2040b57cec5SDimitry Andric   OutStream = &Out;
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
print()2070b57cec5SDimitry Andric void TimePassesHandler::print() {
2080b57cec5SDimitry Andric   if (!Enabled)
2090b57cec5SDimitry Andric     return;
210bdd1243dSDimitry Andric   std::unique_ptr<raw_ostream> MaybeCreated;
211bdd1243dSDimitry Andric   raw_ostream *OS = OutStream;
212bdd1243dSDimitry Andric   if (OutStream) {
213bdd1243dSDimitry Andric     OS = OutStream;
214bdd1243dSDimitry Andric   } else {
215bdd1243dSDimitry Andric     MaybeCreated = CreateInfoOutputFile();
216bdd1243dSDimitry Andric     OS = &*MaybeCreated;
217bdd1243dSDimitry Andric   }
218bdd1243dSDimitry Andric   PassTG.print(*OS, true);
219bdd1243dSDimitry Andric   AnalysisTG.print(*OS, true);
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric 
dump() const2220b57cec5SDimitry Andric LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
2230b57cec5SDimitry Andric   dbgs() << "Dumping timers for " << getTypeName<TimePassesHandler>()
2240b57cec5SDimitry Andric          << ":\n\tRunning:\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->isRunning())
2315ffd83dbSDimitry Andric         dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
2325ffd83dbSDimitry Andric     }
2330b57cec5SDimitry Andric   }
2340b57cec5SDimitry Andric   dbgs() << "\tTriggered:\n";
2350b57cec5SDimitry Andric   for (auto &I : TimingData) {
2365ffd83dbSDimitry Andric     StringRef PassID = I.getKey();
2375ffd83dbSDimitry Andric     const TimerVector& MyTimers = I.getValue();
2385ffd83dbSDimitry Andric     for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
2395ffd83dbSDimitry Andric       const Timer* MyTimer = MyTimers[idx].get();
2405ffd83dbSDimitry Andric       if (MyTimer && MyTimer->hasTriggered() && !MyTimer->isRunning())
2415ffd83dbSDimitry Andric         dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
2425ffd83dbSDimitry Andric     }
2430b57cec5SDimitry Andric   }
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric 
shouldIgnorePass(StringRef PassID)246bdd1243dSDimitry Andric static bool shouldIgnorePass(StringRef PassID) {
247bdd1243dSDimitry Andric   return isSpecialPass(PassID,
248bdd1243dSDimitry Andric                        {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
249bdd1243dSDimitry Andric                         "ModuleInlinerWrapperPass", "DevirtSCCRepeatedPass"});
250bdd1243dSDimitry Andric }
251bdd1243dSDimitry Andric 
startPassTimer(StringRef PassID)252bdd1243dSDimitry Andric void TimePassesHandler::startPassTimer(StringRef PassID) {
253bdd1243dSDimitry Andric   if (shouldIgnorePass(PassID))
254bdd1243dSDimitry Andric     return;
2555f757f3fSDimitry Andric   // Stop the previous pass timer to prevent double counting when a
2565f757f3fSDimitry Andric   // pass requests another pass.
2575f757f3fSDimitry Andric   if (!PassActiveTimerStack.empty()) {
2585f757f3fSDimitry Andric     assert(PassActiveTimerStack.back()->isRunning());
2595f757f3fSDimitry Andric     PassActiveTimerStack.back()->stopTimer();
2605f757f3fSDimitry Andric   }
261bdd1243dSDimitry Andric   Timer &MyTimer = getPassTimer(PassID, /*IsPass*/ true);
2625f757f3fSDimitry Andric   PassActiveTimerStack.push_back(&MyTimer);
263bdd1243dSDimitry Andric   assert(!MyTimer.isRunning());
264bdd1243dSDimitry Andric   MyTimer.startTimer();
265bdd1243dSDimitry Andric }
266bdd1243dSDimitry Andric 
stopPassTimer(StringRef PassID)267bdd1243dSDimitry Andric void TimePassesHandler::stopPassTimer(StringRef PassID) {
268bdd1243dSDimitry Andric   if (shouldIgnorePass(PassID))
269bdd1243dSDimitry Andric     return;
2705f757f3fSDimitry Andric   assert(!PassActiveTimerStack.empty() && "empty stack in popTimer");
2715f757f3fSDimitry Andric   Timer *MyTimer = PassActiveTimerStack.pop_back_val();
2725f757f3fSDimitry Andric   assert(MyTimer && "timer should be present");
2735f757f3fSDimitry Andric   assert(MyTimer->isRunning());
2745f757f3fSDimitry Andric   MyTimer->stopTimer();
2755f757f3fSDimitry Andric 
2765f757f3fSDimitry Andric   // Restart the previously stopped timer.
2775f757f3fSDimitry Andric   if (!PassActiveTimerStack.empty()) {
2785f757f3fSDimitry Andric     assert(!PassActiveTimerStack.back()->isRunning());
2795f757f3fSDimitry Andric     PassActiveTimerStack.back()->startTimer();
2805f757f3fSDimitry Andric   }
281bdd1243dSDimitry Andric }
282bdd1243dSDimitry Andric 
startAnalysisTimer(StringRef PassID)283bdd1243dSDimitry Andric void TimePassesHandler::startAnalysisTimer(StringRef PassID) {
284bdd1243dSDimitry Andric   // Stop the previous analysis timer to prevent double counting when an
285bdd1243dSDimitry Andric   // analysis requests another analysis.
286bdd1243dSDimitry Andric   if (!AnalysisActiveTimerStack.empty()) {
287bdd1243dSDimitry Andric     assert(AnalysisActiveTimerStack.back()->isRunning());
288bdd1243dSDimitry Andric     AnalysisActiveTimerStack.back()->stopTimer();
289bdd1243dSDimitry Andric   }
290bdd1243dSDimitry Andric 
291bdd1243dSDimitry Andric   Timer &MyTimer = getPassTimer(PassID, /*IsPass*/ false);
292bdd1243dSDimitry Andric   AnalysisActiveTimerStack.push_back(&MyTimer);
2930b57cec5SDimitry Andric   if (!MyTimer.isRunning())
2940b57cec5SDimitry Andric     MyTimer.startTimer();
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric 
stopAnalysisTimer(StringRef PassID)297bdd1243dSDimitry Andric void TimePassesHandler::stopAnalysisTimer(StringRef PassID) {
298bdd1243dSDimitry Andric   assert(!AnalysisActiveTimerStack.empty() && "empty stack in popTimer");
299bdd1243dSDimitry Andric   Timer *MyTimer = AnalysisActiveTimerStack.pop_back_val();
3000b57cec5SDimitry Andric   assert(MyTimer && "timer should be present");
3010b57cec5SDimitry Andric   if (MyTimer->isRunning())
3020b57cec5SDimitry Andric     MyTimer->stopTimer();
303bdd1243dSDimitry Andric 
304bdd1243dSDimitry Andric   // Restart the previously stopped timer.
305bdd1243dSDimitry Andric   if (!AnalysisActiveTimerStack.empty()) {
306bdd1243dSDimitry Andric     assert(!AnalysisActiveTimerStack.back()->isRunning());
307bdd1243dSDimitry Andric     AnalysisActiveTimerStack.back()->startTimer();
3080b57cec5SDimitry Andric   }
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric 
registerCallbacks(PassInstrumentationCallbacks & PIC)3110b57cec5SDimitry Andric void TimePassesHandler::registerCallbacks(PassInstrumentationCallbacks &PIC) {
3120b57cec5SDimitry Andric   if (!Enabled)
3130b57cec5SDimitry Andric     return;
3140b57cec5SDimitry Andric 
315e8d8bef9SDimitry Andric   PIC.registerBeforeNonSkippedPassCallback(
316bdd1243dSDimitry Andric       [this](StringRef P, Any) { this->startPassTimer(P); });
3170b57cec5SDimitry Andric   PIC.registerAfterPassCallback(
318e8d8bef9SDimitry Andric       [this](StringRef P, Any, const PreservedAnalyses &) {
319bdd1243dSDimitry Andric         this->stopPassTimer(P);
320e8d8bef9SDimitry Andric       });
3210b57cec5SDimitry Andric   PIC.registerAfterPassInvalidatedCallback(
322e8d8bef9SDimitry Andric       [this](StringRef P, const PreservedAnalyses &) {
323bdd1243dSDimitry Andric         this->stopPassTimer(P);
324e8d8bef9SDimitry Andric       });
3250b57cec5SDimitry Andric   PIC.registerBeforeAnalysisCallback(
326bdd1243dSDimitry Andric       [this](StringRef P, Any) { this->startAnalysisTimer(P); });
3270b57cec5SDimitry Andric   PIC.registerAfterAnalysisCallback(
328bdd1243dSDimitry Andric       [this](StringRef P, Any) { this->stopAnalysisTimer(P); });
3290b57cec5SDimitry Andric }
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric } // namespace llvm
332