我们每天将为您更新无码免费_婷婷中文字幕视频在线_yy6080无码av午夜福利免费_91精品国产免费久久久久久无码_黄片在线免费播放

當(dāng)前位置: 首頁(yè) >觀察 > 正文

當(dāng)前速讀:PGO前瞻

2023-06-25 17:31:02 來(lái)源:博客園

原文在這里。


【資料圖】

原文發(fā)布于2023年2月8日

在構(gòu)建Go二進(jìn)制文件時(shí),Go編譯器會(huì)進(jìn)行優(yōu)化,以盡可能生成性能最佳的二進(jìn)制文件。例如,常量傳播可以在編譯時(shí)對(duì)常量表達(dá)式進(jìn)行求值,避免了運(yùn)行時(shí)的計(jì)算開(kāi)銷(xiāo);逃逸分析可以避免對(duì)局部作用域?qū)ο筮M(jìn)行堆分配,從而減少了垃圾回收的負(fù)擔(dān);內(nèi)聯(lián)則將簡(jiǎn)單函數(shù)的代碼體復(fù)制到調(diào)用處,通常能夠進(jìn)一步優(yōu)化調(diào)用處的代碼(例如額外的常量傳播或更好的逃逸分析)。

Go在發(fā)布的每個(gè)版本中都會(huì)改進(jìn)優(yōu)化,但這并不總是一項(xiàng)容易的任務(wù)。某些優(yōu)化是可調(diào)節(jié)的,但編譯器不能對(duì)每個(gè)函數(shù)都進(jìn)行過(guò)度激進(jìn)的優(yōu)化,因?yàn)檫^(guò)于激進(jìn)的優(yōu)化實(shí)際上可能會(huì)損害性能或?qū)е逻^(guò)長(zhǎng)的構(gòu)建時(shí)間。其他優(yōu)化要求編譯器對(duì)函數(shù)中的“常見(jiàn)”和“不常見(jiàn)”路徑進(jìn)行判斷。編譯器必須根據(jù)靜態(tài)啟發(fā)式規(guī)則進(jìn)行最佳猜測(cè),因?yàn)樗鼰o(wú)法在運(yùn)行時(shí)知道哪些情況將是常見(jiàn)的。

但現(xiàn)在編譯器可以在運(yùn)行時(shí)知道哪些情況是常見(jiàn)的了。

在沒(méi)有關(guān)于代碼在生產(chǎn)環(huán)境中如何使用的確切信息的情況下,編譯器只能對(duì)包的源代碼進(jìn)行操作。但是我們確實(shí)有一種工具來(lái)評(píng)估生產(chǎn)行為:性能分析。如果我們向編譯器提供一個(gè)性能分析文件,它就可以做出更明智的決策:對(duì)最常用的函數(shù)進(jìn)行更積極的優(yōu)化,或更準(zhǔn)確地選擇常見(jiàn)情況。

使用應(yīng)用程序行為的性能分析文件進(jìn)行編譯器優(yōu)化的方法被稱(chēng)為基于性能分析的優(yōu)化(Profile-Guided Optimization,簡(jiǎn)稱(chēng)PGO,也被稱(chēng)為反饋導(dǎo)向優(yōu)化(Feedback-Directed Optimization,簡(jiǎn)稱(chēng)FDO))。

PGO/FDO通過(guò)收集和分析運(yùn)行時(shí)的性能數(shù)據(jù),使得編譯器能夠更準(zhǔn)確地了解代碼的執(zhí)行特性,從而進(jìn)行更精細(xì)的優(yōu)化。通過(guò)結(jié)合靜態(tài)分析和動(dòng)態(tài)運(yùn)行時(shí)數(shù)據(jù),PGO/FDO可以產(chǎn)生更優(yōu)化的代碼,提高程序的性能和效率。這種技術(shù)在提高大型復(fù)雜應(yīng)用程序的性能方面非常有用,特別是對(duì)于高度頻繁執(zhí)行的代碼路徑進(jìn)行優(yōu)化。

Go 1.20中包含了PGO的初步支持,作為預(yù)覽版本提供。請(qǐng)參閱profile-guided optimization user guide以獲取完整的文檔。盡管距離在生產(chǎn)環(huán)境中使用還有一段距離,但仍希望大家在工作中使用,并反饋遇到的問(wèn)題或意見(jiàn)。

示例

以Markdown轉(zhuǎn)HTML服務(wù)為例:用戶通過(guò)/render上傳Markdown文件,然后接收轉(zhuǎn)換后的HTML文件。這里使用gitlab.com/golang-commonmark/markdown。

創(chuàng)建項(xiàng)目

$ go mod init example.com/markdown  $ go get gitlab.com/golang-commonmark/markdown  

main.go內(nèi)容:

package mainimport ("bytes""io""log""net/http"_ "net/http/pprof""gitlab.com/golang-commonmark/markdown")func render(w http.ResponseWriter, r *http.Request) {if r.Method != "POST" {http.Error(w, "Only POST allowed", http.StatusMethodNotAllowed)return}src, err := io.ReadAll(r.Body)if err != nil {log.Printf("error reading body: %v", err)http.Error(w, "Internal Server Error", http.StatusInternalServerError)return}md := markdown.New(markdown.XHTMLOutput(true),markdown.Typographer(true),markdown.Linkify(true),markdown.Tables(true),)var buf bytes.Bufferif err := md.Render(&buf, src); err != nil {log.Printf("error converting markdown: %v", err)http.Error(w, "Malformed markdown", http.StatusBadRequest)return}if _, err := io.Copy(w, &buf); err != nil {log.Printf("error writing response: %v", err)http.Error(w, "Internal Server Error", http.StatusInternalServerError)return}}func main() {http.HandleFunc("/render", render)log.Printf("Serving on port 8080...")log.Fatal(http.ListenAndServe(":8080", nil))}

