LLVM 22.0.0git
PassTimingInfo.cpp
Go to the documentation of this file.
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
19#include "llvm/ADT/Statistic.h"
21#include "llvm/Pass.h"
23#include "llvm/Support/Debug.h"
26#include "llvm/Support/Mutex.h"
29#include <string>
30
31using namespace llvm;
32
33#define DEBUG_TYPE "time-passes"
34
35namespace llvm {
36
38bool TimePassesPerRun = false;
39
42 cl::desc("Time each pass, printing elapsed time for each on exit"));
43
45 "time-passes-per-run", cl::location(TimePassesPerRun), cl::Hidden,
46 cl::desc("Time each pass run, printing elapsed time for each run on exit"),
47 cl::callback([](const bool &) { TimePassesIsEnabled = true; }));
48
49namespace {
50namespace legacy {
51
52//===----------------------------------------------------------------------===//
53// Legacy pass manager's PassTimingInfo implementation
54
55/// Provides an interface for collecting pass timing information.
56///
57/// It was intended to be generic but now we decided to split
58/// interfaces completely. This is now exclusively for legacy-pass-manager use.
59class PassTimingInfo {
60public:
61 using PassInstanceID = void *;
62
63private:
64 StringMap<unsigned> PassIDCountMap; ///< Map that counts instances of passes
65 DenseMap<PassInstanceID, std::unique_ptr<Timer>> TimingData; ///< timers for pass instances
66 TimerGroup *PassTG = nullptr;
67
68public:
69 /// Initializes the static \p TheTimeInfo member to a non-null value when
70 /// -time-passes is enabled. Leaves it null otherwise.
71 ///
72 /// This method may be called multiple times.
73 static void init();
74
75 /// Prints out timing information and then resets the timers.
76 /// By default it uses the stream created by CreateInfoOutputFile().
77 void print(raw_ostream *OutStream = nullptr);
78
79 /// Returns the timer for the specified pass if it exists.
80 Timer *getPassTimer(Pass *, PassInstanceID);
81
82 static PassTimingInfo *TheTimeInfo;
83
84private:
85 Timer *newPassTimer(StringRef PassID, StringRef PassDesc);
86};
87
88static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex;
89
90void PassTimingInfo::init() {
91 if (TheTimeInfo || !TimePassesIsEnabled)
92 return;
93
94 // Constructed the first time this is called, iff -time-passes is enabled.
95 // This guarantees that the object will be constructed after static globals,
96 // thus it will be destroyed before them.
97 static ManagedStatic<PassTimingInfo> TTI;
98 if (!TTI->PassTG)
101 TheTimeInfo = &*TTI;
102}
103
104/// Prints out timing information and then resets the timers.
105void PassTimingInfo::print(raw_ostream *OutStream) {
106 assert(PassTG && "PassTG is null, did you call PassTimingInfo::Init()?");
107 PassTG->print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
108}
109
110Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
111 unsigned &num = PassIDCountMap[PassID];
112 num++;
113 // Appending description with a pass-instance number for all but the first one
114 std::string PassDescNumbered =
115 num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
116 assert(PassTG && "PassTG is null, did you call PassTimingInfo::Init()?");
117 return new Timer(PassID, PassDescNumbered, *PassTG);
118}
119
120Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
121 if (P->getAsPMDataManager())
122 return nullptr;
123
124 init();
125 sys::SmartScopedLock<true> Lock(*TimingInfoMutex);
126 std::unique_ptr<Timer> &T = TimingData[Pass];
127
128 if (!T) {
129 StringRef PassName = P->getPassName();
130 StringRef PassArgument;
131 if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID()))
132 PassArgument = PI->getPassArgument();
133 T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName));
134 }
135 return T.get();
136}
137
138PassTimingInfo *PassTimingInfo::TheTimeInfo;
139} // namespace legacy
140} // namespace
141
143 legacy::PassTimingInfo::init();
144 if (legacy::PassTimingInfo::TheTimeInfo)
145 return legacy::PassTimingInfo::TheTimeInfo->getPassTimer(P, P);
146 return nullptr;
147}
148
149/// If timing is enabled, report the times collected up to now and then reset
150/// them.
152 if (legacy::PassTimingInfo::TheTimeInfo)
153 legacy::PassTimingInfo::TheTimeInfo->print(OutStream);
154}
155
156//===----------------------------------------------------------------------===//
157// Pass timing handling for the New Pass Manager
158//===----------------------------------------------------------------------===//
159
160/// Returns the timer for the specified pass invocation of \p PassID.
161/// Each time it creates a new timer.
162Timer &TimePassesHandler::getPassTimer(StringRef PassID, bool IsPass) {
163 TimerGroup &TG = IsPass ? PassTG : AnalysisTG;
164 if (!PerRun) {
165 TimerVector &Timers = TimingData[PassID];
166 if (Timers.size() == 0)
167 Timers.emplace_back(new Timer(PassID, PassID, TG));
168 return *Timers.front();
169 }
170
171 // Take a vector of Timers created for this \p PassID and append
172 // one more timer to it.
173 TimerVector &Timers = TimingData[PassID];
174 unsigned Count = Timers.size() + 1;
175
176 std::string FullDesc = formatv("{0} #{1}", PassID, Count).str();
177
178 Timer *T = new Timer(PassID, FullDesc, TG);
179 Timers.emplace_back(T);
180 assert(Count == Timers.size() && "Timers vector not adjusted correctly.");
181
182 return *T;
183}
184
185TimePassesHandler::TimePassesHandler(bool Enabled, bool PerRun)
186 : Enabled(Enabled), PerRun(PerRun) {}
187
190
192 OutStream = &Out;
193}
194
196 if (!Enabled)
197 return;
198 std::unique_ptr<raw_ostream> MaybeCreated;
199 raw_ostream *OS = OutStream;
200 if (OutStream) {
201 OS = OutStream;
202 } else {
203 MaybeCreated = CreateInfoOutputFile();
204 OS = &*MaybeCreated;
205 }
206 PassTG.print(*OS, true);
207 AnalysisTG.print(*OS, true);
208}
209
210LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
211 dbgs() << "Dumping timers for " << getTypeName<TimePassesHandler>()
212 << ":\n\tRunning:\n";
213 for (auto &I : TimingData) {
214 StringRef PassID = I.getKey();
215 const TimerVector& MyTimers = I.getValue();
216 for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
217 const Timer* MyTimer = MyTimers[idx].get();
218 if (MyTimer && MyTimer->isRunning())
219 dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
220 }
221 }
222 dbgs() << "\tTriggered:\n";
223 for (auto &I : TimingData) {
224 StringRef PassID = I.getKey();
225 const TimerVector& MyTimers = I.getValue();
226 for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
227 const Timer* MyTimer = MyTimers[idx].get();
228 if (MyTimer && MyTimer->hasTriggered() && !MyTimer->isRunning())
229 dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
230 }
231 }
232}
233
234static bool shouldIgnorePass(StringRef PassID) {
235 return isSpecialPass(PassID,
236 {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
237 "ModuleInlinerWrapperPass", "DevirtSCCRepeatedPass"});
238}
239
240void TimePassesHandler::startPassTimer(StringRef PassID) {
241 if (shouldIgnorePass(PassID))
242 return;
243 // Stop the previous pass timer to prevent double counting when a
244 // pass requests another pass.
245 if (!PassActiveTimerStack.empty()) {
246 assert(PassActiveTimerStack.back()->isRunning());
247 PassActiveTimerStack.back()->stopTimer();
248 }
249 Timer &MyTimer = getPassTimer(PassID, /*IsPass*/ true);
250 PassActiveTimerStack.push_back(&MyTimer);
251 assert(!MyTimer.isRunning());
252 MyTimer.startTimer();
253}
254
255void TimePassesHandler::stopPassTimer(StringRef PassID) {
256 if (shouldIgnorePass(PassID))
257 return;
258 assert(!PassActiveTimerStack.empty() && "empty stack in popTimer");
259 Timer *MyTimer = PassActiveTimerStack.pop_back_val();
260 assert(MyTimer && "timer should be present");
261 assert(MyTimer->isRunning());
262 MyTimer->stopTimer();
263
264 // Restart the previously stopped timer.
265 if (!PassActiveTimerStack.empty()) {
266 assert(!PassActiveTimerStack.back()->isRunning());
267 PassActiveTimerStack.back()->startTimer();
268 }
269}
270
271void TimePassesHandler::startAnalysisTimer(StringRef PassID) {
272 // Stop the previous analysis timer to prevent double counting when an
273 // analysis requests another analysis.
274 if (!AnalysisActiveTimerStack.empty()) {
275 assert(AnalysisActiveTimerStack.back()->isRunning());
276 AnalysisActiveTimerStack.back()->stopTimer();
277 }
278
279 Timer &MyTimer = getPassTimer(PassID, /*IsPass*/ false);
280 AnalysisActiveTimerStack.push_back(&MyTimer);
281 if (!MyTimer.isRunning())
282 MyTimer.startTimer();
283}
284
285void TimePassesHandler::stopAnalysisTimer(StringRef PassID) {
286 assert(!AnalysisActiveTimerStack.empty() && "empty stack in popTimer");
287 Timer *MyTimer = AnalysisActiveTimerStack.pop_back_val();
288 assert(MyTimer && "timer should be present");
289 if (MyTimer->isRunning())
290 MyTimer->stopTimer();
291
292 // Restart the previously stopped timer.
293 if (!AnalysisActiveTimerStack.empty()) {
294 assert(!AnalysisActiveTimerStack.back()->isRunning());
295 AnalysisActiveTimerStack.back()->startTimer();
296 }
297}
298
300 if (!Enabled)
301 return;
302
303 PIC.registerBeforeNonSkippedPassCallback(
304 [this](StringRef P, Any) { this->startPassTimer(P); });
305 PIC.registerAfterPassCallback(
306 [this](StringRef P, Any, const PreservedAnalyses &) {
307 this->stopPassTimer(P);
308 });
309 PIC.registerAfterPassInvalidatedCallback(
310 [this](StringRef P, const PreservedAnalyses &) {
311 this->stopPassTimer(P);
312 });
313 PIC.registerBeforeAnalysisCallback(
314 [this](StringRef P, Any) { this->startAnalysisTimer(P); });
315 PIC.registerAfterAnalysisCallback(
316 [this](StringRef P, Any) { this->stopAnalysisTimer(P); });
317}
318
319} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:638
#define I(x, y, z)
Definition MD5.cpp:58
#define T
#define P(N)
PassInstrumentationCallbacks PIC
This file defines the Pass Instrumentation classes that provide instrumentation points into the pass ...
This header defines classes/functions to handle pass execution timing information with interfaces for...
Shrink Wrap Pass
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
static const char PassName[]
This class manages callbacks registration, as well as provides a way for PassInstrumentation to pass ...
Pass interface - Implemented by all 'passes'.
Definition Pass.h:99
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:133
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
std::string str() const
str - Get the contents as an std::string.
Definition StringRef.h:233
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:151
LLVM_ABI void registerCallbacks(PassInstrumentationCallbacks &PIC)
static constexpr StringRef PassGroupDesc
static constexpr StringRef PassGroupName
LLVM_ABI void print()
Prints out timing information and then resets the timers.
LLVM_ABI void setOutStream(raw_ostream &OutStream)
Set a custom output stream for subsequent reporting.
The TimerGroup class is used to group together related timers into a single report that is printed wh...
Definition Timer.h:186
LLVM_ABI void print(raw_ostream &OS, bool ResetAfterPrint=false)
Print any started timers in this group, optionally resetting timers after printing them.
Definition Timer.cpp:411
This class is used to track the amount of time spent between invocations of its startTimer()/stopTime...
Definition Timer.h:82
bool hasTriggered() const
Check if startTimer() has ever been called on this timer.
Definition Timer.h:123
bool isRunning() const
Check if the timer is currently running.
Definition Timer.h:120
LLVM_ABI void stopTimer()
Stop the timer.
Definition Timer.cpp:158
LLVM_ABI void startTimer()
Start the timer running.
Definition Timer.cpp:149
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
cb< typename detail::callback_traits< F >::result_type, typename detail::callback_traits< F >::arg_type > callback(F CB)
std::lock_guard< SmartMutex< mt_only > > SmartScopedLock
Definition Mutex.h:69
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::unique_ptr< raw_ostream > CreateInfoOutputFile()
Return a stream to print our output on.
Definition Timer.cpp:65
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr, unsigned DynamicVGPRBlockSize=0)
static cl::opt< bool, true > EnableTimingPerRun("time-passes-per-run", cl::location(TimePassesPerRun), cl::Hidden, cl::desc("Time each pass run, printing elapsed time for each run on exit"), cl::callback([](const bool &) { TimePassesIsEnabled=true;}))
LLVM_GET_TYPE_NAME_CONSTEXPR StringRef getTypeName()
We provide a function which tries to compute the (demangled) name of a type statically.
Definition TypeName.h:40
LLVM_ABI bool TimePassesIsEnabled
If the user specifies the -time-passes argument on an LLVM tool command line then the value of this b...
LLVM_ABI bool TimePassesPerRun
If TimePassesPerRun is true, there would be one line of report for each pass invocation.
LLVM_ABI void reportAndResetTimings(raw_ostream *OutStream=nullptr)
If -time-passes has been specified, report the timings immediately and then reset the timers to zero.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI Timer * getPassTimer(Pass *)
Request the timer for this legacy-pass-manager's pass instance.
static bool shouldIgnorePass(StringRef PassID)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
FunctionAddr VTableAddr Count
Definition InstrProf.h:139
LLVM_ABI bool isSpecialPass(StringRef PassID, const std::vector< StringRef > &Specials)
TargetTransformInfo TTI
static cl::opt< bool, true > EnableTiming("time-passes", cl::location(TimePassesIsEnabled), cl::Hidden, cl::desc("Time each pass, printing elapsed time for each on exit"))
static LLVM_ABI TimerGroup & getNamedTimerGroup(StringRef GroupName, StringRef GroupDescription)
Definition Timer.cpp:258