二分搜尋 LLVM 程式碼¶
簡介¶
git bisect
是一個用於找出哪個修訂版本導致錯誤的實用工具。
本文檔描述如何使用 git bisect
。特別是,雖然 LLVM 的歷史記錄大多是線性的,但它有一些合併提交,這些提交添加了專案 – 並且這些合併了這些專案的線性歷史記錄。因此,LLVM 儲存庫有多個根:一個「正常」根,然後每個頂層專案都有一個根,這些專案是在樹外開發然後稍後合併的。截至 2020 年初,唯一這樣合併的專案是 MLIR,但 flang 很可能也會以類似的方式合併。
基本操作¶
請參閱 https://git.dev.org.tw/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 將選擇附近的替代提交。
(要中止 bisect,請執行 git bisect reset
,如果 git 抱怨無法重置,請執行通常的 git checkout -f main; git reset --hard origin/main
操作並重試)。
git bisect run
¶
單個 bisect 步驟通常需要先建置 clang,然後使用剛建置的 clang 編譯大型程式碼庫。這可能需要很長時間,因此如果它可以完全自動發生,那就太好了。git bisect run
如果您編寫一個可以自動重現問題的執行腳本,它可以為您做到這一點。編寫腳本可能需要 10-20 分鐘,但幾乎總是值得的 – 您可以在 bisect 運行時做其他事情(例如編寫本文檔)。
這是一個範例執行腳本。它假設您在 llvm-project
中,並且您有一個同級的 llvm-build-project
建置目錄,您在其中配置 CMake 以使用 Ninja。您在目前目錄中建立了一個檔案 repro.c
,它會使 clang 在 trunk 上崩潰,但在修訂版本 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 來建置不同的專案,然後在執行腳本中運行該專案的已建置可執行檔。)
跨多個根進行 Bisect¶
以下是 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 範圍排除列在左側的修訂版本,因此需要明確忽略它。)
更多資源¶
https://git.dev.org.tw/book/en/v2/Git-Tools-Revision-Selection