啟動(dòng)服務(wù):

$ go build -o markdown.nopgo$ ./markdown.nopgo2023/06/25 11:27:13 Serving on port 8080...  

使用Go項(xiàng)目的README來(lái)進(jìn)行測(cè)試:

$ curl -o README.md -L "https://raw.githubusercontent.com/golang/go/c16c2c49e2fa98ae551fc6335215fadd62d33542/README.md"  $ curl --data-binary @README.md http://localhost:8080/render  

The Go Programming Language

Go is an open source programming language that makes it easy to build simple,reliable, and efficient software.

...

Note that the Go project uses the issue tracker for bug reports andproposals only. See https://go.dev/wiki/Questions for a list ofplaces to ask questions about the Go language.

性能分析

現(xiàn)在我們來(lái)采集一個(gè)profile文件,再使用PGO來(lái)重新構(gòu)建服務(wù),看看性能能提升多少。

main.go中,我們導(dǎo)入了net/http/pprof包,它會(huì)自動(dòng)為服務(wù)器添加一個(gè)/debug/pprof/profile地址,用于獲取CPU分析數(shù)據(jù)。

通常情況下,我們都是從生產(chǎn)環(huán)境中收集性能分析數(shù)據(jù),以便編譯器能夠獲取在實(shí)際生產(chǎn)環(huán)境中的行為情況。但這個(gè)示例沒(méi)有一個(gè)真實(shí)的“生產(chǎn)”環(huán)境,我們將創(chuàng)建一個(gè)簡(jiǎn)單的程序來(lái)生成負(fù)載,同時(shí)收集性能分析數(shù)據(jù)。將該程序的源碼復(fù)制到load/main.go,并啟動(dòng)負(fù)載生成器(確保服務(wù)器仍在運(yùn)行!)。

$ go run example.com/markdown/load

下載性能分析文件:

$ curl -o cpu.pprof "http://localhost:8080/debug/pprof/profile?seconds=30"  

下載完成后,關(guān)閉服務(wù)。

啟用PGO

我們可以使用go build命令的-pgo標(biāo)志要求Go工具鏈?zhǔn)褂肞GO進(jìn)行構(gòu)建。-pgo標(biāo)志可以接受以下兩種參數(shù):

  • 指定要使用的性能分析文件的路徑
  • 使用"auto",它將使用主包目錄中的default.pgo文件

我們建議將default.pgo性能分析文件提交到你的代碼倉(cāng)庫(kù)中。將性能分析文件與源代碼放在一起,可以確保用戶只需獲取代碼倉(cāng)庫(kù)(無(wú)論是通過(guò)版本控制系統(tǒng)還是通過(guò)go get命令),就能自動(dòng)獲得性能分析文件,并且構(gòu)建過(guò)程仍然可重現(xiàn)。在Go 1.20中,默認(rèn)的-pgo選項(xiàng)是off,因此用戶仍需要添加-pgo=auto選項(xiàng),但預(yù)計(jì)將來(lái)的Go版本將把默認(rèn)值改為-pgo=auto,這樣任何構(gòu)建該二進(jìn)制文件的人都將獲得PGO的好處。

構(gòu)建:

$ mv cpu.pprof default.pgo$ go build -pgo=auto -o markdown.withpgo

性能對(duì)比

我們將使用一個(gè)基于Go的基準(zhǔn)測(cè)試版本的負(fù)載生成器來(lái)評(píng)估PGO對(duì)性能的影響。將這個(gè)基準(zhǔn)測(cè)試的代碼復(fù)制到load/bench_test.go文件中。

首先沒(méi)有使用PGO的情況下進(jìn)行測(cè)試:

$ ./markdown.nopgo  

進(jìn)行測(cè)試:

$ go test example.com/markdown/load -bench=. -count=100 -source ../README.md > nopgo.txt

然后啟用PGO:

$ ./markdown.withpgo  

進(jìn)行測(cè)試:

$ go test example.com/markdown/load -bench=. -count=100 -source ../README.md > withpgo.txt

運(yùn)行結(jié)束后進(jìn)行結(jié)果對(duì)比:

$ go install golang.org/x/perf/cmd/benchstat@latest  $ benchstat nopgo.txt withpgo.txtgoos: linuxgoarch: amd64pkg: example.com/markdown/loadcpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz       │  nopgo.txt  │             withpgo.txt             │       │   sec/op    │   sec/op     vs base                │Load-8   445.1μ ± 4%   408.6μ ± 2%  -8.21% (p=0.000 n=100)

新版本大約快了8.2%!在Go 1.20中,通過(guò)啟用PGO,可以獲得2%到4%的CPU使用率提升。性能分析文件包含了關(guān)于應(yīng)用程序行為的豐富信息,而Go 1.20僅僅開(kāi)始利用這些信息進(jìn)行內(nèi)聯(lián)優(yōu)化。未來(lái)的發(fā)布版本將繼續(xù)改進(jìn)性能,因?yàn)榫幾g器的更多部分將利用PGO帶來(lái)的好處。

原文中效率提升了2.6%

文中的代碼可以在這里找到。

聲明:本作品采用署名-非商業(yè)性使用-相同方式共享 4.0 國(guó)際 (CC BY-NC-SA 4.0)進(jìn)行許可,使用時(shí)請(qǐng)注明出處。Author: mengbinblog: mengbinGithub: mengbin92cnblogs: 戀水無(wú)意

標(biāo)簽:

返回頂部