xref: /llvm-project/mlir/lib/Pass/PassStatistics.cpp (revision 8c258fda1f9b33fc847cfff9c2ee33ce4615ff0b)
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