通過git bisect快速定位大型工程中的問題

小米運維發表於2019-04-04

本文介紹瞭如何通過git bisect來快速定位大型工程中所存在的問題

上篇文章回顧:公有云運維福利-開源監控小工具:Open-Falcon外掛cloud-mon

通過git bisect快速定位大型工程中的問題


背景

在開發測試一個重IO操作的應用場景時,我們發現SSD的隨機混合讀寫的數值,在 linux 4.9.2核心上和在linux 4.8.2上有很大的差異,基於此我們開始探索各種方法來解決定位的問題。

                                         通過git bisect快速定位大型工程中的問題

方法探索

初期思路

解決問題初期,我們嘗試用以下三種方式來定位問題所在

  • 搜尋相關文獻

  • 求助於相關社群

  • 逐一測試可行方案

但是,經過大約兩週的搜尋、原始碼修改、編譯和測試,我們仍未定位到問題所在。於是,我們開始尋找其他的解決辦法。

二分查詢

二分查詢(binary search)是一種在有序陣列中查詢某一特定元素的搜尋演算法。

搜尋過程從陣列的中間元素開始,如果中間元素正好是要查詢的元素,則搜尋過程結束;

如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中查詢,並且跟開始一樣從中間元素開始比較;

如果在某一步驟陣列為空,則代表找不到。

這種搜尋演算法每一次比較都使得搜尋範圍縮小一半。

git bisect

git bisect是通過二分查詢來快速定位引入問題commit一個工具,通過它能夠在我們已知的good和bad兩個tag的情況下,確定某個commit。

我們將linux核心程式碼託管於git倉庫,在這其中發現git自帶的bisect命令,可以幫助定位問題所在。

使用方法

首先執行git bisect start來開始bisect查詢,接著執行git bisect bad [bad_commit] ( 若不指定則認為當前commit為bad )來告訴系統哪次提交是有問題的。然後再使用git isect good [good_commit]告訴bisect已知的最後一次正常狀態是哪次提交的,如下所示:

git bisect start
git bisect bad
git bisect good v1
Bisecting: `N` revisions left to test after this[XXXXXXXXXXXXXXX] 中間版本的commit資訊複製程式碼

之後git會自動切換到[bad_commit][good_commit]中間位置的commit版本,以供我們進行測試,觀察在這個提交下,問題是否還是存在。

如果還存在,說明問題是在這個commit之前引入的;如果不存在,說明問題是在這個commit之後引入的。

假設測試結果沒有問題,就可以通過git bisect good來告訴git來繼續尋找,如下所示

git bisect good
Bisecting: `N/2` revisions left to test after this
[XXXXXXXXXXXXXXX] commit資訊複製程式碼

重複執行測試,如果發現這個commit是有問題的,可以通過git bisect bad告訴 git。

git bisect bad
Bisecting: `N/2/2` revisions left to test after this
[XXXXXXXXXXXXXXX] commit資訊複製程式碼

如此迴圈往復,當執行完最後一個revisions之後,引入問題的commit就找到了

開始實踐

確定提交版本

因為linux核心是不同分支並行開發的,所以我們所遇到的問題也是跨了兩個版本,因此首先我們需要找到linux 4.8.2與linux 4.9.2的連續分支。

git —simplify-by-decoration A C D   
git log —graph —decorate —oneline —simplify-by-decoration A B C複製程式碼

得到good 9395452b4aab以及bad 1001354ca341

進行測試

整個測試過程完全是靠人力的投入完成的,對於每一個bisect給出的版本都要進行編譯安裝

make -j24 && make modules && make modules_install && make install複製程式碼

然後進行fio磁碟讀寫測試,分析測試結果,之後選擇good或者bad來進行下一次測試。

測試結果

在經過十幾次的編譯重啟後,最終我們定位到了引入問題的commit,如圖所示

16c54688592ce8eea85d2a26d37b64fa07e3e233 is the first bad commit
commit 16c54688592ce8eea85d2a26d37b64fa07e3e233
Author: Jan Kara <jack@suse.cz>
Date:   Fri Sep 30 01:03:17 2016 -0400    

     ext4: Allow parallel DIO reads    

     We can easily support parallel direct IO reads. We only have to make    
     sure we cannot expose uninitialized data by reading allocated block to    
     which data was not written yet, or which was already truncated. That is    
     easily achieved by holding inode_lock in shared mode - that excludes all    
     writes, truncates, hole punches. We also have to guard against page    
     writeback allocating blocks for delay-allocated pages - that race is    
     handled by the fact that we writeback all the pages in the affected    
     range and the lock protects us from new pages being created there.    
     
     Signed-off-by: Jan Kara <jack@suse.cz>    
     Signed-off-by: Theodore Ts'o <tytso@mit.edu>:

040000 040000 fdd1a8714b64c422bb200d60e9822dfd63508951 0ac1c0ceaf0ddd0eb27bbb8e719179ed68bb79df M  fs複製程式碼

總結分析

為了解決核心效能損耗的問題,我們前前後後大概耗費了一個月的時間進行排查。

而我們決定通過git bisect直接排查核心程式碼以後,只花費了不到一週的時間。

由此可見,大型專案中遇到的問題,與其耗時搜尋結論,不如直接上手逐個commit排查


文章首發於共公眾號“小米運維”,點選檢視原文


相關文章