MLIR  20.0.0git
PassStatistics.cpp
Go to the documentation of this file.
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-exception
6 //
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 
14 using namespace mlir;
15 using namespace mlir::detail;
16 
17 constexpr StringLiteral kPassStatsDescription =
18  "... Pass statistics report ...";
19 
20 namespace {
21 /// Information pertaining to a specific statistic.
22 struct Statistic {
23  const char *name, *desc;
24  uint64_t value;
25 };
26 } // namespace
27 
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";
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 by
58 /// name.
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);
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_STATS
67  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 #endif
80  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 manager
106 /// structure.
107 static void printResultsAsPipeline(raw_ostream &os, OpPassManager &pm) {
108 #if LLVM_ENABLE_STATS
109  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 for
113  // 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 #endif
139 }
140 
141 static 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) {
154  printResultsAsList(*os, pm);
155  break;
157  printResultsAsPipeline(*os, pm);
158  break;
159  }
160  *os << "\n";
161  os->flush();
162 }
163 
164 //===----------------------------------------------------------------------===//
165 // PassStatistics
166 //===----------------------------------------------------------------------===//
167 
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.
177  Initialized = true;
178 #endif
179 
180  // Register this statistic with the parent.
181  owner->statistics.push_back(this);
182 }
183 
184 auto Pass::Statistic::operator=(unsigned value) -> Statistic & {
185  llvm::Statistic::operator=(value);
186  return *this;
187 }
188 
189 //===----------------------------------------------------------------------===//
190 // PassManager
191 //===----------------------------------------------------------------------===//
192 
193 /// Merge the pass statistics of this class into '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 for
220 /// consumption(e.g. dumping).
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 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]);
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.
244 void PassManager::dumpStatistics() {
245  prepareStatistics(*this);
246  printStatistics(*this, *passStatisticsMode);
247 }
248 
249 /// Dump the statistics for each pass after running.
251  passStatisticsMode = displayMode;
252 }
static void printPassEntry(raw_ostream &os, unsigned indent, StringRef pass, MutableArrayRef< Statistic > stats=std::nullopt)
Utility to print a pass entry in the statistics output.
static void printResultsAsList(raw_ostream &os, OpPassManager &pm)
Print the statistics results in a list form, where each pass is sorted by name.
static void printResultsAsPipeline(raw_ostream &os, OpPassManager &pm)
Print the results in pipeline mode that mirrors the internal pass manager structure.
static void printStatistics(OpPassManager &pm, PassDisplayMode displayMode)
static void prepareStatistics(OpPassManager &pm)
Prepare the statistics of passes within the given pass manager for consumption(e.g.
constexpr StringLiteral kPassStatsDescription
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
This class represents a pass manager that runs passes on either a specific operation type,...
Definition: PassManager.h:47
void mergeStatisticsInto(OpPassManager &other)
Merge the pass statistics of this class into 'other'.
iterator_range< pass_iterator > getPasses()
Definition: PassManager.h:80
void enableStatistics(PassDisplayMode displayMode=PassDisplayMode::Pipeline)
Prompts the pass manager to print the statistics collected for each of the held passes after each cal...
This class represents a single pass statistic.
Definition: Pass.h:132
Statistic(Pass *owner, const char *name, const char *description)
The statistic is initialized by the pass owner, a name, and a description.
Statistic & operator=(unsigned value)
Assign the statistic to the given value.
The abstract base pass class.
Definition: Pass.h:51
An adaptor pass used to run operation passes over nested operations.
Definition: PassDetail.h:26
MutableArrayRef< OpPassManager > getPassManagers()
Returns the pass managers held by this adaptor.
Definition: PassDetail.h:47
MutableArrayRef< SmallVector< OpPassManager, 1 > > getParallelPassManagers()
Return the async pass managers held by this parallel adaptor.
Definition: PassDetail.h:54
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition: CallGraph.h:229
AttrTypeReplacer.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
Include the generated interface declarations.
PassDisplayMode
An enum describing the different display modes for the information within the pass manager.
Definition: PassManager.h:198