brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.0 KiB · 01191aa Raw
253 lines · cpp
1//===- PassStatistics.cpp -------------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "PassDetail.h"10#include "mlir/Pass/PassManager.h"11#include "llvm/ADT/StringExtras.h"12#include "llvm/Support/Format.h"13 14using namespace mlir;15using namespace mlir::detail;16 17constexpr StringLiteral kPassStatsDescription =18    "... Pass statistics report ...";19 20namespace {21/// Information pertaining to a specific statistic.22struct Statistic {23  const char *name, *desc;24  uint64_t value;25};26} // namespace27 28/// Utility to print a pass entry in the statistics output.29static void printPassEntry(raw_ostream &os, unsigned indent, StringRef pass,30                           MutableArrayRef<Statistic> stats = {}) {31  os.indent(indent) << pass << "\n";32  if (stats.empty())33    return;34 35  // Make sure to sort the statistics by name.36  llvm::array_pod_sort(37      stats.begin(), stats.end(), [](const auto *lhs, const auto *rhs) {38        return StringRef{lhs->name}.compare(StringRef{rhs->name});39      });40 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));45    largestValue =46        std::max(largestValue, (size_t)llvm::utostr(stat.value).size());47  }48 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,53                                          stat.desc);54  }55}56 57/// Print the statistics results in a list form, where each pass is sorted by58/// name.59static 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);63 64    // If this is not an adaptor, add the stats to the list if there are any.65    if (!adaptor) {66#if LLVM_ENABLE_STATS67      auto statistics = pass->getStatistics();68      if (statistics.empty())69        return;70 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()});75      } else {76        for (auto [idx, statistic] : llvm::enumerate(pass->getStatistics()))77          passEntry[idx].value += statistic->getValue();78      }79#endif80      return;81    }82 83    // Otherwise, recursively add each of the children.84    for (auto &mgr : adaptor->getPassManagers())85      for (Pass &pass : mgr.getPasses())86        addStats(&pass);87  };88  for (Pass &pass : pm.getPasses())89    addStats(&pass);90 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());98                       });99 100  // Print the timing information sequentially.101  for (auto &statData : passAndStatistics)102    printPassEntry(os, /*indent=*/2, statData->first(), statData->second);103}104 105/// Print the results in pipeline mode that mirrors the internal pass manager106/// structure.107static void printResultsAsPipeline(raw_ostream &os, OpPassManager &pm) {108#if LLVM_ENABLE_STATS109  std::function<void(unsigned, Pass *)> printPass = [&](unsigned indent,110                                                        Pass *pass) {111    if (auto *adaptor = dyn_cast<OpToOpPassAdaptor>(pass)) {112      // If this adaptor has more than one internal pipeline, print an entry for113      // it.114      auto mgrs = adaptor->getPassManagers();115      if (mgrs.size() > 1) {116        printPassEntry(os, indent, adaptor->getAdaptorName());117        indent += 2;118      }119 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);126      }127      return;128    }129 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);135  };136  for (Pass &pass : pm.getPasses())137    printPass(/*indent=*/0, &pass);138#endif139}140 141static void printStatistics(OpPassManager &pm, PassDisplayMode displayMode) {142  auto os = llvm::CreateInfoOutputFile();143 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";150 151  // Defer to a specialized printer for each display mode.152  switch (displayMode) {153  case PassDisplayMode::List:154    printResultsAsList(*os, pm);155    break;156  case PassDisplayMode::Pipeline:157    printResultsAsPipeline(*os, pm);158    break;159  }160  *os << "\n";161  os->flush();162}163 164//===----------------------------------------------------------------------===//165// PassStatistics166//===----------------------------------------------------------------------===//167 168Pass::Statistic::Statistic(Pass *owner, const char *name,169                           const char *description)170    : llvm::Statistic{/*DebugType=*/"", name, description} {171#if LLVM_ENABLE_STATS172  // Always set the 'initialized' bit to true so that this statistic isn't173  // placed in the static registry.174  // TODO: This is sort of hack as `llvm::Statistic`s can't be setup to avoid175  // automatic registration with the global registry. We should either add176  // support for this in LLVM, or just write our own statistics classes.177  Initialized = true;178#endif179 180  // Register this statistic with the parent.181  owner->statistics.push_back(this);182}183 184auto Pass::Statistic::operator=(unsigned value) -> Statistic & {185  llvm::Statistic::operator=(value);186  return *this;187}188 189//===----------------------------------------------------------------------===//190// PassManager191//===----------------------------------------------------------------------===//192 193/// Merge the pass statistics of this class into 'other'.194void OpPassManager::mergeStatisticsInto(OpPassManager &other) {195  auto passes = getPasses(), otherPasses = other.getPasses();196 197  for (auto passPair : llvm::zip(passes, otherPasses)) {198    Pass &pass = std::get<0>(passPair), &otherPass = std::get<1>(passPair);199 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));206      continue;207    }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;215    }216  }217}218 219/// Prepare the statistics of passes within the given pass manager for220/// consumption(e.g. dumping).221static void prepareStatistics(OpPassManager &pm) {222  for (Pass &pass : pm.getPasses()) {223    OpToOpPassAdaptor *adaptor = dyn_cast<OpToOpPassAdaptor>(&pass);224    if (!adaptor)225      continue;226    MutableArrayRef<OpPassManager> nestedPms = adaptor->getPassManagers();227 228    // Merge the statistics from the async pass managers into the main nested229    // 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]);234      }235    }236 237    // Prepare the statistics of each of the nested passes.238    for (OpPassManager &nestedPM : nestedPms)239      prepareStatistics(nestedPM);240  }241}242 243/// Dump the statistics of the passes within this pass manager.244void PassManager::dumpStatistics() {245  prepareStatistics(*this);246  printStatistics(*this, *passStatisticsMode);247}248 249/// Dump the statistics for each pass after running.250void PassManager::enableStatistics(PassDisplayMode displayMode) {251  passStatisticsMode = displayMode;252}253