LLVM 18.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 TG;
67
68public:
69 /// Default constructor for yet-inactive timeinfo.
70 /// Use \p init() to activate it.
71 PassTimingInfo();
72
73 /// Print out timing information and release timers.
74 ~PassTimingInfo();
75
76 /// Initializes the static \p TheTimeInfo member to a non-null value when
77 /// -time-passes is enabled. Leaves it null otherwise.
78 ///
79 /// This method may be called multiple times.
80 static void init();
81
82 /// Prints out timing information and then resets the timers.
83 /// By default it uses the stream created by CreateInfoOutputFile().
84 void print(raw_ostream *OutStream = nullptr);
85
86 /// Returns the timer for the specified pass if it exists.
87 Timer *getPassTimer(Pass *, PassInstanceID);
88
89 static PassTimingInfo *TheTimeInfo;
90
91private:
92 Timer *newPassTimer(StringRef PassID, StringRef PassDesc);
93};
94
95static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex;
96
97PassTimingInfo::PassTimingInfo() : TG("pass", "Pass execution timing report") {}
98
99PassTimingInfo::~PassTimingInfo() {
100 // Deleting the timers accumulates their info into the TG member.
101 // Then TG member is (implicitly) deleted, actually printing the report.
102 TimingData.clear();
103}
104
105void PassTimingInfo::init() {
106 if (!TimePassesIsEnabled || TheTimeInfo)
107 return;
108
109 // Constructed the first time this is called, iff -time-passes is enabled.
110 // This guarantees that the object will be constructed after static globals,
111 // thus it will be destroyed before them.
113 TheTimeInfo = &*TTI;
114}
115
116/// Prints out timing information and then resets the timers.
117void PassTimingInfo::print(raw_ostream *OutStream) {
118 TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
119}
120
121Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
122 unsigned &num = PassIDCountMap[PassID];
123 num++;
124 // Appending description with a pass-instance number for all but the first one
125 std::string PassDescNumbered =
126 num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
127 return new Timer(PassID, PassDescNumbered, TG);
128}
129
130Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
131 if (P->getAsPMDataManager())
132 return nullptr;
133
134 init();
135 sys::SmartScopedLock<true> Lock(*TimingInfoMutex);
136 std::unique_ptr<Timer> &T = TimingData[Pass];
137
138 if (!T) {
139 StringRef PassName = P->getPassName();
140 StringRef PassArgument;
141 if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID()))
142 PassArgument = PI->getPassArgument();
143 T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName));
144 }
145 return T.get();
146}
147
148PassTimingInfo *PassTimingInfo::TheTimeInfo;
149} // namespace legacy
150} // namespace
151
153 legacy::PassTimingInfo::init();
154 if (legacy::PassTimingInfo::TheTimeInfo)
155 return legacy::PassTimingInfo::TheTimeInfo->getPassTimer(P, P);
156 return nullptr;
157}
158
159/// If timing is enabled, report the times collected up to now and then reset
160/// them.
162 if (legacy::PassTimingInfo::TheTimeInfo)
163 legacy::PassTimingInfo::TheTimeInfo->print(OutStream);
164}
165
166//===----------------------------------------------------------------------===//
167// Pass timing handling for the New Pass Manager
168//===----------------------------------------------------------------------===//
169
170/// Returns the timer for the specified pass invocation of \p PassID.
171/// Each time it creates a new timer.
172Timer &TimePassesHandler::getPassTimer(StringRef PassID, bool IsPass) {
173 TimerGroup &TG = IsPass ? PassTG : AnalysisTG;
174 if (!PerRun) {
175 TimerVector &Timers = TimingData[PassID];
176 if (Timers.size() == 0)
177 Timers.emplace_back(new Timer(PassID, PassID, TG));
178 return *Timers.front();
179 }
180
181 // Take a vector of Timers created for this \p PassID and append
182 // one more timer to it.
183 TimerVector &Timers = TimingData[PassID];
184 unsigned Count = Timers.size() + 1;
185
186 std::string FullDesc = formatv("{0} #{1}", PassID, Count).str();
187
188 Timer *T = new Timer(PassID, FullDesc, TG);
189 Timers.emplace_back(T);
190 assert(Count == Timers.size() && "Timers vector not adjusted correctly.");
191
192 return *T;
193}
194
196 : PassTG("pass", "Pass execution timing report"),
197 AnalysisTG("analysis", "Analysis execution timing report"),
198 Enabled(Enabled), PerRun(PerRun) {}
199
202
204 OutStream = &Out;
205}
206
208 if (!Enabled)
209 return;
210 std::unique_ptr<raw_ostream> MaybeCreated;
211 raw_ostream *OS = OutStream;
212 if (OutStream) {
213 OS = OutStream;
214 } else {
215 MaybeCreated = CreateInfoOutputFile();
216 OS = &*MaybeCreated;
217 }
218 PassTG.print(*OS, true);
219 AnalysisTG.print(*OS, true);
220}
221
222LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
223 dbgs() << "Dumping timers for " << getTypeName<TimePassesHandler>()
224 << ":\n\tRunning:\n";
225 for (auto &I : TimingData) {
226 StringRef PassID = I.getKey();
227 const TimerVector& MyTimers = I.getValue();
228 for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
229 const Timer* MyTimer = MyTimers[idx].get();
230 if (MyTimer && MyTimer->isRunning())
231 dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
232 }
233 }
234 dbgs() << "\tTriggered:\n";
235 for (auto &I : TimingData) {
236 StringRef PassID = I.getKey();
237 const TimerVector& MyTimers = I.getValue();
238 for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
239 const Timer* MyTimer = MyTimers[idx].get();
240 if (MyTimer && MyTimer->hasTriggered() && !MyTimer->isRunning())
241 dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
242 }
243 }
244}
245
246static bool shouldIgnorePass(StringRef PassID) {
247 return isSpecialPass(PassID,
248 {"PassManager", "PassAdaptor", "AnalysisManagerProxy",
249 "ModuleInlinerWrapperPass", "DevirtSCCRepeatedPass"});
250}
251
252void TimePassesHandler::startPassTimer(StringRef PassID) {
253 if (shouldIgnorePass(PassID))
254 return;
255 assert(!ActivePassTimer && "should only have one pass timer at a time");
256 Timer &MyTimer = getPassTimer(PassID, /*IsPass*/ true);
257 ActivePassTimer = &MyTimer;
258 assert(!MyTimer.isRunning());
259 MyTimer.startTimer();
260}
261
262void TimePassesHandler::stopPassTimer(StringRef PassID) {
263 if (shouldIgnorePass(PassID))
264 return;
265 assert(ActivePassTimer);
266 assert(ActivePassTimer->isRunning());
267 ActivePassTimer->stopTimer();
268 ActivePassTimer = nullptr;
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
304 [this](StringRef P, Any) { this->startPassTimer(P); });
306 [this](StringRef P, Any, const PreservedAnalyses &) {
307 this->stopPassTimer(P);
308 });
310 [this](StringRef P, const PreservedAnalyses &) {
311 this->stopPassTimer(P);
312 });
314 [this](StringRef P, Any) { this->startAnalysisTimer(P); });
316 [this](StringRef P, Any) { this->stopAnalysisTimer(P); });
317}
318
319} // namespace llvm
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:510
#define I(x, y, z)
Definition: MD5.cpp:58
#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...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
static bool Enabled
Definition: Statistic.cpp:46
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
static const char PassName[]
Definition: Any.h:28
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
Definition: ManagedStatic.h:83
PassInfo class - An instance of this class exists for every pass known by the system,...
Definition: PassInfo.h:30
This class manages callbacks registration, as well as provides a way for PassInstrumentation to pass ...
void registerAfterPassInvalidatedCallback(CallableT C, bool ToFront=false)
void registerAfterAnalysisCallback(CallableT C, bool ToFront=false)
void registerBeforeNonSkippedPassCallback(CallableT C)
void registerAfterPassCallback(CallableT C, bool ToFront=false)
Pass interface - Implemented by all 'passes'.
Definition: Pass.h:94
static const PassInfo * lookupPassInfo(const void *TI)
Definition: Pass.cpp:192
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:112
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:222
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
This class implements -time-passes functionality for new pass manager.
void registerCallbacks(PassInstrumentationCallbacks &PIC)
void print()
Prints out timing information and then resets the timers.
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:173
void print(raw_ostream &OS, bool ResetAfterPrint=false)
Print any started timers in this group, optionally resetting timers after printing them.
Definition: Timer.cpp:426
This class is used to track the amount of time spent between invocations of its startTimer()/stopTime...
Definition: Timer.h:79
bool hasTriggered() const
Check if startTimer() has ever been called on this timer.
Definition: Timer.h:119
bool isRunning() const
Check if the timer is currently running.
Definition: Timer.h:116
void stopTimer()
Stop the timer.
Definition: Timer.cpp:197
void startTimer()
Start the timer running.
Definition: Timer.cpp:190
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
LocationClass< Ty > location(Ty &L)
Definition: CommandLine.h:465
cb< typename detail::callback_traits< F >::result_type, typename detail::callback_traits< F >::arg_type > callback(F CB)
Definition: CommandLine.h:517
std::lock_guard< SmartMutex< mt_only > > SmartScopedLock
Definition: Mutex.h:69
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
std::unique_ptr< raw_fd_ostream > CreateInfoOutputFile()
Return a file stream to print our output on.
Definition: Timer.cpp:96
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;}))
bool TimePassesIsEnabled
If the user specifies the -time-passes argument on an LLVM tool command line then the value of this b...
bool TimePassesPerRun
If TimePassesPerRun is true, there would be one line of report for each pass invocation.
void reportAndResetTimings(raw_ostream *OutStream=nullptr)
If -time-passes has been specified, report the timings immediately and then reset the timers to zero.
Printable print(const GCNRegPressure &RP, const GCNSubtarget *ST=nullptr)
Timer * getPassTimer(Pass *)
Request the timer for this legacy-pass-manager's pass instance.
static bool shouldIgnorePass(StringRef PassID)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
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"))