PassTimingInfo.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. #include "llvm/IR/PassTimingInfo.h"
  18. #include "llvm/ADT/DenseMap.h"
  19. #include "llvm/ADT/Statistic.h"
  20. #include "llvm/ADT/StringRef.h"
  21. #include "llvm/IR/PassInstrumentation.h"
  22. #include "llvm/Pass.h"
  23. #include "llvm/Support/CommandLine.h"
  24. #include "llvm/Support/Debug.h"
  25. #include "llvm/Support/FormatVariadic.h"
  26. #include "llvm/Support/ManagedStatic.h"
  27. #include "llvm/Support/Mutex.h"
  28. #include "llvm/Support/Timer.h"
  29. #include "llvm/Support/raw_ostream.h"
  30. #include <memory>
  31. #include <string>
  32. using namespace llvm;
  33. #define DEBUG_TYPE "time-passes"
  34. namespace llvm {
  35. bool TimePassesIsEnabled = false;
  36. static cl::opt<bool, true> EnableTiming(
  37. "time-passes", cl::location(TimePassesIsEnabled), cl::Hidden,
  38. cl::desc("Time each pass, printing elapsed time for each on exit"));
  39. namespace {
  40. namespace legacy {
  41. //===----------------------------------------------------------------------===//
  42. // Legacy pass manager's PassTimingInfo implementation
  43. /// Provides an interface for collecting pass timing information.
  44. ///
  45. /// It was intended to be generic but now we decided to split
  46. /// interfaces completely. This is now exclusively for legacy-pass-manager use.
  47. class PassTimingInfo {
  48. public:
  49. using PassInstanceID = void *;
  50. private:
  51. StringMap<unsigned> PassIDCountMap; ///< Map that counts instances of passes
  52. DenseMap<PassInstanceID, std::unique_ptr<Timer>> TimingData; ///< timers for pass instances
  53. TimerGroup TG;
  54. public:
  55. /// Default constructor for yet-inactive timeinfo.
  56. /// Use \p init() to activate it.
  57. PassTimingInfo();
  58. /// Print out timing information and release timers.
  59. ~PassTimingInfo();
  60. /// Initializes the static \p TheTimeInfo member to a non-null value when
  61. /// -time-passes is enabled. Leaves it null otherwise.
  62. ///
  63. /// This method may be called multiple times.
  64. static void init();
  65. /// Prints out timing information and then resets the timers.
  66. /// By default it uses the stream created by CreateInfoOutputFile().
  67. void print(raw_ostream *OutStream = nullptr);
  68. /// Returns the timer for the specified pass if it exists.
  69. Timer *getPassTimer(Pass *, PassInstanceID);
  70. static PassTimingInfo *TheTimeInfo;
  71. private:
  72. Timer *newPassTimer(StringRef PassID, StringRef PassDesc);
  73. };
  74. static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex;
  75. PassTimingInfo::PassTimingInfo()
  76. : TG("pass", "... Pass execution timing report ...") {}
  77. PassTimingInfo::~PassTimingInfo() {
  78. // Deleting the timers accumulates their info into the TG member.
  79. // Then TG member is (implicitly) deleted, actually printing the report.
  80. TimingData.clear();
  81. }
  82. void PassTimingInfo::init() {
  83. if (!TimePassesIsEnabled || TheTimeInfo)
  84. return;
  85. // Constructed the first time this is called, iff -time-passes is enabled.
  86. // This guarantees that the object will be constructed after static globals,
  87. // thus it will be destroyed before them.
  88. static ManagedStatic<PassTimingInfo> TTI;
  89. TheTimeInfo = &*TTI;
  90. }
  91. /// Prints out timing information and then resets the timers.
  92. void PassTimingInfo::print(raw_ostream *OutStream) {
  93. TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
  94. }
  95. Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
  96. unsigned &num = PassIDCountMap[PassID];
  97. num++;
  98. // Appending description with a pass-instance number for all but the first one
  99. std::string PassDescNumbered =
  100. num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
  101. return new Timer(PassID, PassDescNumbered, TG);
  102. }
  103. Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
  104. if (P->getAsPMDataManager())
  105. return nullptr;
  106. init();
  107. sys::SmartScopedLock<true> Lock(*TimingInfoMutex);
  108. std::unique_ptr<Timer> &T = TimingData[Pass];
  109. if (!T) {
  110. StringRef PassName = P->getPassName();
  111. StringRef PassArgument;
  112. if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID()))
  113. PassArgument = PI->getPassArgument();
  114. T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName));
  115. }
  116. return T.get();
  117. }
  118. PassTimingInfo *PassTimingInfo::TheTimeInfo;
  119. } // namespace legacy
  120. } // namespace
  121. Timer *getPassTimer(Pass *P) {
  122. legacy::PassTimingInfo::init();
  123. if (legacy::PassTimingInfo::TheTimeInfo)
  124. return legacy::PassTimingInfo::TheTimeInfo->getPassTimer(P, P);
  125. return nullptr;
  126. }
  127. /// If timing is enabled, report the times collected up to now and then reset
  128. /// them.
  129. void reportAndResetTimings(raw_ostream *OutStream) {
  130. if (legacy::PassTimingInfo::TheTimeInfo)
  131. legacy::PassTimingInfo::TheTimeInfo->print(OutStream);
  132. }
  133. //===----------------------------------------------------------------------===//
  134. // Pass timing handling for the New Pass Manager
  135. //===----------------------------------------------------------------------===//
  136. /// Returns the timer for the specified pass invocation of \p PassID.
  137. /// Each time it creates a new timer.
  138. Timer &TimePassesHandler::getPassTimer(StringRef PassID) {
  139. // Bump counts for each request of the timer.
  140. unsigned Count = nextPassID(PassID);
  141. // Unconditionally appending description with a pass-invocation number.
  142. std::string FullDesc = formatv("{0} #{1}", PassID, Count).str();
  143. PassInvocationID UID{PassID, Count};
  144. Timer *T = new Timer(PassID, FullDesc, TG);
  145. auto Pair = TimingData.try_emplace(UID, T);
  146. assert(Pair.second && "should always create a new timer");
  147. return *(Pair.first->second.get());
  148. }
  149. TimePassesHandler::TimePassesHandler(bool Enabled)
  150. : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled) {}
  151. void TimePassesHandler::setOutStream(raw_ostream &Out) {
  152. OutStream = &Out;
  153. }
  154. void TimePassesHandler::print() {
  155. if (!Enabled)
  156. return;
  157. TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
  158. }
  159. LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
  160. dbgs() << "Dumping timers for " << getTypeName<TimePassesHandler>()
  161. << ":\n\tRunning:\n";
  162. for (auto &I : TimingData) {
  163. const Timer *MyTimer = I.second.get();
  164. if (!MyTimer || MyTimer->isRunning())
  165. dbgs() << "\tTimer " << MyTimer << " for pass " << I.first.first << "("
  166. << I.first.second << ")\n";
  167. }
  168. dbgs() << "\tTriggered:\n";
  169. for (auto &I : TimingData) {
  170. const Timer *MyTimer = I.second.get();
  171. if (!MyTimer || (MyTimer->hasTriggered() && !MyTimer->isRunning()))
  172. dbgs() << "\tTimer " << MyTimer << " for pass " << I.first.first << "("
  173. << I.first.second << ")\n";
  174. }
  175. }
  176. void TimePassesHandler::startTimer(StringRef PassID) {
  177. Timer &MyTimer = getPassTimer(PassID);
  178. TimerStack.push_back(&MyTimer);
  179. if (!MyTimer.isRunning())
  180. MyTimer.startTimer();
  181. }
  182. void TimePassesHandler::stopTimer(StringRef PassID) {
  183. assert(TimerStack.size() > 0 && "empty stack in popTimer");
  184. Timer *MyTimer = TimerStack.pop_back_val();
  185. assert(MyTimer && "timer should be present");
  186. if (MyTimer->isRunning())
  187. MyTimer->stopTimer();
  188. }
  189. static bool matchPassManager(StringRef PassID) {
  190. size_t prefix_pos = PassID.find('<');
  191. if (prefix_pos == StringRef::npos)
  192. return false;
  193. StringRef Prefix = PassID.substr(0, prefix_pos);
  194. return Prefix.endswith("PassManager") || Prefix.endswith("PassAdaptor") ||
  195. Prefix.endswith("AnalysisManagerProxy");
  196. }
  197. bool TimePassesHandler::runBeforePass(StringRef PassID) {
  198. if (matchPassManager(PassID))
  199. return true;
  200. startTimer(PassID);
  201. LLVM_DEBUG(dbgs() << "after runBeforePass(" << PassID << ")\n");
  202. LLVM_DEBUG(dump());
  203. // we are not going to skip this pass, thus return true.
  204. return true;
  205. }
  206. void TimePassesHandler::runAfterPass(StringRef PassID) {
  207. if (matchPassManager(PassID))
  208. return;
  209. stopTimer(PassID);
  210. LLVM_DEBUG(dbgs() << "after runAfterPass(" << PassID << ")\n");
  211. LLVM_DEBUG(dump());
  212. }
  213. void TimePassesHandler::registerCallbacks(PassInstrumentationCallbacks &PIC) {
  214. if (!Enabled)
  215. return;
  216. PIC.registerBeforePassCallback(
  217. [this](StringRef P, Any) { return this->runBeforePass(P); });
  218. PIC.registerAfterPassCallback(
  219. [this](StringRef P, Any) { this->runAfterPass(P); });
  220. PIC.registerAfterPassInvalidatedCallback(
  221. [this](StringRef P) { this->runAfterPass(P); });
  222. PIC.registerBeforeAnalysisCallback(
  223. [this](StringRef P, Any) { this->runBeforePass(P); });
  224. PIC.registerAfterAnalysisCallback(
  225. [this](StringRef P, Any) { this->runAfterPass(P); });
  226. }
  227. } // namespace llvm