Skip to content

Commit 8d21a8d

Browse files
committed
[mlir][Pass] Enable the option for reproducer generation without crashing
This patch adds API `makeReproducer` and cl::opt flag --mlir-generate-reproducer=<filename> in order to allow for mlir reproducer dumps even when the pipeline doesn't crash. This will be useful for frameworks and runtimes that use MLIR where it is needed to reproduce the pipeline behavior for reasons outside of diagnosing crashes. An example is for diagnosing performance issues using offline tools, where being able to dump the reproducer from a runtime compiler would be helpful.
1 parent 00defca commit 8d21a8d

File tree

5 files changed

+59
-0
lines changed

5 files changed

+59
-0
lines changed

mlir/include/mlir/Pass/PassManager.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,12 @@ struct ReproducerStream {
222222
using ReproducerStreamFactory =
223223
std::function<std::unique_ptr<ReproducerStream>(std::string &error)>;
224224

225+
std::string
226+
makeReproducer(StringRef anchorName,
227+
const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
228+
Operation *op, StringRef outputFile, bool disableThreads = false,
229+
bool verifyPasses = false);
230+
225231
/// The main pass manager and pipeline builder.
226232
class PassManager : public OpPassManager {
227233
public:

mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ class MlirOptMainConfig {
173173
}
174174
bool shouldVerifyRoundtrip() const { return verifyRoundtripFlag; }
175175

176+
/// Reproducer file generation (no crash required).
177+
StringRef getReproducerFilename() const { return generateReproducerFileFlag; }
178+
176179
protected:
177180
/// Allow operation with no registered dialects.
178181
/// This option is for convenience during testing only and discouraged in
@@ -228,6 +231,9 @@ class MlirOptMainConfig {
228231

229232
/// Verify that the input IR round-trips perfectly.
230233
bool verifyRoundtripFlag = false;
234+
235+
/// The reproducer output filename (no crash required).
236+
std::string generateReproducerFileFlag = "";
231237
};
232238

233239
/// This defines the function type used to setup the pass manager. This can be

mlir/lib/Pass/PassCrashRecovery.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,25 @@ makeReproducerStreamFactory(StringRef outputFile) {
440440
};
441441
}
442442

443+
void printAsTextualPipeline(
444+
raw_ostream &os, StringRef anchorName,
445+
const llvm::iterator_range<OpPassManager::pass_iterator> &passes);
446+
447+
std::string mlir::makeReproducer(
448+
StringRef anchorName,
449+
const llvm::iterator_range<OpPassManager::pass_iterator> &passes,
450+
Operation *op, StringRef outputFile, bool disableThreads,
451+
bool verifyPasses) {
452+
453+
std::string description;
454+
std::string pipelineStr;
455+
llvm::raw_string_ostream passOS(pipelineStr);
456+
::printAsTextualPipeline(passOS, anchorName, passes);
457+
appendReproducer(description, op, makeReproducerStreamFactory(outputFile),
458+
pipelineStr, disableThreads, verifyPasses);
459+
return description;
460+
}
461+
443462
void PassManager::enableCrashReproducerGeneration(StringRef outputFile,
444463
bool genLocalReproducer) {
445464
enableCrashReproducerGeneration(makeReproducerStreamFactory(outputFile),

mlir/lib/Tools/mlir-opt/MlirOptMain.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,16 @@ struct MlirOptMainConfigCLOptions : public MlirOptMainConfig {
151151

152152
static cl::list<std::string> passPlugins(
153153
"load-pass-plugin", cl::desc("Load passes from plugin library"));
154+
155+
static cl::opt<std::string, /*ExternalStorage=*/true>
156+
generateReproducerFile(
157+
"mlir-generate-reproducer",
158+
llvm::cl::desc(
159+
"Generate an mlir reproducer at the provided filename"
160+
" (no crash required)"),
161+
cl::location(generateReproducerFileFlag), cl::init(""),
162+
cl::value_desc("filename"));
163+
154164
/// Set the callback to load a pass plugin.
155165
passPlugins.setCallback([&](const std::string &pluginPath) {
156166
auto plugin = PassPlugin::load(pluginPath);
@@ -384,6 +394,14 @@ performActions(raw_ostream &os,
384394
if (failed(pm.run(*op)))
385395
return failure();
386396

397+
// Generate reproducers if requested
398+
if (!config.getReproducerFilename().empty()) {
399+
StringRef anchorName = pm.getAnyOpAnchorName();
400+
const auto &passes = pm.getPasses();
401+
makeReproducer(anchorName, passes, op.get(),
402+
config.getReproducerFilename());
403+
}
404+
387405
// Print the output.
388406
TimingScope outputTiming = timing.nest("Output");
389407
if (config.shouldEmitBytecode()) {
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: mlir-opt %s -pass-pipeline='builtin.module(builtin.module(test-module-pass))' --mlir-generate-reproducer=%t -verify-diagnostics
2+
// RUN: cat %t | FileCheck -check-prefix=REPRO %s
3+
4+
module @inner_mod1 {
5+
module @foo {}
6+
}
7+
8+
// REPRO: module @inner_mod1
9+
// REPRO: module @foo {
10+
// REPRO: pipeline: "builtin.module(any(builtin.module(test-module-pass)))"

0 commit comments

Comments
 (0)