133a64540SRiver Riddle //===- PassStatistics.cpp -------------------------------------------------===//
233a64540SRiver Riddle //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633a64540SRiver Riddle //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
833a64540SRiver Riddle
933a64540SRiver Riddle #include "PassDetail.h"
1033a64540SRiver Riddle #include "mlir/Pass/PassManager.h"
1133a64540SRiver Riddle #include "llvm/ADT/StringExtras.h"
1233a64540SRiver Riddle #include "llvm/Support/Format.h"
1333a64540SRiver Riddle
1433a64540SRiver Riddle using namespace mlir;
1533a64540SRiver Riddle using namespace mlir::detail;
1633a64540SRiver Riddle
174562e389SRiver Riddle constexpr StringLiteral kPassStatsDescription =
1833a64540SRiver Riddle "... Pass statistics report ...";
1933a64540SRiver Riddle
2033a64540SRiver Riddle namespace {
2133a64540SRiver Riddle /// Information pertaining to a specific statistic.
2233a64540SRiver Riddle struct Statistic {
2333a64540SRiver Riddle const char *name, *desc;
2467dc8021SMingming Liu uint64_t value;
2533a64540SRiver Riddle };
26be0a7e9fSMehdi Amini } // namespace
2733a64540SRiver Riddle
2833a64540SRiver Riddle /// Utility to print a pass entry in the statistics output.
printPassEntry(raw_ostream & os,unsigned indent,StringRef pass,MutableArrayRef<Statistic> stats=std::nullopt)2933a64540SRiver Riddle static void printPassEntry(raw_ostream &os, unsigned indent, StringRef pass,
301a36588eSKazu Hirata MutableArrayRef<Statistic> stats = std::nullopt) {
3133a64540SRiver Riddle os.indent(indent) << pass << "\n";
3233a64540SRiver Riddle if (stats.empty())
3333a64540SRiver Riddle return;
3433a64540SRiver Riddle
3533a64540SRiver Riddle // Make sure to sort the statistics by name.
3604644a9eSSlava Zakharin llvm::array_pod_sort(
3704644a9eSSlava Zakharin stats.begin(), stats.end(), [](const auto *lhs, const auto *rhs) {
3804644a9eSSlava Zakharin return StringRef{lhs->name}.compare(StringRef{rhs->name});
3933a64540SRiver Riddle });
4033a64540SRiver Riddle
4133a64540SRiver Riddle // Collect the largest name and value length from each of the statistics.
4233a64540SRiver Riddle size_t largestName = 0, largestValue = 0;
4333a64540SRiver Riddle for (auto &stat : stats) {
4433a64540SRiver Riddle largestName = std::max(largestName, (size_t)strlen(stat.name));
4533a64540SRiver Riddle largestValue =
4633a64540SRiver Riddle std::max(largestValue, (size_t)llvm::utostr(stat.value).size());
4733a64540SRiver Riddle }
4833a64540SRiver Riddle
4933a64540SRiver Riddle // Print each of the statistics.
5033a64540SRiver Riddle for (auto &stat : stats) {
5133a64540SRiver Riddle os.indent(indent + 2) << llvm::format("(S) %*u %-*s - %s\n", largestValue,
5233a64540SRiver Riddle stat.value, largestName, stat.name,
5333a64540SRiver Riddle stat.desc);
5433a64540SRiver Riddle }
5533a64540SRiver Riddle }
5633a64540SRiver Riddle
5733a64540SRiver Riddle /// Print the statistics results in a list form, where each pass is sorted by
5833a64540SRiver Riddle /// name.
printResultsAsList(raw_ostream & os,OpPassManager & pm)5933a64540SRiver Riddle static void printResultsAsList(raw_ostream &os, OpPassManager &pm) {
6033a64540SRiver Riddle llvm::StringMap<std::vector<Statistic>> mergedStats;
6133a64540SRiver Riddle std::function<void(Pass *)> addStats = [&](Pass *pass) {
6256a69851SRiver Riddle auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass);
6333a64540SRiver Riddle
6433a64540SRiver Riddle // If this is not an adaptor, add the stats to the list if there are any.
6533a64540SRiver Riddle if (!adaptor) {
6618839be9SFangrui Song #if LLVM_ENABLE_STATS
6733a64540SRiver Riddle auto statistics = pass->getStatistics();
6833a64540SRiver Riddle if (statistics.empty())
6933a64540SRiver Riddle return;
7033a64540SRiver Riddle
7133a64540SRiver Riddle auto &passEntry = mergedStats[pass->getName()];
7233a64540SRiver Riddle if (passEntry.empty()) {
7333a64540SRiver Riddle for (Pass::Statistic *it : pass->getStatistics())
7433a64540SRiver Riddle passEntry.push_back({it->getName(), it->getDesc(), it->getValue()});
7533a64540SRiver Riddle } else {
76*8c258fdaSJakub Kuderski for (auto [idx, statistic] : llvm::enumerate(pass->getStatistics()))
77*8c258fdaSJakub Kuderski passEntry[idx].value += statistic->getValue();
7833a64540SRiver Riddle }
7918839be9SFangrui Song #endif
8033a64540SRiver Riddle return;
8133a64540SRiver Riddle }
8233a64540SRiver Riddle
8333a64540SRiver Riddle // Otherwise, recursively add each of the children.
8433a64540SRiver Riddle for (auto &mgr : adaptor->getPassManagers())
8533a64540SRiver Riddle for (Pass &pass : mgr.getPasses())
8633a64540SRiver Riddle addStats(&pass);
8733a64540SRiver Riddle };
8833a64540SRiver Riddle for (Pass &pass : pm.getPasses())
8933a64540SRiver Riddle addStats(&pass);
9033a64540SRiver Riddle
9133a64540SRiver Riddle // Sort the statistics by pass name and then by record name.
92ba8e336aSBenjamin Kramer auto passAndStatistics =
93ba8e336aSBenjamin Kramer llvm::to_vector<16>(llvm::make_pointer_range(mergedStats));
94ba8e336aSBenjamin Kramer llvm::array_pod_sort(passAndStatistics.begin(), passAndStatistics.end(),
95ba8e336aSBenjamin Kramer [](const decltype(passAndStatistics)::value_type *lhs,
96ba8e336aSBenjamin Kramer const decltype(passAndStatistics)::value_type *rhs) {
97ba8e336aSBenjamin Kramer return (*lhs)->getKey().compare((*rhs)->getKey());
9833a64540SRiver Riddle });
9933a64540SRiver Riddle
10033a64540SRiver Riddle // Print the timing information sequentially.
10133a64540SRiver Riddle for (auto &statData : passAndStatistics)
102ba8e336aSBenjamin Kramer printPassEntry(os, /*indent=*/2, statData->first(), statData->second);
10333a64540SRiver Riddle }
10433a64540SRiver Riddle
10533a64540SRiver Riddle /// Print the results in pipeline mode that mirrors the internal pass manager
10633a64540SRiver Riddle /// structure.
printResultsAsPipeline(raw_ostream & os,OpPassManager & pm)10733a64540SRiver Riddle static void printResultsAsPipeline(raw_ostream &os, OpPassManager &pm) {
10818839be9SFangrui Song #if LLVM_ENABLE_STATS
10933a64540SRiver Riddle std::function<void(unsigned, Pass *)> printPass = [&](unsigned indent,
11033a64540SRiver Riddle Pass *pass) {
11156a69851SRiver Riddle if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass)) {
11233a64540SRiver Riddle // If this adaptor has more than one internal pipeline, print an entry for
11333a64540SRiver Riddle // it.
11433a64540SRiver Riddle auto mgrs = adaptor->getPassManagers();
11533a64540SRiver Riddle if (mgrs.size() > 1) {
11656a69851SRiver Riddle printPassEntry(os, indent, adaptor->getAdaptorName());
11733a64540SRiver Riddle indent += 2;
11833a64540SRiver Riddle }
11933a64540SRiver Riddle
12033a64540SRiver Riddle // Print each of the children passes.
12133a64540SRiver Riddle for (OpPassManager &mgr : mgrs) {
122c2fb9c29SRiver Riddle auto name = ("'" + mgr.getOpAnchorName() + "' Pipeline").str();
12333a64540SRiver Riddle printPassEntry(os, indent, name);
12433a64540SRiver Riddle for (Pass &pass : mgr.getPasses())
12533a64540SRiver Riddle printPass(indent + 2, &pass);
12633a64540SRiver Riddle }
12733a64540SRiver Riddle return;
12833a64540SRiver Riddle }
12933a64540SRiver Riddle
13033a64540SRiver Riddle // Otherwise, we print the statistics for this pass.
13133a64540SRiver Riddle std::vector<Statistic> stats;
13233a64540SRiver Riddle for (Pass::Statistic *stat : pass->getStatistics())
13333a64540SRiver Riddle stats.push_back({stat->getName(), stat->getDesc(), stat->getValue()});
13433a64540SRiver Riddle printPassEntry(os, indent, pass->getName(), stats);
13533a64540SRiver Riddle };
13633a64540SRiver Riddle for (Pass &pass : pm.getPasses())
13733a64540SRiver Riddle printPass(/*indent=*/0, &pass);
13818839be9SFangrui Song #endif
13933a64540SRiver Riddle }
14033a64540SRiver Riddle
printStatistics(OpPassManager & pm,PassDisplayMode displayMode)141df186507SBenjamin Kramer static void printStatistics(OpPassManager &pm, PassDisplayMode displayMode) {
14233a64540SRiver Riddle auto os = llvm::CreateInfoOutputFile();
14333a64540SRiver Riddle
14433a64540SRiver Riddle // Print the stats header.
14533a64540SRiver Riddle *os << "===" << std::string(73, '-') << "===\n";
14633a64540SRiver Riddle // Figure out how many spaces for the description name.
14733a64540SRiver Riddle unsigned padding = (80 - kPassStatsDescription.size()) / 2;
14833a64540SRiver Riddle os->indent(padding) << kPassStatsDescription << '\n';
14933a64540SRiver Riddle *os << "===" << std::string(73, '-') << "===\n";
15033a64540SRiver Riddle
15133a64540SRiver Riddle // Defer to a specialized printer for each display mode.
15233a64540SRiver Riddle switch (displayMode) {
15333a64540SRiver Riddle case PassDisplayMode::List:
15433a64540SRiver Riddle printResultsAsList(*os, pm);
15533a64540SRiver Riddle break;
15633a64540SRiver Riddle case PassDisplayMode::Pipeline:
15733a64540SRiver Riddle printResultsAsPipeline(*os, pm);
15833a64540SRiver Riddle break;
15933a64540SRiver Riddle }
16033a64540SRiver Riddle *os << "\n";
16133a64540SRiver Riddle os->flush();
16233a64540SRiver Riddle }
16333a64540SRiver Riddle
16433a64540SRiver Riddle //===----------------------------------------------------------------------===//
16533a64540SRiver Riddle // PassStatistics
16633a64540SRiver Riddle //===----------------------------------------------------------------------===//
16733a64540SRiver Riddle
Statistic(Pass * owner,const char * name,const char * description)16833a64540SRiver Riddle Pass::Statistic::Statistic(Pass *owner, const char *name,
16933a64540SRiver Riddle const char *description)
17033a64540SRiver Riddle : llvm::Statistic{/*DebugType=*/"", name, description} {
17133a64540SRiver Riddle #if LLVM_ENABLE_STATS
17233a64540SRiver Riddle // Always set the 'initialized' bit to true so that this statistic isn't
17333a64540SRiver Riddle // placed in the static registry.
17433a64540SRiver Riddle // TODO: This is sort of hack as `llvm::Statistic`s can't be setup to avoid
175ae05cf27SKazuaki Ishizaki // automatic registration with the global registry. We should either add
17633a64540SRiver Riddle // support for this in LLVM, or just write our own statistics classes.
17733a64540SRiver Riddle Initialized = true;
17833a64540SRiver Riddle #endif
17933a64540SRiver Riddle
18033a64540SRiver Riddle // Register this statistic with the parent.
18133a64540SRiver Riddle owner->statistics.push_back(this);
18233a64540SRiver Riddle }
18333a64540SRiver Riddle
operator =(unsigned value)18433a64540SRiver Riddle auto Pass::Statistic::operator=(unsigned value) -> Statistic & {
18533a64540SRiver Riddle llvm::Statistic::operator=(value);
18633a64540SRiver Riddle return *this;
18733a64540SRiver Riddle }
18833a64540SRiver Riddle
18933a64540SRiver Riddle //===----------------------------------------------------------------------===//
19033a64540SRiver Riddle // PassManager
19133a64540SRiver Riddle //===----------------------------------------------------------------------===//
19233a64540SRiver Riddle
19333a64540SRiver Riddle /// Merge the pass statistics of this class into 'other'.
mergeStatisticsInto(OpPassManager & other)19433a64540SRiver Riddle void OpPassManager::mergeStatisticsInto(OpPassManager &other) {
19533a64540SRiver Riddle auto passes = getPasses(), otherPasses = other.getPasses();
19633a64540SRiver Riddle
19733a64540SRiver Riddle for (auto passPair : llvm::zip(passes, otherPasses)) {
19833a64540SRiver Riddle Pass &pass = std::get<0>(passPair), &otherPass = std::get<1>(passPair);
19933a64540SRiver Riddle
20033a64540SRiver Riddle // If this is an adaptor, then recursively merge the pass managers.
20156a69851SRiver Riddle if (auto *adaptorPass = dyn_cast<OpToOpPassAdaptor>(&pass)) {
20256a69851SRiver Riddle auto *otherAdaptorPass = cast<OpToOpPassAdaptor>(&otherPass);
20333a64540SRiver Riddle for (auto mgrs : llvm::zip(adaptorPass->getPassManagers(),
20433a64540SRiver Riddle otherAdaptorPass->getPassManagers()))
20533a64540SRiver Riddle std::get<0>(mgrs).mergeStatisticsInto(std::get<1>(mgrs));
20633a64540SRiver Riddle continue;
20733a64540SRiver Riddle }
20833a64540SRiver Riddle // Otherwise, merge the statistics for the current pass.
20933a64540SRiver Riddle assert(pass.statistics.size() == otherPass.statistics.size());
21033a64540SRiver Riddle for (unsigned i = 0, e = pass.statistics.size(); i != e; ++i) {
21133a64540SRiver Riddle assert(pass.statistics[i]->getName() ==
21233a64540SRiver Riddle StringRef(otherPass.statistics[i]->getName()));
21333a64540SRiver Riddle *otherPass.statistics[i] += *pass.statistics[i];
21433a64540SRiver Riddle *pass.statistics[i] = 0;
21533a64540SRiver Riddle }
21633a64540SRiver Riddle }
21733a64540SRiver Riddle }
21833a64540SRiver Riddle
21933a64540SRiver Riddle /// Prepare the statistics of passes within the given pass manager for
22033a64540SRiver Riddle /// consumption(e.g. dumping).
prepareStatistics(OpPassManager & pm)22133a64540SRiver Riddle static void prepareStatistics(OpPassManager &pm) {
22233a64540SRiver Riddle for (Pass &pass : pm.getPasses()) {
22356a69851SRiver Riddle OpToOpPassAdaptor *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);
22433a64540SRiver Riddle if (!adaptor)
22533a64540SRiver Riddle continue;
22633a64540SRiver Riddle MutableArrayRef<OpPassManager> nestedPms = adaptor->getPassManagers();
22733a64540SRiver Riddle
22856a69851SRiver Riddle // Merge the statistics from the async pass managers into the main nested
229d41b3bf7SWill Dietz // pass managers. Prepare recursively before merging.
23056a69851SRiver Riddle for (auto &asyncPM : adaptor->getParallelPassManagers()) {
231d41b3bf7SWill Dietz for (unsigned i = 0, e = asyncPM.size(); i != e; ++i) {
232d41b3bf7SWill Dietz prepareStatistics(asyncPM[i]);
23333a64540SRiver Riddle asyncPM[i].mergeStatisticsInto(nestedPms[i]);
23433a64540SRiver Riddle }
235d41b3bf7SWill Dietz }
23633a64540SRiver Riddle
23733a64540SRiver Riddle // Prepare the statistics of each of the nested passes.
23833a64540SRiver Riddle for (OpPassManager &nestedPM : nestedPms)
23933a64540SRiver Riddle prepareStatistics(nestedPM);
24033a64540SRiver Riddle }
24133a64540SRiver Riddle }
24233a64540SRiver Riddle
24333a64540SRiver Riddle /// Dump the statistics of the passes within this pass manager.
dumpStatistics()24433a64540SRiver Riddle void PassManager::dumpStatistics() {
24533a64540SRiver Riddle prepareStatistics(*this);
24633a64540SRiver Riddle printStatistics(*this, *passStatisticsMode);
24733a64540SRiver Riddle }
24833a64540SRiver Riddle
24933a64540SRiver Riddle /// Dump the statistics for each pass after running.
enableStatistics(PassDisplayMode displayMode)25033a64540SRiver Riddle void PassManager::enableStatistics(PassDisplayMode displayMode) {
25133a64540SRiver Riddle passStatisticsMode = displayMode;
25233a64540SRiver Riddle }
253