Skip to content

Commit b2b4d52

Browse files
committed
Use global TimerGroups for both new pass manager and old pass manager timers
Additionally, remove the behavior for both pass manager's timer manager classes (`PassTimingInfo` for the old pass manager and `TimePassesHandler` for the new pass manager) where these classes would print the values of their timers upon destruction. Currently, each pass manager manages their own `TimerGroup`s. This is problematic because of duplicate `TimerGroup`s (both pass managers have a `TimerGroup` for pass times with identical names and descriptions). The result is that in Clang, `-ftime-report` has two "Pass execution timing report" sections (one for the new pass manager which manages optimization passes, and one for the old pass manager which manages the backend). The result of this change is that Clang's `-ftime-report` now prints both optimization and backend pass timing info in a unified "Pass execution timing report" section. Moving the ownership of the `TimerGroups` to globals also makes it easier to implement JSON-formatted `-ftime-report`. This was not possible with the old structure because the two pass managers were created and destroyed in far parts of the codebase and outputting JSON requires the printing logic to be at the same place because of formatting. Previous discourse discussion: https://discourse.llvm.org/t/difficulties-with-implementing-json-formatted-ftime-report/84353
1 parent ab87206 commit b2b4d52

File tree

6 files changed

+79
-51
lines changed

6 files changed

+79
-51
lines changed

clang/test/Misc/time-passes.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,5 @@
1919
// NPM: InstCombinePass{{$}}
2020
// NPM-NOT: InstCombinePass #
2121
// TIME: Total{{$}}
22-
// NPM: Pass execution timing report
2322

2423
int foo(int x, int y) { return x + y; }

