二分查找 LLVM 代码¶
简介¶
git bisect
是一个有用的工具,用于查找哪个版本引入了错误。
本文档介绍了如何使用 git bisect
。 特别是,虽然 LLVM 大部分历史是线性的,但它有一些合并提交添加了项目——这些项目合并了这些项目的线性历史。 因此,LLVM 仓库有多个根:一个“正常”根,然后每个顶层项目都有一个根,这些项目是树外开发的,然后稍后合并。 截至 2020 年初,唯一这样合并的项目是 MLIR,但 flang 很可能也会以类似的方式合并。
基本操作¶
有关详细概述,请参阅 https://git-scm.cn/docs/git-bisect。 总结如下:
git bisect start git bisect bad main git bisect good f00ba
git 将检出一个中间版本。 尝试在该版本中重现您的问题,并运行 git bisect good
或 git bisect bad
。
如果您无法在当前提交中重现问题(可能是构建已损坏),请运行 git bisect skip
,git 将选择附近的备用提交。
(要中止二分查找,请运行 git bisect reset
,如果 git 抱怨无法重置,请执行通常的 git checkout -f main; git reset --hard origin/main
操作,然后重试)。
git bisect run
¶
单个二分查找步骤通常首先需要构建 clang,然后使用刚构建的 clang 编译大型代码库。 这可能需要很长时间,因此如果它可以完全自动进行,那就太好了。 如果您编写一个可以自动重现问题的运行脚本,git bisect run
可以为您做到这一点。 编写脚本可能需要 10-20 分钟,但这几乎总是值得的——您可以在二分查找运行时做其他事情(例如编写本文档)。
这是一个运行脚本示例。 它假设您在 llvm-project
中,并且您有一个同级的 llvm-build-project
构建目录,您在其中配置了 CMake 以使用 Ninja。 您在当前目录中有一个文件 repro.c
,它使主干上的 clang 崩溃,但在版本 f00ba
上运行良好。
# Build clang. If the build fails, `exit 125` causes this # revision to be skipped ninja -C ../llvm-build-project clang || exit 125 ../llvm-build-project/bin/clang repro.c
为了确保您的运行脚本有效,最好手动运行 ./run.sh
并调整脚本直到它工作,然后根据脚本的结果手动运行一次 git bisect good
或 git bisect bad
(在脚本运行后检查 echo $?
),然后才运行 git bisect run ./run.sh
。 不要忘记将您的运行脚本标记为可执行文件——git bisect run
不会检查这一点,它只是假定每次运行脚本都失败。
一旦您的运行脚本工作,运行 git bisect run ./run.sh
,几个小时后您将知道哪个提交导致了回归。
(这是一个非常简单的运行脚本。 通常,您希望使用刚构建的 clang 来构建不同的项目,然后在运行脚本中运行该项目的已构建可执行文件。)
跨多个根进行二分查找¶
以下是 LLVM 当前历史记录的样子
A-o-o-......-o-D-o-o-HEAD / B-o-...-o-C-
A
是 LLVM 中的第一个提交,97724f18c79c
。
B
是 MLIR 中的第一个提交,aed0d21a62db
。
D
是将 MLIR 合并到主 LLVM 仓库的合并提交,0f0d0ed1c78f
。
C
是 MLIR 在合并之前的最后一个提交,0f0d0ed1c78f^2
。 (^n
修饰符选择合并提交的第 n 个父提交。)
git bisect
会遍历所有父版本。 由于 MLIR 的合并方式,在 C
或更早版本的每个版本中,仅存在 mlir/
目录,而其他任何内容都不存在。
截至 2020 年初,没有 git bisect
的标志告诉它不要深入到所有可达提交中。 理想情况下,我们希望告诉它仅跟随 D
的第一个父提交。
最好的解决方法是将目录列表传递给 git bisect
:如果您知道该错误是由于 llvm、clang 或 compiler-rt 中的更改引起的,请使用
git bisect start -- clang llvm compiler-rt
这样,mlir
中的提交将永远不会被评估。
或者,git bisect skip aed0d21a6 aed0d21a6..0f0d0ed1c78f
显式跳过该分支上的所有提交。 在快速机器上运行需要 1.5 分钟,并使 git bisect log
输出变得难以阅读。 (aed0d21a6
列出两次是因为 git 范围排除左侧列出的修订版本,因此需要显式忽略它。)