Misexpect

当开发者使用 llvm.expect 内联函数,即通过使用 __builtin_expect(...),他们试图向优化器传达他们的代码在运行时的预期行为。然而,这些注释可能由于各种原因而错误:代码库的更改会静默地使它们失效,开发者错误地注释了它们(例如,使用 LIKELY 而不是 UNLIKELY),或者他们可能在编写注释时错误地假设了一些东西。无论出于何种原因,检测这些情况都是有用的,这样优化器可以对代码做出更有用的决策。

MisExpect 诊断旨在通过将 llvm.expect 内联函数添加的分支权重与通过分析收集的分支权重进行比较,帮助开发者识别和解决这些情况。只要这些值不匹配,就会向用户显示一个诊断信息。有关 LLVM 后端中检查如何运作的详细信息,请参阅 LLVM 的文档。

默认情况下,MisExpect 检查非常严格,因为 llvm.expect 内联函数的使用专为特殊情况设计,在这种情况下,条件的结果严重偏向。因此,优化器可能非常激进,如果结果不如注释建议的那样可预测,可能会导致性能下降。即使注释 90% 的时间都是正确的,也可能有利于删除注释或使用其他内联函数,该内联函数可以更直接地传达概率。

由于这可能过于严格,因此 MisExpect 诊断默认情况下未启用,并支持一个额外的标志来容忍与精确阈值的一些偏差。-fdiagnostic-misexpect-tolerance=N 在比较分支权重时,接受在预期值的 N% 内的偏差。因此,传递 -fdiagnostic-misexpect-tolerance=5 如果来自概要文件的权重在 llvm.expect 内联函数添加的权重的 5% 之内,将不会报告诊断消息。

MisExpect 诊断也以优化备注的形式提供,可以序列化并通过 LLVM 中的 opt-viewer.py 脚本来处理。

-Rpass=misexpect

当分析数据与 llvm.expect 内联函数的使用冲突时,启用 misexpect 优化备注。

-Wmisexpect

当分析数据与 llvm.expect 内联函数的使用冲突时,启用 misexpect 警告。

-fdiagnostic-misexpect-tolerance=N

放松 MisExpect 检查,以容忍分析值在预期分支权重的 N% 之内。例如,N=5 的值允许 MisExpect 检查 0.95 * Threshold

LLVM 支持 4 种类型的概要文件格式:前端、IR、CS-IR 和采样。MisExpect 诊断与所有概要文件格式兼容。

概要文件类型

描述

前端

在编译期间由前端添加的概要文件检测,例如 clang

IR

由 LLVM 后端在编译期间添加的概要文件检测

CS-IR

基于上下文敏感 IR 的概要文件

采样

通过使用外部工具(例如 Linux 上的 perf)进行采样收集的概要文件