| # Misexpect |
| |
| When developers use `llvm.expect` intrinsics, i.e., through use of |
| `__builtin_expect(...)`, they are trying to communicate how their code is |
| expected to behave at runtime to the optimizer. These annotations, however, can |
| be incorrect for a variety of reasons: changes to the code base invalidate them |
| silently, the developer mis-annotated them (e.g., using `LIKELY` instead of |
| `UNLIKELY`), or perhaps they assumed something incorrectly when they wrote |
| the annotation. Regardless of why, it is useful to detect these situations so |
| that the optimizer can make more useful decisions about the code. MisExpect |
| diagnostics are intended to help developers identify and address these |
| situations, by comparing the use of the `llvm.expect` intrinsic to the ground |
| truth provided by a profiling input. |
| |
| The MisExpect checks in the LLVM backend follow a simple procedure: if there is |
| a mismatch between the branch weights collected during profiling and those |
| supplied by an `llvm.expect` intrinsic, then it will emit a diagnostic |
| message to the user. |
| |
| The most natural place to perform the verification is just prior to when |
| branch weights are assigned to the target instruction in the form of |
| branch weight metadata. |
| |
| There are 3 key places in the LLVM backend where branch weights are |
| created and assigned based on profiling information or the use of the |
| `llvm.expect` intrinsic, and our implementation focuses on these |
| places to perform the verification. |
| |
| We calculate the threshold for emitting MisExpect related diagnostics |
| based on the values the compiler assigns to `llvm.expect` intrinsics, |
| which can be set through the `-likely-branch-weight` and |
| `-unlikely-branch-weight` LLVM options. During verification, if the |
| profile weights mismatch the calculated threshold, then we will emit a |
| remark or warning detailing a potential performance regression. The |
| diagnostic also reports the percentage of the time the annotation was |
| correct during profiling to help developers reason about how to proceed. |
| |
| The diagnostics are also available in the form of optimization remarks, |
| which can be serialized and processed through the `opt-viewer.py` |
| scripts in LLVM. |
| |
| :::{option} -pass-remarks=misexpect |
| Enables optimization remarks for misexpect when profiling data conflicts with |
| use of `llvm.expect` intrinsics. |
| ::: |
| |
| :::{option} -pgo-warn-misexpect |
| Enables misexpect warnings when profiling data conflicts with use of |
| `llvm.expect` intrinsics. |
| ::: |
| |
| LLVM supports 4 types of profile formats: Frontend, IR, CS-IR, and |
| Sampling. MisExpect Diagnostics are compatible with all Profiling formats. |
| |
| | Profile Type | Description | |
| | ------------ | -------------------------------------------------------------------------------- | |
| | Frontend | Profiling instrumentation added during compilation by the frontend, i.e. `clang` | |
| | IR | Profiling instrumentation added during by the LLVM backend | |
| | CS-IR | Context Sensitive IR based profiles | |
| | Sampling | Profiles collected through sampling with external tools, such as `perf` on Linux | |