一個 Benchmark 比較分析工具
回復(fù)“Go語言”即可獲贈從入門到進(jìn)階共10本電子書
在 Go 中,通過撰寫 Benchmark 函數(shù)可以很方便地對某個功能點(diǎn)進(jìn)行性能檢測。對于重要的函數(shù),我們可以在 CI/CD 中添加相應(yīng)的測試流程,當(dāng)函數(shù)性能發(fā)生變化時能夠及時感知。那問題來了,如何檢測函數(shù)的性能變化?
換個說法,你編寫了某功能函數(shù)但發(fā)現(xiàn)它運(yùn)行很慢,需要對該函數(shù)進(jìn)行優(yōu)化,當(dāng)你在谷歌搜索找到更好的實(shí)現(xiàn)方式,通過 Benchmark 函數(shù)發(fā)現(xiàn)它的確變快了。但你說不清楚具體變快了多少,你想知道函數(shù)優(yōu)化前后的性能對比,提高多少百分點(diǎn),可信度高嗎?
針對以上的需求場景,有一個工具可以幫助到你,它就是 benchstat。
Benchmark 示例
我們先回顧一下基準(zhǔn)測試。為了方便理解,這里以計(jì)算經(jīng)典的計(jì)算斐波那契數(shù)列值為例。
func?FibSolution(n?int)?int?{
?if?n?2?{
??return?n
?}
?return?FibSolution(n-1)?+?FibSolution(n-2)
}
上述代碼是遞歸式實(shí)現(xiàn),很明顯,當(dāng) n 越來越大時,該函數(shù)的運(yùn)行會變得非常耗時。以 n 為 20 為例,Benchmark 函數(shù)如下
func?BenchmarkFib20(b?*testing.B)?{
?for?i?:=?0;?i???FibSolution(20)
?}
}
命令行執(zhí)行go test -bench=BenchmarkFib20得到性能結(jié)果
BenchmarkFib20-8???????????39452?????????????30229?ns/op
其中,-8 代表的是 8 cpu,函數(shù)運(yùn)行次數(shù)為 39452,每次函數(shù)的平均花費(fèi)時間為 30229ns。如果我們想得到多次樣本數(shù)據(jù),可以指定 go test 的 -count=N 參數(shù)。例如想得到 5 次樣本數(shù)據(jù),則執(zhí)行go test -bench=BenchmarkFib20 -count=5
BenchmarkFib20-8???????????39325?????????????30297?ns/op
BenchmarkFib20-8???????????39216?????????????30349?ns/op
BenchmarkFib20-8???????????39901?????????????30251?ns/op
BenchmarkFib20-8???????????39336?????????????30455?ns/op
BenchmarkFib20-8???????????39423?????????????30894?ns/op
計(jì)算斐波那契數(shù)列值的迭代式實(shí)現(xiàn)如下
func?FibSolution(n?int)?int?{
?if?n?2?{
??return?n
?}
?p,?q,?r?:=?0,?0,?1
?for?i?:=?2;?i?<=?n;?i++?{
??p?=?q
??q?=?r
??r?=?p?+?q
?}
?return?r
}
對比這兩種函數(shù)的性能差異,最樸素的方式就是分別對這兩個函數(shù)進(jìn)行基準(zhǔn)測試,然后通過手工分析這些基準(zhǔn)測試結(jié)果,但是這并不直觀。
benchstat
benchstat 是 Go 官方推薦的一款命令行工具,它用于計(jì)算和比較基準(zhǔn)測試的相關(guān)統(tǒng)計(jì)數(shù)據(jù)。
我們可以通過以下命令進(jìn)行安裝
go?install?golang.org/x/perf/cmd/benchstat@latest
執(zhí)行 -h 參數(shù)可以看到該工具的使用描述
~?$?benchstat?-h
usage:?benchstat?[options]?old.txt?[new.txt]?[more.txt?...]
options:
??-alpha?α
?????consider?change?significant?if?p???-csv
?????print?results?in?CSV?form
??-delta-test?test
?????significance?test?to?apply?to?delta:?utest,?ttest,?or?none?(default?"utest")
??-geomean
?????print?the?geometric?mean?of?each?file
??-html
?????print?results?as?an?HTML?table
??-norange
?????suppress?range?columns?(CSV?only)
??-sort?order
?????sort?by?order:?[-]delta,?[-]name,?none?(default?"none")
??-split?labels
?????split?benchmarks?by?labels?(default?"pkg,goos,goarch")
我們想比較 FibSolution(n) 從 15 到 20,兩種實(shí)現(xiàn)方式的性能基準(zhǔn)測試。
$?go?test?-bench=.?-count=5?|?tee?old.txt
$?go?test?-bench=.?-count=5?|?tee?new.txt
注意,這兩條命令執(zhí)行時,分別對應(yīng) FibSolution 函數(shù)采用遞歸式和迭代式實(shí)現(xiàn)邏輯。
此時,我們可以對這兩個函數(shù)實(shí)現(xiàn)邏輯進(jìn)行性能對比
?$?benchstat?old.txt?new.txt?
name?????old?time/op??new?time/op??delta
Fib15-8??2.67μs?±?2%??0.01μs?±?5%??-99.81%??(p=0.008?n=5+5)
Fib16-8??4.20μs?±?1%??0.01μs?±?2%??-99.87%??(p=0.008?n=5+5)
Fib17-8??6.81μs?±?0%??0.01μs?±?2%??-99.92%??(p=0.008?n=5+5)
Fib18-8??11.1μs?±?1%???0.0μs?±?1%??-99.95%??(p=0.008?n=5+5)
Fib19-8??18.0μs?±?2%???0.0μs?±?4%??-99.97%??(p=0.008?n=5+5)
Fib20-8??29.2μs?±?1%???0.0μs?±?3%??-99.98%??(p=0.008?n=5+5)
可以看到,遞歸式實(shí)現(xiàn)的函數(shù),他的執(zhí)行時間隨著 n 值變大增加非常明顯。迭代式實(shí)現(xiàn)方式,相較于遞歸式,它的平均時間開銷降低了 99 % 以上,優(yōu)化效果非常明顯。
另外,p=0.008 表示結(jié)果的可信程度,p 值越大表明可信度越低。一般以 0.05 作為臨界值,超過該值,則結(jié)果不可信。n=5+5 表示分別使用的有效樣本數(shù)量。
總結(jié)
benchstat 是一個基準(zhǔn)測試統(tǒng)計(jì)工具,當(dāng)我們做一些優(yōu)化工作時,可以利用它減輕人工分析數(shù)據(jù)成本。
如果你的項(xiàng)目在 CI/CD 流程中有部署自動化測試,那不妨將該工具加入進(jìn)來。在對函數(shù)有改動且加劇了性能損耗時,它或許能幫助你提前發(fā)現(xiàn)問題。
-------------------?End?-------------------
往期精彩文章推薦:

歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持
想加入Go學(xué)習(xí)群請?jiān)诤笈_回復(fù)【入群】
萬水千山總是情,點(diǎn)個【在看】行不行
