Skip to content

Commit 09d8e44

Browse files
authored
[llvm][Timer] Use global TimerGroups for both new pass manager and old pass manager timers (#130375)
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 09a36c8 commit 09d8e44

File tree

6 files changed

+48
-36
lines changed

6 files changed

+48
-36
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: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,18 @@ 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

5049
/// Groups of timers for passes and analyses.
51-
TimerGroup PassTG;
52-
TimerGroup AnalysisTG;
50+
TimerGroup &PassTG =
51+
NamedRegionTimer::getNamedTimerGroup(PassGroupName, PassGroupDesc);
52+
TimerGroup &AnalysisTG = NamedRegionTimer::getNamedTimerGroup(
53+
AnalysisGroupName, AnalysisGroupDesc);
5354

5455
using TimerVector = llvm::SmallVector<std::unique_ptr<Timer>, 4>;
5556
/// Map of timers for pass invocations
@@ -71,12 +72,15 @@ class TimePassesHandler {
7172
bool PerRun;
7273

7374
public:
75+
static constexpr StringRef PassGroupName = "pass";
76+
static constexpr StringRef AnalysisGroupName = "analysis";
77+
static constexpr StringRef PassGroupDesc = "Pass execution timing report";
78+
static constexpr StringRef AnalysisGroupDesc =
79+
"Analysis execution timing report";
80+
7481
TimePassesHandler();
7582
TimePassesHandler(bool Enabled, bool PerRun = false);
7683

77-
/// Destructor handles the print action if it has not been handled before.
78-
~TimePassesHandler() { print(); }
79-
8084
/// Prints out timing information and then resets the timers.
8185
void print();
8286

llvm/include/llvm/Support/Timer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ 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 TimerGroup stored in the same global map owned by
174+
// NamedRegionTimer.
175+
static TimerGroup &getNamedTimerGroup(StringRef GroupName,
176+
StringRef GroupDescription);
172177
};
173178

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

llvm/lib/IR/PassTimingInfo.cpp

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,9 @@ class PassTimingInfo {
6363
private:
6464
StringMap<unsigned> PassIDCountMap; ///< Map that counts instances of passes
6565
DenseMap<PassInstanceID, std::unique_ptr<Timer>> TimingData; ///< timers for pass instances
66-
TimerGroup TG;
66+
TimerGroup *PassTG = nullptr;
6767

6868
public:
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-
7669
/// Initializes the static \p TheTimeInfo member to a non-null value when
7770
/// -time-passes is enabled. Leaves it null otherwise.
7871
///
@@ -94,14 +87,6 @@ class PassTimingInfo {
9487

9588
static ManagedStatic<sys::SmartMutex<true>> TimingInfoMutex;
9689

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-
10590
void PassTimingInfo::init() {
10691
if (TheTimeInfo || !TimePassesIsEnabled)
10792
return;
@@ -110,12 +95,16 @@ void PassTimingInfo::init() {
11095
// This guarantees that the object will be constructed after static globals,
11196
// thus it will be destroyed before them.
11297
static ManagedStatic<PassTimingInfo> TTI;
98+
if (!TTI->PassTG)
99+
TTI->PassTG = &NamedRegionTimer::getNamedTimerGroup(
100+
TimePassesHandler::PassGroupName, TimePassesHandler::PassGroupDesc);
113101
TheTimeInfo = &*TTI;
114102
}
115103

116104
/// Prints out timing information and then resets the timers.
117105
void PassTimingInfo::print(raw_ostream *OutStream) {
118-
TG.print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
106+
assert(PassTG && "PassTG is null, did you call PassTimingInfo::Init()?");
107+
PassTG->print(OutStream ? *OutStream : *CreateInfoOutputFile(), true);
119108
}
120109

121110
Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
@@ -124,7 +113,8 @@ Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) {
124113
// Appending description with a pass-instance number for all but the first one
125114
std::string PassDescNumbered =
126115
num <= 1 ? PassDesc.str() : formatv("{0} #{1}", PassDesc, num).str();
127-
return new Timer(PassID, PassDescNumbered, TG);
116+
assert(PassTG && "PassTG is null, did you call PassTimingInfo::Init()?");
117+
return new Timer(PassID, PassDescNumbered, *PassTG);
128118
}
129119

130120
Timer *PassTimingInfo::getPassTimer(Pass *P, PassInstanceID Pass) {
@@ -193,9 +183,7 @@ Timer &TimePassesHandler::getPassTimer(StringRef PassID, bool IsPass) {
193183
}
194184

195185
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) {}
186+
: Enabled(Enabled), PerRun(PerRun) {}
199187

200188
TimePassesHandler::TimePassesHandler()
201189
: TimePassesHandler(TimePassesIsEnabled, TimePassesPerRun) {}

llvm/lib/Support/Timer.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,16 +222,27 @@ 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
}
@@ -244,6 +255,11 @@ NamedRegionTimer::NamedRegionTimer(StringRef Name, StringRef Description,
244255
: &namedGroupedTimers().get(Name, Description, GroupName,
245256
GroupDescription)) {}
246257

258+
TimerGroup &NamedRegionTimer::getNamedTimerGroup(StringRef GroupName,
259+
StringRef GroupDescription) {
260+
return namedGroupedTimers().getTimerGroup(GroupName, GroupDescription);
261+
}
262+
247263
//===----------------------------------------------------------------------===//
248264
// TimerGroup Implementation
249265
//===----------------------------------------------------------------------===//

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)