llvm/include/llvm/IR/PassTimingInfo.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,14 @@ Timer *getPassTimer(Pass *);
3939
/// This class implements -time-passes functionality for new pass manager.
4040
/// It provides the pass-instrumentation callbacks that measure the pass
4141
/// execution time. They collect timing info into individual timers as
42-
/// passes are being run. At the end of its life-time it prints the resulting
43-
/// timing report.
42+
/// passes are being run.
4443
class TimePassesHandler {
4544
/// Value of this type is capable of uniquely identifying pass invocations.
4645
/// It is a pair of string Pass-Identifier (which for now is common
4746
/// to all the instance of a given pass) + sequential invocation counter.
4847
using PassInvocationID = std::pair<StringRef, unsigned>;
4948

50-
/// Groups of timers for passes and analyses.
51-
TimerGroup PassTG;
52-
TimerGroup AnalysisTG;
53-
54-
using TimerVector = llvm::SmallVector<std::unique_ptr<Timer>, 4>;
49+
using TimerVector = llvm::SmallVector<Timer *, 4>;
5550
/// Map of timers for pass invocations
5651
StringMap<TimerVector> TimingData;
5752

@@ -74,8 +69,7 @@ class TimePassesHandler {
7469
TimePassesHandler();
7570
TimePassesHandler(bool Enabled, bool PerRun = false);
7671

77-
/// Destructor handles the print action if it has not been handled before.
78-
~TimePassesHandler() { print(); }
72+
~TimePassesHandler() = default;
7973

8074
/// Prints out timing information and then resets the timers.
8175
void print();

llvm/include/llvm/Support/Timer.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,17 @@ struct NamedRegionTimer : public TimeRegion {
169169
explicit NamedRegionTimer(StringRef Name, StringRef Description,
170170
StringRef GroupName,
171171
StringRef GroupDescription, bool Enabled = true);
172+
173+
// Create or get a timer stored in the same global map as other timers owned
174+
// by NamedRegionTimer.
175+
static Timer &getNamedGroupTimer(StringRef Name, StringRef Description,
176+
StringRef GroupName,
177+
StringRef GroupDescription);
178+
179+
// Create or get a TimerGroup stored in the same global map owned by
180+
// NamedRegionTimer.
181+
static TimerGroup &getNamedGroupTimerGroup(StringRef GroupName,
182+
StringRef GroupDescription);
172183
};
173184

174185
/// The TimerGroup class is used to group together related timers into a single

llvm/lib/IR/PassTimingInfo.cpp

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ namespace llvm {
3737
bool TimePassesIsEnabled = false;
3838
bool TimePassesPerRun = false;
3939

40+
static constexpr StringRef PassGroupName = "pass";
41+
static constexpr StringRef AnalysisGroupName = "analysis";
42+
static constexpr StringRef PassGroupDesc = "Pass execution timing report";
43+
static constexpr StringRef AnalysisGroupDesc =
44+
"Analysis execution timing report";
45+
4046
static cl::opt<bool, true> EnableTiming(
4147
"time-passes", cl::location(TimePassesIsEnabled), cl::Hidden,
4248
cl::desc("Time each pass, printing elapsed time for each on exit"));
@@ -62,16 +68,12 @@ class PassTimingInfo {
6268

6369
private:
6470
StringMap<unsigned> PassIDCountMap; ///< Map that counts instances of passes
65-
DenseMap<PassInstanceID, std::unique_ptr<Timer>> TimingData; ///< timers for pass instances
66-
TimerGroup TG;
71+
DenseMap<PassInstanceID, Timer *> TimingData; ///< timers for pass instances
6772

6873
public:
69-
/// Default constructor for yet-inactive timeinfo.
70-
/// Use \p init() to activate it.
71-
PassTimingInfo();
74+
PassTimingInfo() = default;
7275

73-
/// Print out timing information and release timers.
74-
~PassTimingInfo();
76+
~PassTimingInfo() = default;
7577

7678
/// Initializes the static \p TheTimeInfo member to a non-null value when
7779
/// -time-passes is enabled. Leaves it null otherwise.
@@ -94,14 +96,6 @@ class PassTimingInfo {
9496

9597
static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex;
9698

97-
PassTimingInfo::PassTimingInfo() : TG("pass", "Pass execution timing report") {}
98-
99-
PassTimingInfo::~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-
10599
void PassTimingInfo::init() {
106100
if (TheTimeInfo || !TimePassesIsEnabled)
107101
return;
@@ -115,7 +109,8 @@ void PassTimingInfo::init() {
115109

116110
/// Prints out timing information and then resets the timers.
117111
void PassTimingInfo::print(raw_ostream *OutStream) {
118-
TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
112+
NamedRegionTimer::getNamedGroupTimerGroup(PassGroupName, PassGroupDesc)
113+
.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
119114
}
120115

121116
Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
@@ -124,7 +119,8 @@ Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
124119
// Appending description with a pass-instance number for all but the first one
125120
std::string PassDescNumbered =
126121
num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
127-
return new Timer(PassID, PassDescNumbered, TG);
122+
return &NamedRegionTimer::getNamedGroupTimer(PassID, PassDescNumbered,
123+
PassGroupName, PassGroupDesc);
128124
}
129125

130126
Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
@@ -133,16 +129,16 @@ Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
133129

134130
init();
135131
sys::SmartScopedLock<true> Lock(*TimingInfoMutex);
136-
std::unique_ptr<Timer> &T = TimingData[Pass];
132+
Timer *&T = TimingData[Pass];
137133

138134
if (!T) {
139135
StringRef PassName = P->getPassName();
140136
StringRef PassArgument;
141137
if (const PassInfo *PI = Pass::lookupPassInfo(P->getPassID()))
142138
PassArgument = PI->getPassArgument();
143-
T.reset(newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName));
139+
T = newPassTimer(PassArgument.empty() ? PassName : PassArgument, PassName);
144140
}
145-
return T.get();
141+
return T;
146142
}
147143

148144
PassTimingInfo *PassTimingInfo::TheTimeInfo;
@@ -170,11 +166,13 @@ void reportAndResetTimings(raw_ostream *OutStream) {
170166
/// Returns the timer for the specified pass invocation of \p PassID.
171167
/// Each time it creates a new timer.
172168
Timer &TimePassesHandler::getPassTimer(StringRef PassID, bool IsPass) {
173-
TimerGroup &TG = IsPass ? PassTG : AnalysisTG;
169+
StringRef TGName = IsPass ? PassGroupName : PassGroupDesc;
170+
StringRef TGDesc = IsPass ? PassGroupDesc : AnalysisGroupDesc;
171+
TimerGroup &TG = NamedRegionTimer::getNamedGroupTimerGroup(TGName, TGDesc);
174172
if (!PerRun) {
175173
TimerVector &Timers = TimingData[PassID];
176174
if (Timers.size() == 0)
177-
Timers.emplace_back(new Timer(PassID, PassID, TG));
175+
Timers.push_back(new Timer(PassID, PassID, TG));
178176
return *Timers.front();
179177
}
180178

@@ -186,16 +184,14 @@ Timer &TimePassesHandler::getPassTimer(StringRef PassID, bool IsPass) {
186184
std::string FullDesc = formatv("{0} #{1}", PassID, Count).str();
187185

188186
Timer *T = new Timer(PassID, FullDesc, TG);
189-
Timers.emplace_back(T);
187+
Timers.push_back(T);
190188
assert(Count == Timers.size() && "Timers vector not adjusted correctly.");
191189

192190
return *T;
193191
}
194192

195193
TimePassesHandler::TimePassesHandler(bool Enabled, bool PerRun)
196-
: PassTG("pass", "Pass execution timing report"),
197-
AnalysisTG("analysis", "Analysis execution timing report"),
198-
Enabled(Enabled), PerRun(PerRun) {}
194+
: Enabled(Enabled), PerRun(PerRun) {}
199195

200196
TimePassesHandler::TimePassesHandler()
201197
: TimePassesHandler(TimePassesIsEnabled, TimePassesPerRun) {}
@@ -215,8 +211,12 @@ void TimePassesHandler::print() {
215211
MaybeCreated = CreateInfoOutputFile();
216212
OS = &*MaybeCreated;
217213
}
218-
PassTG.print(*OS, true);
219-
AnalysisTG.print(*OS, true);
214+
215+
NamedRegionTimer::getNamedGroupTimerGroup(PassGroupName, PassGroupDesc)
216+
.print(*OS, true);
217+
NamedRegionTimer::getNamedGroupTimerGroup(AnalysisGroupName,
218+
AnalysisGroupDesc)
219+
.print(*OS, true);
220220
}
221221

222222
LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
@@ -226,7 +226,7 @@ LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
226226
StringRef PassID = I.getKey();
227227
const TimerVector& MyTimers = I.getValue();
228228
for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
229-
const Timer* MyTimer = MyTimers[idx].get();
229+
const Timer *MyTimer = MyTimers[idx];
230230
if (MyTimer && MyTimer->isRunning())
231231
dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
232232
}
@@ -236,7 +236,7 @@ LLVM_DUMP_METHOD void TimePassesHandler::dump() const {
236236
StringRef PassID = I.getKey();
237237
const TimerVector& MyTimers = I.getValue();
238238
for (unsigned idx = 0; idx < MyTimers.size(); idx++) {
239-
const Timer* MyTimer = MyTimers[idx].get();
239+
const Timer *MyTimer = MyTimers[idx];
240240
if (MyTimer && MyTimer->hasTriggered() && !MyTimer->isRunning())
241241
dbgs() << "\tTimer " << MyTimer << " for pass " << PassID << "(" << idx << ")\n";
242242
}

llvm/lib/Support/Timer.cpp

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,27 +222,51 @@ class Name2PairMap {
222222
StringRef GroupDescription) {
223223
sys::SmartScopedLock<true> L(timerLock());
224224

225-
std::pair<TimerGroup*, Name2TimerMap> &GroupEntry = Map[GroupName];
226-
227-
if (!GroupEntry.first)
228-
GroupEntry.first = new TimerGroup(GroupName, GroupDescription);
229-
225+
std::pair<TimerGroup *, Name2TimerMap> &GroupEntry =
226+
getGroupEntry(GroupName, GroupDescription);
230227
Timer &T = GroupEntry.second[Name];
231228
if (!T.isInitialized())
232229
T.init(Name, Description, *GroupEntry.first);
233230
return T;
234231
}
232+
233+
TimerGroup &getTimerGroup(StringRef GroupName, StringRef GroupDescription) {
234+
return *getGroupEntry(GroupName, GroupDescription).first;
235+
}
236+
237+
private:
238+
std::pair<TimerGroup *, Name2TimerMap> &
239+
getGroupEntry(StringRef GroupName, StringRef GroupDescription) {
240+
std::pair<TimerGroup *, Name2TimerMap> &GroupEntry = Map[GroupName];
241+
if (!GroupEntry.first)
242+
GroupEntry.first = new TimerGroup(GroupName, GroupDescription);
243+
244+
return GroupEntry;
245+
}
235246
};
236247

237248
}
238249

239250
NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef Description,
240251
StringRef GroupName,
241252
StringRef GroupDescription, bool Enabled)
242-
: TimeRegion(!Enabled
243-
? nullptr
244-
: &namedGroupedTimers().get(Name, Description, GroupName,
245-
GroupDescription)) {}
253+
: TimeRegion(!Enabled ? nullptr
254+
: &getNamedGroupTimer(Name, Description, GroupName,
255+
GroupDescription)) {}
256+
257+
Timer &NamedRegionTimer::getNamedGroupTimer(StringRef Name,
258+
StringRef Description,
259+
StringRef GroupName,
260+
StringRef GroupDescription) {
261+
return namedGroupedTimers().get(Name, Description, GroupName,
262+
GroupDescription);
263+
}
264+
265+
TimerGroup &
266+
NamedRegionTimer::getNamedGroupTimerGroup(StringRef GroupName,
267+
StringRef GroupDescription) {
268+
return namedGroupedTimers().getTimerGroup(GroupName, GroupDescription);
269+
}
246270

247271
//===----------------------------------------------------------------------===//
248272
// TimerGroup Implementation

llvm/unittests/IR/TimePassesTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ TEST(TimePassesTest, CustomOut) {
161161
PI.runBeforePass(Pass2, M);
162162
PI.runAfterPass(Pass2, M, PreservedAnalyses::all());
163163

164-
// Generate report by deleting the handler.
165-
TimePasses.reset();
164+
// Clear and generate report again.
165+
TimePasses->print();
166166

167167
// There should be Pass2 in this report and no Pass1.
168168
EXPECT_FALSE(TimePassesStr.str().empty());

0 commit comments

Comments
 (0)