1 //===- PassStatistics.cpp -------------------------------------------------===//
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 #include "PassDetail.h"
10 #include "mlir/Pass/PassManager.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/Support/Format.h"
15 using namespace mlir::detail
;
17 constexpr StringLiteral kPassStatsDescription
=
18 "... Pass statistics report ...";
21 /// Information pertaining to a specific statistic.
23 const char *name
, *desc
;
28 /// Utility to print a pass entry in the statistics output.
29 static void printPassEntry(raw_ostream
&os
, unsigned indent
, StringRef pass
,
30 MutableArrayRef
<Statistic
> stats
= std::nullopt
) {
31 os
.indent(indent
) << pass
<< "\n";
35 // Make sure to sort the statistics by name.
37 stats
.begin(), stats
.end(), [](const auto *lhs
, const auto *rhs
) {
38 return StringRef
{lhs
->name
}.compare(StringRef
{rhs
->name
});
41 // Collect the largest name and value length from each of the statistics.
42 size_t largestName
= 0, largestValue
= 0;
43 for (auto &stat
: stats
) {
44 largestName
= std::max(largestName
, (size_t)strlen(stat
.name
));
46 std::max(largestValue
, (size_t)llvm::utostr(stat
.value
).size());
49 // Print each of the statistics.
50 for (auto &stat
: stats
) {
51 os
.indent(indent
+ 2) << llvm::format("(S) %*u %-*s - %s\n", largestValue
,
52 stat
.value
, largestName
, stat
.name
,
57 /// Print the statistics results in a list form, where each pass is sorted by
59 static void printResultsAsList(raw_ostream
&os
, OpPassManager
&pm
) {
60 llvm::StringMap
<std::vector
<Statistic
>> mergedStats
;
61 std::function
<void(Pass
*)> addStats
= [&](Pass
*pass
) {
62 auto *adaptor
= dyn_cast
<OpToOpPassAdaptor
>(pass
);
64 // If this is not an adaptor, add the stats to the list if there are any.
67 auto statistics
= pass
->getStatistics();
68 if (statistics
.empty())
71 auto &passEntry
= mergedStats
[pass
->getName()];
72 if (passEntry
.empty()) {
73 for (Pass::Statistic
*it
: pass
->getStatistics())
74 passEntry
.push_back({it
->getName(), it
->getDesc(), it
->getValue()});
76 for (auto [idx
, statistic
] : llvm::enumerate(pass
->getStatistics()))
77 passEntry
[idx
].value
+= statistic
->getValue();
83 // Otherwise, recursively add each of the children.
84 for (auto &mgr
: adaptor
->getPassManagers())
85 for (Pass
&pass
: mgr
.getPasses())
88 for (Pass
&pass
: pm
.getPasses())
91 // Sort the statistics by pass name and then by record name.
92 auto passAndStatistics
=
93 llvm::to_vector
<16>(llvm::make_pointer_range(mergedStats
));
94 llvm::array_pod_sort(passAndStatistics
.begin(), passAndStatistics
.end(),
95 [](const decltype(passAndStatistics
)::value_type
*lhs
,
96 const decltype(passAndStatistics
)::value_type
*rhs
) {
97 return (*lhs
)->getKey().compare((*rhs
)->getKey());
100 // Print the timing information sequentially.
101 for (auto &statData
: passAndStatistics
)
102 printPassEntry(os
, /*indent=*/2, statData
->first(), statData
->second
);
105 /// Print the results in pipeline mode that mirrors the internal pass manager
107 static void printResultsAsPipeline(raw_ostream
&os
, OpPassManager
&pm
) {
108 #if LLVM_ENABLE_STATS
109 std::function
<void(unsigned, Pass
*)> printPass
= [&](unsigned indent
,
111 if (auto *adaptor
= dyn_cast
<OpToOpPassAdaptor
>(pass
)) {
112 // If this adaptor has more than one internal pipeline, print an entry for
114 auto mgrs
= adaptor
->getPassManagers();
115 if (mgrs
.size() > 1) {
116 printPassEntry(os
, indent
, adaptor
->getAdaptorName());
120 // Print each of the children passes.
121 for (OpPassManager
&mgr
: mgrs
) {
122 auto name
= ("'" + mgr
.getOpAnchorName() + "' Pipeline").str();
123 printPassEntry(os
, indent
, name
);
124 for (Pass
&pass
: mgr
.getPasses())
125 printPass(indent
+ 2, &pass
);
130 // Otherwise, we print the statistics for this pass.
131 std::vector
<Statistic
> stats
;
132 for (Pass::Statistic
*stat
: pass
->getStatistics())
133 stats
.push_back({stat
->getName(), stat
->getDesc(), stat
->getValue()});
134 printPassEntry(os
, indent
, pass
->getName(), stats
);
136 for (Pass
&pass
: pm
.getPasses())
137 printPass(/*indent=*/0, &pass
);
141 static void printStatistics(OpPassManager
&pm
, PassDisplayMode displayMode
) {
142 auto os
= llvm::CreateInfoOutputFile();
144 // Print the stats header.
145 *os
<< "===" << std::string(73, '-') << "===\n";
146 // Figure out how many spaces for the description name.
147 unsigned padding
= (80 - kPassStatsDescription
.size()) / 2;
148 os
->indent(padding
) << kPassStatsDescription
<< '\n';
149 *os
<< "===" << std::string(73, '-') << "===\n";
151 // Defer to a specialized printer for each display mode.
152 switch (displayMode
) {
153 case PassDisplayMode::List
:
154 printResultsAsList(*os
, pm
);
156 case PassDisplayMode::Pipeline
:
157 printResultsAsPipeline(*os
, pm
);
164 //===----------------------------------------------------------------------===//
166 //===----------------------------------------------------------------------===//
168 Pass::Statistic::Statistic(Pass
*owner
, const char *name
,
169 const char *description
)
170 : llvm::Statistic
{/*DebugType=*/"", name
, description
} {
171 #if LLVM_ENABLE_STATS
172 // Always set the 'initialized' bit to true so that this statistic isn't
173 // placed in the static registry.
174 // TODO: This is sort of hack as `llvm::Statistic`s can't be setup to avoid
175 // automatic registration with the global registry. We should either add
176 // support for this in LLVM, or just write our own statistics classes.
180 // Register this statistic with the parent.
181 owner
->statistics
.push_back(this);
184 auto Pass::Statistic::operator=(unsigned value
) -> Statistic
& {
185 llvm::Statistic::operator=(value
);
189 //===----------------------------------------------------------------------===//
191 //===----------------------------------------------------------------------===//
193 /// Merge the pass statistics of this class into 'other'.
194 void OpPassManager::mergeStatisticsInto(OpPassManager
&other
) {
195 auto passes
= getPasses(), otherPasses
= other
.getPasses();
197 for (auto passPair
: llvm::zip(passes
, otherPasses
)) {
198 Pass
&pass
= std::get
<0>(passPair
), &otherPass
= std::get
<1>(passPair
);
200 // If this is an adaptor, then recursively merge the pass managers.
201 if (auto *adaptorPass
= dyn_cast
<OpToOpPassAdaptor
>(&pass
)) {
202 auto *otherAdaptorPass
= cast
<OpToOpPassAdaptor
>(&otherPass
);
203 for (auto mgrs
: llvm::zip(adaptorPass
->getPassManagers(),
204 otherAdaptorPass
->getPassManagers()))
205 std::get
<0>(mgrs
).mergeStatisticsInto(std::get
<1>(mgrs
));
208 // Otherwise, merge the statistics for the current pass.
209 assert(pass
.statistics
.size() == otherPass
.statistics
.size());
210 for (unsigned i
= 0, e
= pass
.statistics
.size(); i
!= e
; ++i
) {
211 assert(pass
.statistics
[i
]->getName() ==
212 StringRef(otherPass
.statistics
[i
]->getName()));
213 *otherPass
.statistics
[i
] += *pass
.statistics
[i
];
214 *pass
.statistics
[i
] = 0;
219 /// Prepare the statistics of passes within the given pass manager for
220 /// consumption(e.g. dumping).
221 static void prepareStatistics(OpPassManager
&pm
) {
222 for (Pass
&pass
: pm
.getPasses()) {
223 OpToOpPassAdaptor
*adaptor
= dyn_cast
<OpToOpPassAdaptor
>(&pass
);
226 MutableArrayRef
<OpPassManager
> nestedPms
= adaptor
->getPassManagers();
228 // Merge the statistics from the async pass managers into the main nested
229 // pass managers. Prepare recursively before merging.
230 for (auto &asyncPM
: adaptor
->getParallelPassManagers()) {
231 for (unsigned i
= 0, e
= asyncPM
.size(); i
!= e
; ++i
) {
232 prepareStatistics(asyncPM
[i
]);
233 asyncPM
[i
].mergeStatisticsInto(nestedPms
[i
]);
237 // Prepare the statistics of each of the nested passes.
238 for (OpPassManager
&nestedPM
: nestedPms
)
239 prepareStatistics(nestedPM
);
243 /// Dump the statistics of the passes within this pass manager.
244 void PassManager::dumpStatistics() {
245 prepareStatistics(*this);
246 printStatistics(*this, *passStatisticsMode
);
249 /// Dump the statistics for each pass after running.
250 void PassManager::enableStatistics(PassDisplayMode displayMode
) {
251 passStatisticsMode
= displayMode
;