1 //===- PassTimingInfo.cpp - LLVM Pass Timing Implementation ---------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the LLVM Pass Timing infrastructure for both
10 // new and legacy pass managers.
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.
16 //===----------------------------------------------------------------------===//
18 #include "llvm/IR/PassTimingInfo.h"
19 #include "llvm/ADT/DenseMap.h"
20 #include "llvm/ADT/Statistic.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/IR/PassInstrumentation.h"
23 #include "llvm/Pass.h"
24 #include "llvm/Support/CommandLine.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/FormatVariadic.h"
27 #include "llvm/Support/ManagedStatic.h"
28 #include "llvm/Support/Mutex.h"
29 #include "llvm/Support/Timer.h"
30 #include "llvm/Support/raw_ostream.h"
36 #define DEBUG_TYPE "time-passes"
40 bool TimePassesIsEnabled
= false;
42 static cl::opt
<bool, true> EnableTiming(
43 "time-passes", cl::location(TimePassesIsEnabled
), cl::Hidden
,
44 cl::desc("Time each pass, printing elapsed time for each on exit"));
49 //===----------------------------------------------------------------------===//
50 // Legacy pass manager's PassTimingInfo implementation
52 /// Provides an interface for collecting pass timing information.
54 /// It was intended to be generic but now we decided to split
55 /// interfaces completely. This is now exclusively for legacy-pass-manager use.
56 class PassTimingInfo
{
58 using PassInstanceID
= void *;
61 StringMap
<unsigned> PassIDCountMap
; ///< Map that counts instances of passes
62 DenseMap
<PassInstanceID
, std::unique_ptr
<Timer
>> TimingData
; ///< timers for pass instances
66 /// Default constructor for yet-inactive timeinfo.
67 /// Use \p init() to activate it.
70 /// Print out timing information and release timers.
73 /// Initializes the static \p TheTimeInfo member to a non-null value when
74 /// -time-passes is enabled. Leaves it null otherwise.
76 /// This method may be called multiple times.
79 /// Prints out timing information and then resets the timers.
80 /// By default it uses the stream created by CreateInfoOutputFile().
81 void print(raw_ostream
*OutStream
= nullptr);
83 /// Returns the timer for the specified pass if it exists.
84 Timer
*getPassTimer(Pass
*, PassInstanceID
);
86 static PassTimingInfo
*TheTimeInfo
;
89 Timer
*newPassTimer(StringRef PassID
, StringRef PassDesc
);
92 static ManagedStatic
<sys::SmartMutex
<true>> TimingInfoMutex
;
94 PassTimingInfo::PassTimingInfo()
95 : TG("pass", "... Pass execution timing report ...") {}
97 PassTimingInfo::~PassTimingInfo() {
98 // Deleting the timers accumulates their info into the TG member.
99 // Then TG member is (implicitly) deleted, actually printing the report.
103 void PassTimingInfo::init() {
104 if (!TimePassesIsEnabled
|| TheTimeInfo
)
107 // Constructed the first time this is called, iff -time-passes is enabled.
108 // This guarantees that the object will be constructed after static globals,
109 // thus it will be destroyed before them.
110 static ManagedStatic
<PassTimingInfo
> TTI
;
114 /// Prints out timing information and then resets the timers.
115 void PassTimingInfo::print(raw_ostream
*OutStream
) {
116 TG
.print(OutStream
? *OutStream
: *CreateInfoOutputFile(), true);
119 Timer
*PassTimingInfo::newPassTimer(StringRef PassID
, StringRef PassDesc
) {
120 unsigned &num
= PassIDCountMap
[PassID
];
122 // Appending description with a pass-instance number for all but the first one
123 std::string PassDescNumbered
=
124 num
<= 1 ? PassDesc
.str() : formatv("{0} #{1}", PassDesc
, num
).str();
125 return new Timer(PassID
, PassDescNumbered
, TG
);
128 Timer
*PassTimingInfo::getPassTimer(Pass
*P
, PassInstanceID Pass
) {
129 if (P
->getAsPMDataManager())
133 sys::SmartScopedLock
<true> Lock(*TimingInfoMutex
);
134 std::unique_ptr
<Timer
> &T
= TimingData
[Pass
];
137 StringRef PassName
= P
->getPassName();
138 StringRef PassArgument
;
139 if (const PassInfo
*PI
= Pass::lookupPassInfo(P
->getPassID()))
140 PassArgument
= PI
->getPassArgument();
141 T
.reset(newPassTimer(PassArgument
.empty() ? PassName
: PassArgument
, PassName
));
146 PassTimingInfo
*PassTimingInfo::TheTimeInfo
;
147 } // namespace legacy
150 Timer
*getPassTimer(Pass
*P
) {
151 legacy::PassTimingInfo::init();
152 if (legacy::PassTimingInfo::TheTimeInfo
)
153 return legacy::PassTimingInfo::TheTimeInfo
->getPassTimer(P
, P
);
157 /// If timing is enabled, report the times collected up to now and then reset
159 void reportAndResetTimings(raw_ostream
*OutStream
) {
160 if (legacy::PassTimingInfo::TheTimeInfo
)
161 legacy::PassTimingInfo::TheTimeInfo
->print(OutStream
);
164 //===----------------------------------------------------------------------===//
165 // Pass timing handling for the New Pass Manager
166 //===----------------------------------------------------------------------===//
168 /// Returns the timer for the specified pass invocation of \p PassID.
169 /// Each time it creates a new timer.
170 Timer
&TimePassesHandler::getPassTimer(StringRef PassID
) {
171 // Bump counts for each request of the timer.
172 unsigned Count
= nextPassID(PassID
);
174 // Unconditionally appending description with a pass-invocation number.
175 std::string FullDesc
= formatv("{0} #{1}", PassID
, Count
).str();
177 PassInvocationID UID
{PassID
, Count
};
178 Timer
*T
= new Timer(PassID
, FullDesc
, TG
);
179 auto Pair
= TimingData
.try_emplace(UID
, T
);
180 assert(Pair
.second
&& "should always create a new timer");
181 return *(Pair
.first
->second
.get());
184 TimePassesHandler::TimePassesHandler(bool Enabled
)
185 : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled
) {}
187 void TimePassesHandler::setOutStream(raw_ostream
&Out
) {
191 void TimePassesHandler::print() {
194 TG
.print(OutStream
? *OutStream
: *CreateInfoOutputFile(), true);
197 LLVM_DUMP_METHOD
void TimePassesHandler::dump() const {
198 dbgs() << "Dumping timers for " << getTypeName
<TimePassesHandler
>()
199 << ":\n\tRunning:\n";
200 for (auto &I
: TimingData
) {
201 const Timer
*MyTimer
= I
.second
.get();
202 if (!MyTimer
|| MyTimer
->isRunning())
203 dbgs() << "\tTimer " << MyTimer
<< " for pass " << I
.first
.first
<< "("
204 << I
.first
.second
<< ")\n";
206 dbgs() << "\tTriggered:\n";
207 for (auto &I
: TimingData
) {
208 const Timer
*MyTimer
= I
.second
.get();
209 if (!MyTimer
|| (MyTimer
->hasTriggered() && !MyTimer
->isRunning()))
210 dbgs() << "\tTimer " << MyTimer
<< " for pass " << I
.first
.first
<< "("
211 << I
.first
.second
<< ")\n";
215 void TimePassesHandler::startTimer(StringRef PassID
) {
216 Timer
&MyTimer
= getPassTimer(PassID
);
217 TimerStack
.push_back(&MyTimer
);
218 if (!MyTimer
.isRunning())
219 MyTimer
.startTimer();
222 void TimePassesHandler::stopTimer(StringRef PassID
) {
223 assert(TimerStack
.size() > 0 && "empty stack in popTimer");
224 Timer
*MyTimer
= TimerStack
.pop_back_val();
225 assert(MyTimer
&& "timer should be present");
226 if (MyTimer
->isRunning())
227 MyTimer
->stopTimer();
230 static bool matchPassManager(StringRef PassID
) {
231 size_t prefix_pos
= PassID
.find('<');
232 if (prefix_pos
== StringRef::npos
)
234 StringRef Prefix
= PassID
.substr(0, prefix_pos
);
235 return Prefix
.endswith("PassManager") || Prefix
.endswith("PassAdaptor") ||
236 Prefix
.endswith("AnalysisManagerProxy");
239 bool TimePassesHandler::runBeforePass(StringRef PassID
) {
240 if (matchPassManager(PassID
))
245 LLVM_DEBUG(dbgs() << "after runBeforePass(" << PassID
<< ")\n");
248 // we are not going to skip this pass, thus return true.
252 void TimePassesHandler::runAfterPass(StringRef PassID
) {
253 if (matchPassManager(PassID
))
258 LLVM_DEBUG(dbgs() << "after runAfterPass(" << PassID
<< ")\n");
262 void TimePassesHandler::registerCallbacks(PassInstrumentationCallbacks
&PIC
) {
266 PIC
.registerBeforePassCallback(
267 [this](StringRef P
, Any
) { return this->runBeforePass(P
); });
268 PIC
.registerAfterPassCallback(
269 [this](StringRef P
, Any
) { this->runAfterPass(P
); });
270 PIC
.registerAfterPassInvalidatedCallback(
271 [this](StringRef P
) { this->runAfterPass(P
); });
272 PIC
.registerBeforeAnalysisCallback(
273 [this](StringRef P
, Any
) { this->runBeforePass(P
); });
274 PIC
.registerAfterAnalysisCallback(
275 [this](StringRef P
, Any
) { this->runAfterPass(P
); });