-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[MLIR] Introduce RemarkEngine + pluggable remark streaming (YAML/Bitstream) #152474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
e4292d1
[MLIR] MLIR Integrate LLVM Optimization Remarks Infrastructure
grypp 066fe47
address copilot
grypp fa75d31
add doc
grypp d7a3c03
address comments
grypp f22137f
Split Streamer from RemarlEngine
grypp 521c676
fix doc
grypp d851e0e
add callback
grypp f4d7bd6
Add mlir::remark. RemarkBase->Remark
grypp 514d429
Pass->Passed
grypp 6e9b734
Add detail. Add Arg.
grypp 2bd50fd
move RemarkCategories-> mlir::remark
grypp a825d7f
fix copilot
grypp 2fbb84a
fx
grypp 0c4b386
fix comment
grypp 0b43c0c
add test
grypp a58c20f
improve the doc
grypp 77da6ed
address @joker-eph comments
grypp e113886
Improve document for Failure
grypp 39d4fff
Set better API for enableOptimizationRemarksWithLLVMStreamer
grypp c6970b9
few fixes
grypp 219308f
add LLVM_UNLIKELY
grypp c3be28a
address comments
grypp 3e57446
more test
grypp a7de476
address @razvanlupusoru comments
grypp 24690b2
Slightly change emitRemarks print
grypp 2634a9e
Use functionName
grypp 0c90ab1
add doc
grypp 4746b78
fx
grypp 203355c
add remarkoptions
grypp 9302c26
xf
grypp 3b94875
fx
grypp File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,259 @@ | ||
| # Remark Infrastructure | ||
|
|
||
| Remarks are **structured, human- and machine-readable notes** emitted by the | ||
| compiler to explain: | ||
|
|
||
| - What was transformed | ||
| - What was missed | ||
| - Why it happened | ||
|
|
||
| The **`RemarkEngine`** collects finalized remarks during compilation and sends | ||
| them to a pluggable **streamer**. By default, MLIR integrates with LLVM’s | ||
| [`llvm::remarks`](https://llvm.org/docs/Remarks.html), allowing you to: | ||
|
|
||
| - Stream remarks as passes run | ||
| - Serialize them to **YAML** or **LLVM bitstream** for tooling | ||
|
|
||
| *** | ||
|
|
||
| ## Key Points | ||
|
|
||
| - **Opt-in** – Disabled by default; zero overhead unless enabled. | ||
| - **Per-context** – Configured on `MLIRContext`. | ||
| - **Formats** – LLVM Remark engine (YAML / Bitstream) or custom streamers. | ||
| - **Kinds** – `Passed`, `Missed`, `Failure`, `Analysis`. | ||
| - **API** – Lightweight streaming interface using `<<` (like MLIR diagnostics). | ||
|
|
||
| *** | ||
|
|
||
| ## How It Works | ||
|
|
||
| Two main components: | ||
|
|
||
| - **`RemarkEngine`** (owned by `MLIRContext`): Receives finalized | ||
| `InFlightRemark`s, optionally mirrors them to the `DiagnosticEngine`, and | ||
| dispatches to the installed streamer. | ||
|
|
||
| - **`MLIRRemarkStreamerBase`** (abstract): Backend interface with a single hook: | ||
|
|
||
| ```c++ | ||
| virtual void streamOptimizationRemark(const Remark &remark) = 0; | ||
| ``` | ||
|
|
||
| **Default backend – `MLIRLLVMRemarkStreamer`** Adapts `mlir::Remark` to LLVM’s | ||
| remark format and writes YAML/bitstream via `llvm::remarks::RemarkStreamer`. | ||
|
|
||
| **Ownership flow:** `MLIRContext` → `RemarkEngine` → `MLIRRemarkStreamerBase` | ||
|
|
||
| *** | ||
|
|
||
| ## Categories | ||
|
|
||
| MLIR provides four built-in remark categories (extendable if needed): | ||
|
|
||
| #### 1. **Passed** | ||
|
|
||
| Optimization/transformation succeeded. | ||
|
|
||
| ``` | ||
| [Passed] RemarkName | Category:Vectorizer:myPass1 | Function=foo | Remark="vectorized loop", tripCount=128 | ||
| ``` | ||
|
|
||
| #### 2. **Missed** | ||
|
|
||
| Optimization/transformation didn’t apply — ideally with actionable feedback. | ||
|
|
||
| ``` | ||
| [Missed] | Category:Unroll | Function=foo | Reason="tripCount=4 < threshold=256", Suggestion="increase unroll to 128" | ||
| ``` | ||
|
|
||
| #### 3. **Failure** | ||
|
|
||
| Optimization/transformation attempted but failed. This is slightly different | ||
| from the `Missed` category. | ||
|
|
||
| For example, the user specifies `-use-max-register=100` when invoking the | ||
| compiler, but the attempt fails for some reason: | ||
|
|
||
| ```bash | ||
| $ your-compiler -use-max-register=100 mycode.xyz | ||
| ``` | ||
|
|
||
| ``` | ||
| [Failed] Category:RegisterAllocator | Reason="Limiting to use-max-register=100 failed; it now uses 104 registers for better performance" | ||
| ``` | ||
|
|
||
| #### 4. **Analysis** | ||
|
|
||
| Neutral analysis results. | ||
|
|
||
| ``` | ||
| [Analysis] Category:Register | Remark="Kernel uses 168 registers" | ||
| [Analysis] Category:Register | Remark="Kernel uses 10kB local memory" | ||
| ``` | ||
|
|
||
| *** | ||
|
|
||
| ## Emitting Remarks | ||
|
|
||
| The `remark::*` helpers return an **in-flight remark**. | ||
| You append strings or key–value metrics using `<<`. | ||
|
|
||
| ### Remark Options | ||
|
|
||
| When constructing a remark, you typically provide four fields that are `StringRef`: | ||
|
|
||
| 1. **Remark name** – identifiable name | ||
| 2. **Category** – high-level classification | ||
| 3. **Sub-category** – more fine-grained classification | ||
| 4. **Function name** – the function where the remark originates | ||
|
|
||
|
|
||
| ### Example | ||
|
|
||
| ```c++ | ||
| #include "mlir/IR/Remarks.h" | ||
|
|
||
| LogicalResult MyPass::runOnOperation() { | ||
| Location loc = getOperation()->getLoc(); | ||
|
|
||
| remark::RemarkOpts opts = remark::RemarkOpts::name(MyRemarkName1) | ||
| .category(categoryVectorizer) | ||
| .function(fName) | ||
| .subCategory(myPassname1); | ||
|
|
||
| // PASSED | ||
| remark::passed(loc, opts) | ||
| << "vectorized loop" | ||
| << remark::metric("tripCount", 128); | ||
|
|
||
| // ANALYSIS | ||
| remark::analysis(loc, opts) | ||
| << "Kernel uses 168 registers"; | ||
|
|
||
| // MISSED (with reason + suggestion) | ||
| int tripBad = 4, threshold = 256, target = 128; | ||
| remark::missed(loc, opts) | ||
| << remark::reason("tripCount={0} < threshold={1}", tripBad, threshold) | ||
| << remark::suggest("increase unroll to {0}", target); | ||
|
|
||
| // FAILURE | ||
| remark::failed(loc, opts) | ||
| << remark::reason("failed due to unsupported pattern"); | ||
|
|
||
| return success(); | ||
| } | ||
| ``` | ||
|
|
||
| *** | ||
|
|
||
| ### Metrics and Shortcuts | ||
|
|
||
| Helper functions accept | ||
| [LLVM format](https://llvm.org/docs/ProgrammersManual.html#formatting-strings-the-formatv-function) | ||
| style strings. This format builds lazily, so remarks are zero-cost when | ||
| disabled. | ||
|
|
||
| #### Adding Remarks | ||
|
|
||
| - **`remark::add(fmt, ...)`** – Shortcut for `metric("Remark", ...)`. | ||
|
|
||
| #### Adding Reasons | ||
|
|
||
| - **`remark::reason(fmt, ...)`** – Shortcut for `metric("Reason", ...)`. Used to | ||
| explain why a remark was missed or failed. | ||
|
|
||
| #### Adding Suggestions | ||
|
|
||
| - **`remark::suggest(fmt, ...)`** – Shortcut for `metric("Suggestion", ...)`. | ||
| Used to provide actionable feedback. | ||
|
|
||
| #### Adding Custom Metrics | ||
|
|
||
| - **`remark::metric(key, value)`** – Adds a structured key–value metric. | ||
|
|
||
| Example: tracking `TripCount`. When exported to YAML, it appears under `args` | ||
| for machine readability: | ||
|
|
||
| ```cpp | ||
| remark::metric("TripCount", value) | ||
| ``` | ||
|
|
||
| #### String Metrics | ||
|
|
||
| Passing a plain string (e.g. `<< "vectorized loop"`) is equivalent to: | ||
|
|
||
| ```cpp | ||
| metric("Remark", "vectorized loop") | ||
| ``` | ||
|
|
||
| *** | ||
|
|
||
| ## Enabling Remarks | ||
|
|
||
| ### 1. **With LLVMRemarkStreamer (YAML or Bitstream)** | ||
|
|
||
| Persists remarks to a file in the chosen format. | ||
|
|
||
| ```c++ | ||
| mlir::remark::RemarkCategories cats{/*passed=*/categoryLoopunroll, | ||
grypp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /*missed=*/std::nullopt, | ||
| /*analysis=*/std::nullopt, | ||
| /*failed=*/categoryLoopunroll}; | ||
|
|
||
| mlir::remark::enableOptimizationRemarksWithLLVMStreamer( | ||
| context, yamlFile, llvm::remarks::Format::YAML, cats); | ||
| ``` | ||
|
|
||
| **YAML format** – human-readable, easy to diff: | ||
|
|
||
| ```yaml | ||
| --- !Passed | ||
| pass: Category:SubCategory | ||
| name: MyRemarkName1 | ||
| function: myFunc | ||
| loc: myfile.mlir:12:3 | ||
| args: | ||
| - Remark: vectorized loop | ||
| - tripCount: 128 | ||
| ``` | ||
|
|
||
| **Bitstream format** – compact binary for large runs. | ||
|
|
||
| *** | ||
|
|
||
| ### 2. **With `mlir::emitRemarks` (No Streamer)** | ||
|
|
||
| If the streamer isn't passed, the remarks are mirrored to the `DiagnosticEngine` | ||
| using `mlir::emitRemarks` | ||
|
|
||
| ```c++ | ||
| mlir::remark::RemarkCategories cats{/*passed=*/categoryLoopunroll, | ||
| /*missed=*/std::nullopt, | ||
| /*analysis=*/std::nullopt, | ||
| /*failed=*/categoryLoopunroll}; | ||
| remark::enableOptimizationRemarks( | ||
| /*streamer=*/nullptr, cats, | ||
| /*printAsEmitRemarks=*/true); | ||
| ``` | ||
|
|
||
| *** | ||
|
|
||
| ### 3. **With a Custom Streamer** | ||
|
|
||
| You can implement a custom streamer by inheriting `MLIRRemarkStreamerBase` to | ||
| consume remarks in any format. | ||
|
|
||
| ```c++ | ||
| class MyStreamer : public MLIRRemarkStreamerBase { | ||
| public: | ||
| void streamOptimizationRemark(const Remark &remark) override { | ||
| // Convert and write remark to your custom format | ||
| } | ||
| }; | ||
|
|
||
| auto myStreamer = std::make_unique<MyStreamer>(); | ||
| remark::enableOptimizationRemarks( | ||
| /*streamer=*/myStreamer, cats, | ||
| /*printAsEmitRemarks=*/true); | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.