MLIR  22.0.0git
Remarks.cpp
Go to the documentation of this file.
1 //===- Remarks.cpp - MLIR Remarks -----------------------------------------===//
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 "mlir/IR/Remarks.h"
10 
12 #include "mlir/IR/Diagnostics.h"
13 #include "mlir/IR/Value.h"
14 
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/ADT/StringRef.h"
17 
18 using namespace mlir::remark::detail;
19 
20 //------------------------------------------------------------------------------
21 // Remark
22 //------------------------------------------------------------------------------
23 
24 Remark::Arg::Arg(llvm::StringRef k, Value v) : key(k) {
25  llvm::raw_string_ostream os(val);
26  os << v;
27 }
28 
29 Remark::Arg::Arg(llvm::StringRef k, Type t) : key(k) {
30  llvm::raw_string_ostream os(val);
31  os << t;
32 }
33 
34 void Remark::insert(llvm::StringRef s) { args.emplace_back(s); }
35 void Remark::insert(Arg a) { args.push_back(std::move(a)); }
36 
37 // Simple helper to print key=val list (sorted).
38 static void printArgs(llvm::raw_ostream &os, llvm::ArrayRef<Remark::Arg> args) {
39  if (args.empty())
40  return;
41 
42  llvm::SmallVector<Remark::Arg, 8> sorted(args.begin(), args.end());
43  llvm::sort(sorted, [](const Remark::Arg &a, const Remark::Arg &b) {
44  return a.key < b.key;
45  });
46 
47  for (size_t i = 0; i < sorted.size(); ++i) {
48  const auto &a = sorted[i];
49  os << a.key << "=";
50 
51  llvm::StringRef val(a.val);
52  bool needsQuote = val.contains(' ') || val.contains(',') ||
53  val.contains('{') || val.contains('}');
54  if (needsQuote)
55  os << '"' << val << '"';
56  else
57  os << val;
58 
59  if (i + 1 < sorted.size())
60  os << ", ";
61  }
62 }
63 
64 /// Print the remark to the given output stream.
65 /// Example output:
66 // clang-format off
67 /// [Missed] Category: Loop | Pass:Unroller | Function=main | Reason="tripCount=4 < threshold=256"
68 /// [Failure] LoopOptimizer | Reason="failed due to unsupported pattern"
69 // clang-format on
70 void Remark::print(llvm::raw_ostream &os, bool printLocation) const {
71  // Header: [Type] pass:remarkName
72  StringRef type = getRemarkTypeString();
73  StringRef categoryName = getFullCategoryName();
74  StringRef name = remarkName;
75 
76  os << '[' << type << "] ";
77  os << name << " | ";
78  if (!categoryName.empty())
79  os << "Category:" << categoryName << " | ";
80  if (!functionName.empty())
81  os << "Function=" << getFunction() << " | ";
82 
83  if (printLocation) {
84  if (auto flc = mlir::dyn_cast<mlir::FileLineColLoc>(getLocation()))
85  os << " @" << flc.getFilename() << ":" << flc.getLine() << ":"
86  << flc.getColumn();
87  }
88 
89  printArgs(os, getArgs());
90 }
91 
92 std::string Remark::getMsg() const {
93  std::string s;
94  llvm::raw_string_ostream os(s);
95  print(os);
96  os.flush();
97  return s;
98 }
99 
100 llvm::StringRef Remark::getRemarkTypeString() const {
101  switch (remarkKind) {
103  return "Unknown";
105  return "Passed";
107  return "Missed";
109  return "Failure";
111  return "Analysis";
112  }
113  llvm_unreachable("Unknown remark kind");
114 }
115 
116 llvm::remarks::Type Remark::getRemarkType() const {
117  switch (remarkKind) {
119  return llvm::remarks::Type::Unknown;
121  return llvm::remarks::Type::Passed;
123  return llvm::remarks::Type::Missed;
127  return llvm::remarks::Type::Analysis;
128  }
129  llvm_unreachable("Unknown remark kind");
130 }
131 
132 llvm::remarks::Remark Remark::generateRemark() const {
133  auto locLambda = [&]() -> llvm::remarks::RemarkLocation {
134  if (auto flc = dyn_cast<FileLineColLoc>(getLocation()))
135  return {flc.getFilename(), flc.getLine(), flc.getColumn()};
136  return {"<unknown file>", 0, 0};
137  };
138 
139  llvm::remarks::Remark r; // The result.
140  r.RemarkType = getRemarkType();
141  r.RemarkName = getRemarkName();
142  // MLIR does not use passes; instead, it has categories and sub-categories.
143  r.PassName = getFullCategoryName();
144  r.FunctionName = getFunction();
145  r.Loc = locLambda();
146  for (const Remark::Arg &arg : getArgs()) {
147  r.Args.emplace_back();
148  r.Args.back().Key = arg.key;
149  r.Args.back().Val = arg.val;
150  }
151  return r;
152 }
153 
154 //===----------------------------------------------------------------------===//
155 // InFlightRemark
156 //===----------------------------------------------------------------------===//
157 
159  if (remark && owner)
160  owner->report(std::move(*remark));
161  owner = nullptr;
162 }
163 
164 //===----------------------------------------------------------------------===//
165 // Remark Engine
166 //===----------------------------------------------------------------------===//
167 
168 template <typename RemarkT, typename... Args>
169 InFlightRemark RemarkEngine::makeRemark(Args &&...args) {
170  static_assert(std::is_base_of_v<Remark, RemarkT>,
171  "RemarkT must derive from Remark");
172  return InFlightRemark(*this,
173  std::make_unique<RemarkT>(std::forward<Args>(args)...));
174 }
175 
176 template <typename RemarkT>
178 RemarkEngine::emitIfEnabled(Location loc, RemarkOpts opts,
179  bool (RemarkEngine::*isEnabled)(StringRef) const) {
180  return (this->*isEnabled)(opts.categoryName) ? makeRemark<RemarkT>(loc, opts)
181  : InFlightRemark{};
182 }
183 
184 bool RemarkEngine::isMissedOptRemarkEnabled(StringRef categoryName) const {
185  return missFilter && missFilter->match(categoryName);
186 }
187 
188 bool RemarkEngine::isPassedOptRemarkEnabled(StringRef categoryName) const {
189  return passedFilter && passedFilter->match(categoryName);
190 }
191 
192 bool RemarkEngine::isAnalysisOptRemarkEnabled(StringRef categoryName) const {
193  return analysisFilter && analysisFilter->match(categoryName);
194 }
195 
196 bool RemarkEngine::isFailedOptRemarkEnabled(StringRef categoryName) const {
197  return failedFilter && failedFilter->match(categoryName);
198 }
199 
201  RemarkOpts opts) {
202  return emitIfEnabled<OptRemarkPass>(loc, opts,
203  &RemarkEngine::isPassedOptRemarkEnabled);
204 }
205 
207  RemarkOpts opts) {
208  return emitIfEnabled<OptRemarkMissed>(
209  loc, opts, &RemarkEngine::isMissedOptRemarkEnabled);
210 }
211 
213  RemarkOpts opts) {
214  return emitIfEnabled<OptRemarkFailure>(
215  loc, opts, &RemarkEngine::isFailedOptRemarkEnabled);
216 }
217 
219  RemarkOpts opts) {
220  return emitIfEnabled<OptRemarkAnalysis>(
221  loc, opts, &RemarkEngine::isAnalysisOptRemarkEnabled);
222 }
223 
224 //===----------------------------------------------------------------------===//
225 // RemarkEngine
226 //===----------------------------------------------------------------------===//
227 
228 void RemarkEngine::report(const Remark &&remark) {
229  // Stream the remark
230  if (remarkStreamer)
231  remarkStreamer->streamOptimizationRemark(remark);
232 
233  // Print using MLIR's diagnostic
234  if (printAsEmitRemarks)
235  emitRemark(remark.getLocation(), remark.getMsg());
236 }
237 
239  if (remarkStreamer)
240  remarkStreamer->finalize();
241 }
242 
243 llvm::LogicalResult
244 RemarkEngine::initialize(std::unique_ptr<MLIRRemarkStreamerBase> streamer,
245  std::string *errMsg) {
246  // If you need to validate categories/filters, do so here and set errMsg.
247  remarkStreamer = std::move(streamer);
248  return success();
249 }
250 
251 RemarkEngine::RemarkEngine(bool printAsEmitRemarks,
252  const RemarkCategories &cats)
253  : printAsEmitRemarks(printAsEmitRemarks) {
254  if (cats.passed)
255  passedFilter = llvm::Regex(cats.passed.value());
256  if (cats.missed)
257  missFilter = llvm::Regex(cats.missed.value());
258  if (cats.analysis)
259  analysisFilter = llvm::Regex(cats.analysis.value());
260  if (cats.failed)
261  failedFilter = llvm::Regex(cats.failed.value());
262 }
263 
264 llvm::LogicalResult mlir::remark::enableOptimizationRemarks(
265  MLIRContext &ctx,
266  std::unique_ptr<remark::detail::MLIRRemarkStreamerBase> streamer,
267  const remark::RemarkCategories &cats, bool printAsEmitRemarks) {
268  auto engine =
269  std::make_unique<remark::detail::RemarkEngine>(printAsEmitRemarks, cats);
270 
271  std::string errMsg;
272  if (failed(engine->initialize(std::move(streamer), &errMsg))) {
273  llvm::report_fatal_error(
274  llvm::Twine("Failed to initialize remark engine. Error: ") + errMsg);
275  }
276  ctx.setRemarkEngine(std::move(engine));
277 
278  return success();
279 }
static void printArgs(llvm::raw_ostream &os, llvm::ArrayRef< Remark::Arg > args)
Definition: Remarks.cpp:38
@ Failure
Op failed to vectorize.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
void setRemarkEngine(std::unique_ptr< remark::detail::RemarkEngine > engine)
Set the remark engine for this context.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
InFlightRemark is a RAII class that holds a reference to a Remark instance and allows to build the re...
Definition: Remarks.h:281
InFlightRemark emitOptimizationRemarkFailure(Location loc, RemarkOpts opts)
Report a failed optimization remark, this will create an InFlightRemark that can be used to build the...
Definition: Remarks.cpp:212
LogicalResult initialize(std::unique_ptr< MLIRRemarkStreamerBase > streamer, std::string *errMsg)
Setup the remark engine with the given output path and format.
Definition: Remarks.cpp:244
void report(const Remark &&remark)
Report a remark.
Definition: Remarks.cpp:228
InFlightRemark emitOptimizationRemark(Location loc, RemarkOpts opts)
Report a successful remark, this will create an InFlightRemark that can be used to build the remark u...
Definition: Remarks.cpp:200
RemarkEngine()=delete
Default constructor is deleted, use the other constructor.
InFlightRemark emitOptimizationRemarkMiss(Location loc, RemarkOpts opts)
Report a missed optimization remark that can be used to build the remark using the << operator.
Definition: Remarks.cpp:206
~RemarkEngine()
Destructor that will close the output file and reset the main remark streamer.
Definition: Remarks.cpp:238
InFlightRemark emitOptimizationRemarkAnalysis(Location loc, RemarkOpts opts)
Report an analysis remark, this will create an InFlightRemark that can be used to build the remark us...
Definition: Remarks.cpp:218
llvm::StringRef getFullCategoryName() const
Definition: Remarks.h:147
void print(llvm::raw_ostream &os, bool printLocation=false) const
Print the remark to the given output stream.
Definition: Remarks.cpp:70
StringRef categoryName
Sub category passname e.g., "Unroll" or "UnrollAndJam".
Definition: Remarks.h:180
SmallVector< Arg, 4 > args
Args collected via the streaming interface.
Definition: Remarks.h:192
StringRef getFunction() const
Definition: Remarks.h:139
llvm::remarks::Type getRemarkType() const
Definition: Remarks.cpp:116
StringRef getRemarkTypeString() const
Definition: Remarks.cpp:100
Location getLocation() const
Definition: Remarks.h:135
StringRef remarkName
Remark identifier.
Definition: Remarks.h:189
ArrayRef< Arg > getArgs() const
Definition: Remarks.h:165
RemarkKind remarkKind
Keeps the MLIR diagnostic kind, which is used to determine the diagnostic kind in the LLVM remark str...
Definition: Remarks.h:174
StringRef getRemarkName() const
Definition: Remarks.h:157
void insert(llvm::StringRef s)
Definition: Remarks.cpp:34
StringRef functionName
Name of the convering function like interface.
Definition: Remarks.h:176
llvm::remarks::Remark generateRemark() const
Diagnostic -> Remark.
Definition: Remarks.cpp:132
std::string getMsg() const
Definition: Remarks.cpp:92
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
LogicalResult enableOptimizationRemarks(MLIRContext &ctx, std::unique_ptr< remark::detail::MLIRRemarkStreamerBase > streamer, const remark::RemarkCategories &cats, bool printAsEmitRemarks=false)
Setup remarks for the context.
@ RemarkPassed
An optimization was applied.
@ RemarkAnalysis
Informational context (e.g., analysis numbers) without a pass/fail outcome.
@ RemarkMissed
A profitable optimization opportunity was found but not applied.
@ RemarkFailure
The compiler attempted the optimization but failed (e.g., legality checks, or better opportunites).
InFlightDiagnostic emitRemark(Location loc)
Utility method to emit a remark message using this location.
Define an the set of categories to accept.
Definition: Remarks.h:31
std::optional< std::string > missed
Definition: Remarks.h:32
std::optional< std::string > passed
Definition: Remarks.h:32
std::optional< std::string > analysis
Definition: Remarks.h:32
std::optional< std::string > failed
Definition: Remarks.h:32
Options to create a Remark.
Definition: Remarks.h:58
StringRef categoryName
Definition: Remarks.h:60
Arg(llvm::StringRef m)
Definition: Remarks.h:107