Add factory to create streams for logging the reproducer. Allows for more general logging (beyond file) and logging the configuration/module separately (logged in order, configuration before module).
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
mlir/include/mlir/Pass/PassManager.h | ||
---|---|---|
213 | Could we reduce the API surface? | |
mlir/lib/Pass/Pass.cpp | ||
709 | Could we reduce the API surface? | |
752–754 | (Spell the type) | |
757 | Making this configurable is breaking the mlir-opt option to load a reproducer: the reproducer is no longer a self-contained "known" format, do you really need this hook? Can we always print to the same stream instead? |
mlir/include/mlir/Pass/PassManager.h | ||
---|---|---|
213 | close is required by ToolOutput today to differentiate between completed and not completed dumps. It is not required if one just streams without needing any cleanup - but then one needs some checking later to verify if a failure got dumped. Or are you suggesting best effort, just always assume it will complete and other parts (e.g. if file is not saved in the end, just pass the name and assume consumers are robust enough). So would you propose that getStream opens the stream too and return none if failed? (not sure why optional) I considered a single stream, but there seems to be 2 pieces of information being captured here: pass pipeline and module/top-level object, we mix them by using comments but that means you need to code a convention and re-extract. Which is needed if we got to file, but if stored separately then the convention doesn't help. I don't feel super strong here, as extracting the string out is easy. An option is also to not make this pure virtual and so the common case is you are reusing the same stream. | |
mlir/lib/Pass/Pass.cpp | ||
757 | It is self-contained if you use a filename :) it isn't if you log it to (say) a DB, but for that case you would need to do work. But you are correct: if you now implement a different file logger using the specialization, then you'd need to duplicate the same conventions. |
mlir/include/mlir/Pass/PassManager.h | ||
---|---|---|
213 |
Is there a code path today where we discard the output? It seems to me that we only invoke the factory to create the ReproducerStream after we decide we want to log in the first place, i.e. close() is called unconditionally which drove my comment here.
Yes, if you want to say that this can fail. Another way would be to make getStream not able to fail and rely on the factory to return nullptr.
Right, and we implemented this convention at this point I think with mlir-opt able to load a reproducer. |
mlir/include/mlir/Pass/PassManager.h | ||
---|---|---|
213 |
+1 to both of these points. I don't see a reason for an explicit close, the destructor of the stream can just handle that.
+1 here as well. Unless there is a concrete and compelling reason, I'd rather just have one stream. Does this struct need anything other than just: virtual std::string description() = 0; virtual raw_ostream &os() = 0; |
mlir/include/mlir/Pass/PassManager.h | ||
---|---|---|
213 |
Yes, if the process gets interrupted. So the assumption would be that no matter what we have outputted to stream successfully. And any post processing is fine (e.g., any corruption of the stream is acceptable, atomicity is assumed).
Opening the stream may be expensive, but can be done in the factory. It needs no more than that if we flatten the information using a convention and assume commiting the written output on destruction is always fine. | |
mlir/lib/Pass/Pass.cpp | ||
751–752 | That is the error being reported. |
mlir/lib/Pass/Pass.cpp | ||
---|---|---|
751–752 | I do not see it used anywhere in the method =) |
mlir/include/mlir/Pass/PassManager.h | ||
---|---|---|
213 |
You mean if the process crash while printing? during the first line here: // Output the .mlir module. preCrashOperation->print(crashStream->operationStream()); crashStream->close(); In this case we won't call the destructor either, so it should be equivalent isn't it? |
Spell out type & return error rather than report locally
mlir/lib/Pass/Pass.cpp | ||
---|---|---|
751–752 | Ah, good catch thanks |
LGTM with a minor tweak on FileReproducerStream
mlir/lib/Pass/Pass.cpp | ||
---|---|---|
702 | I'd rather patch ToolOutputFile to get access to this (it is already stored there!): diff --git a/llvm/include/llvm/Support/ToolOutputFile.h b/llvm/include/llvm/Support/ToolOutputFile.h index cf01b9ecefc5..441aa5881fb8 100644 --- a/llvm/include/llvm/Support/ToolOutputFile.h +++ b/llvm/include/llvm/Support/ToolOutputFile.h @@ -34,7 +34,7 @@ class ToolOutputFile { public: /// The flag which indicates whether we should not delete the file. bool Keep; - + StringRef GetFilename() { return Filename; } explicit CleanupInstaller(StringRef Filename); ~CleanupInstaller(); } Installer; @@ -57,6 +57,9 @@ public: /// Return the contained raw_fd_ostream. raw_fd_ostream &os() { return *OS; } + /// Return the filename it was initialized with. + StringRef GetFilename() { return Installer.GetFilename(); } + /// Indicate that the tool's job wrt this output file has been successful and /// the file should not be deleted. void keep() { Installer.Keep = true; } |
LGTM with Mehdi's comments addressed.
Please update the documentation on the website detailing on how users can hook into this.
StringRef?