Go PGO 快速上手,性能可提高 2~4-!
大家好,我是煎魚。
2023 年初,在 Go1.20,PGO 發佈了預覽版本。在本次 Go1.21 的新版本發佈,修復了各種問題後,PGO 已經正式官宣生產可用。
今天這篇文章就是和大家一起跟着官方示例,快速體驗他的性能優化和使用。
溫習一下 PGO
Profile-guided optimization (PGO),PGO 是計算機編程中的一種編譯器優化技術,藉助配置文件來引導編譯,達到提高程序運行時性能的目的。
翻譯過來是使用配置文件引導的優化,能提供應用程序的性能。也被稱爲:
-
profile-directed feedback(PDF)
-
feedback-directed optimization(FDO)
該項優化是一個通用技術,不侷限於某一門語言。像是我們常見很多應用都有所使用其來優化。如下幾個案例:
-
Chrome 瀏覽器,在 64 位版本的 Chrome 中從 53 版開始啓用 PGO, 32 位版在 54 版中啓用。
-
AutoFDO 進行了 PGO 的優化,直接將某數據中心中的 C/C++ 程序的性能提高了 5-15%(不用改業務代碼)。
Go 怎麼讀取 PGO
PGO 第一個版本先支持的 pprof CPU,直接讀取 pprof CPU profile 文件來完成優化。
有以下兩種方式:
-
手動指定:Go 工具鏈在 go build 子命令增加了
-pgo=<path>
參數,用於顯式指定用於 PGO 構建的 profile 文件位置。 -
自動指定:當 Go 工具鏈在主模塊目錄下找到 default.pgo 的配置文件時,將會自動啓用 PGO。
快速 Demo
初始化應用程序
首先我們創建一個 Demo 目錄,用於做一系列的實驗。執行如下命令:
$ mkdir pgo-demo && cd pgo-demo
初始化模塊路徑和拉取程序所需的依賴:
$ go mod init example.com/markdown
go: creating new go.mod: module example.com/markdown
$ go get gitlab.com/golang-commonmark/markdown@bf3e522c626a
創建 main.go 文件,寫入如下
package main
import (
"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.Buffer
if 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))
}
編譯並運行應用程序:
$ go build -o markdown.nopgo
$ ./markdown.nopgo
2023/10/02 13:55:40 Serving on port 8080...
運行起來後進行驗證,這是一個將 Markdown 轉換爲 HTML 的應用程序。
我們從 GitHub 上拉取一份 markdown 文件並給到該程序進行轉換。如下命令:
$ curl -o README.md -L "https://raw.githubusercontent.com/golang/go/c16c2c49e2fa98ae551fc6335215fadd62d33542/README.md"
$ curl --data-binary @README.md http://localhost:8080/render
<h1>The Go Programming Language</h1>
<p>Go is an open source programming language that makes it easy to build simple,
reliable, and efficient software.</p>
...
如果正常則說明運行沒問題。
收集 PGO 所需的配置文件
一般情況下,我們可以通過生產、測試環境的 pprof 採集所需的 profile 文件,用於做 PGO 的配置文件。
但由於示例沒有對應的生產環境。本次快速 Demo,Go 官方提供了一個簡單的程序來快速的發壓。
在確保前面小節的 pgo-demo 程序正常運行的情況下。運行如下命令,啓動一個發壓程序:
$ go run github.com/prattmic/markdown-pgo/load@latest
收集對應的 profile 文件:
$ curl -o cpu.pprof "http://localhost:8080/debug/pprof/profile?seconds=30"
生成了一個 cpu.pprof 文件,可以在後續使用。
應用程序使用 PGO
前面我們有提到,當模塊目錄下包含 default.pgo 時。Go 工具鏈就會自動應用 PGO。
我們只需要將前面的 cpu.pprof 修改一下即可。執行如下命令:
$ mv cpu.pprof default.pgo
$ go build -o markdown.withpgo
編譯成功後,使用如下命令驗證是否正常:
$ go version -m markdown.withpgo
markdown.withpgo: go1.21.1
path example.com/markdown
mod example.com/markdown (devel)
...
build GOOS=darwin
build GOAMD64=v1
build -pgo=/Users/eddycjy/app/go/pgo-demo/default.pgo
可以看到最後的build -pgo=...
,代表該應用程序成功應用了我們的 default.pgo 文件(啓用 PGO)。
總結
PGO 作爲 Go 新版本的一個性能好幫手,在官方給出的數據中啓用 PGO 後,性能能夠得到一定的提升。但也會帶來其他方面(CPU、大小等)的開銷增加。
如本文的例子中,官方給出的數據是程序性能提升了約 2~4%,CPU 使用率會帶來 2~7% 的開銷增加。也可能會導致構建時長變長一些、編譯後的二進制文件會稍微大一些。
面對一些場景,PGO 是一個不錯的性能優化方式。但有利必有弊,就看這個應用程序的類型和綜合取捨了。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/mjbx3fUMjkynuhXoQ1yxog