Misexpect¶
当开发者使用 llvm.expect
内置函数时,即通过使用 __builtin_expect(...)
,他们试图向优化器传达他们的代码在运行时的预期行为。然而,这些注解可能因多种原因而不正确:代码库的更改会使其静默失效,开发者错误地注解了它们(例如,使用 LIKELY
而不是 UNLIKELY
),或者他们在编写注解时可能错误地假设了某些事情。无论出于何种原因,检测这些情况都是有用的,这样优化器就可以对代码做出更有用的决策。MisExpect 诊断旨在通过将 llvm.expect
内置函数的使用与性能剖析输入提供的真实情况进行比较,来帮助开发者识别和解决这些情况。
LLVM 后端中的 MisExpect 检查遵循一个简单的过程:如果性能剖析期间收集的分支权重与 llvm.expect
内置函数提供的分支权重不匹配,则它将向用户发出诊断消息。
执行验证的最自然的位置是在分支权重以分支权重元数据的形式分配给目标指令之前。
在 LLVM 后端中有 3 个关键位置,分支权重是基于性能剖析信息或 llvm.expect
内置函数的使用而创建和分配的,我们的实现侧重于在这些位置执行验证。
我们基于编译器分配给 llvm.expect
内置函数的值来计算发出 MisExpect 相关诊断的阈值,这些值可以通过 -likely-branch-weight
和 -unlikely-branch-weight
LLVM 选项设置。在验证期间,如果性能剖析权重与计算的阈值不匹配,那么我们将发出备注或警告,详细说明潜在的性能回归。诊断还会报告性能剖析期间注解正确的百分比,以帮助开发者思考如何继续。
诊断也以优化备注的形式提供,可以通过 LLVM 中的 opt-viewer.py
脚本进行序列化和处理。
- -pass-remarks=misexpect¶
当性能剖析数据与
llvm.expect
内置函数的使用冲突时,启用 misexpect 的优化备注。
- -pgo-warn-misexpect¶
当性能剖析数据与
llvm.expect
内置函数的使用冲突时,启用 misexpect 警告。
LLVM 支持 4 种类型的性能剖析格式:前端、IR、CS-IR 和采样。MisExpect 诊断与所有性能剖析格式兼容。
性能剖析类型 |
描述 |
---|---|
前端 |
在编译期间由前端添加的性能剖析 instrumentation,即 |
IR |
由 LLVM 后端添加的性能剖析 instrumentation |
CS-IR |
基于上下文敏感 IR 的性能剖析 |
采样 |
通过使用外部工具(例如 Linux 上的 |