PGO前瞻

来源:https://www.cnblogs.com/lianshuiwuyi/archive/2023/06/25/17502845.html
-Advertisement-
Play Games

原文在[這裡](https://go.dev/blog/pgo-preview)。 > 原文發佈於2023年2月8日 在構建Go二進位文件時,Go編譯器會進行優化,以儘可能生成性能最佳的二進位文件。例如,常量傳播可以在編譯時對常量表達式進行求值,避免了運行時的計算開銷;逃逸分析可以避免對局部作用域對 ...


原文在這裡

原文發佈於2023年2月8日

在構建Go二進位文件時,Go編譯器會進行優化,以儘可能生成性能最佳的二進位文件。例如,常量傳播可以在編譯時對常量表達式進行求值,避免了運行時的計算開銷;逃逸分析可以避免對局部作用域對象進行堆分配,從而減少了垃圾回收的負擔;內聯則將簡單函數的代碼體複製到調用處,通常能夠進一步優化調用處的代碼(例如額外的常量傳播或更好的逃逸分析)。

Go在發佈的每個版本中都會改進優化,但這並不總是一項容易的任務。某些優化是可調節的,但編譯器不能對每個函數都進行過度激進的優化,因為過於激進的優化實際上可能會損害性能或導致過長的構建時間。其他優化要求編譯器對函數中的“常見”和“不常見”路徑進行判斷。編譯器必鬚根據靜態啟髮式規則進行最佳猜測,因為它無法在運行時知道哪些情況將是常見的。

但現在編譯器可以在運行時知道哪些情況是常見的了。

在沒有關於代碼在生產環境中如何使用的確切信息的情況下,編譯器只能對包的源代碼進行操作。但是我們確實有一種工具來評估生產行為:性能分析。如果我們向編譯器提供一個性能分析文件,它就可以做出更明智的決策:對最常用的函數進行更積極的優化,或更準確地選擇常見情況。

使用應用程式行為的性能分析文件進行編譯器優化的方法被稱為基於性能分析的優化(Profile-Guided Optimization,簡稱PGO,也被稱為反饋導向優化(Feedback-Directed Optimization,簡稱FDO))。

PGO/FDO通過收集和分析運行時的性能數據,使得編譯器能夠更準確地瞭解代碼的執行特性,從而進行更精細的優化。通過結合靜態分析和動態運行時數據,PGO/FDO可以產生更優化的代碼,提高程式的性能和效率。這種技術在提高大型複雜應用程式的性能方面非常有用,特別是對於高度頻繁執行的代碼路徑進行優化。

Go 1.20中包含了PGO的初步支持,作為預覽版本提供。請參閱profile-guided optimization user guide以獲取完整的文檔。儘管距離在生產環境中使用還有一段距離,但仍希望大家在工作中使用,並反饋遇到的問題或意見

示例

以Markdown轉HTML服務為例:用戶通過/render上傳Markdown文件,然後接收轉換後的HTML文件。這裡使用gitlab.com/golang-commonmark/markdown

創建項目

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

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/06/25 11:27:13 Serving on port 8080...  

使用Go項目的README來進行測試:

$ 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>  
...  
<p>Note that the Go project uses the issue tracker for bug reports and
proposals only. See <a href="https://go.dev/wiki/Questions">https://go.dev/wiki/Questions</a> for a list of
places to ask questions about the Go language.</p>  

性能分析

現在我們來採集一個profile文件,再使用PGO來重新構建服務,看看性能能提升多少。

main.go中,我們導入了net/http/pprof包,它會自動為伺服器添加一個/debug/pprof/profile地址,用於獲取CPU分析數據。

通常情況下,我們都是從生產環境中收集性能分析數據,以便編譯器能夠獲取在實際生產環境中的行為情況。但這個示例沒有一個真實的“生產”環境,我們將創建一個簡單的程式來生成負載,同時收集性能分析數據。將該程式的源碼複製到load/main.go,並啟動負載生成器(確保伺服器仍在運行!)。

$ go run example.com/markdown/load

下載性能分析文件:

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

下載完成後,關閉服務。

啟用PGO

我們可以使用go build命令的-pgo標誌要求Go工具鏈使用PGO進行構建。-pgo標誌可以接受以下兩種參數:

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

我們建議將default.pgo性能分析文件提交到你的代碼倉庫中。將性能分析文件與源代碼放在一起,可以確保用戶只需獲取代碼倉庫(無論是通過版本控制系統還是通過go get命令),就能自動獲得性能分析文件,並且構建過程仍然可重現。在Go 1.20中,預設的-pgo選項是off,因此用戶仍需要添加-pgo=auto選項,但預計將來的Go版本將把預設值改為-pgo=auto,這樣任何構建該二進位文件的人都將獲得PGO的好處。

構建:

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

性能對比

我們將使用一個基於Go的基準測試版本的負載生成器來評估PGO對性能的影響。將這個基準測試的代碼複製到load/bench_test.go文件中。

首先沒有使用PGO的情況下進行測試:

$ ./markdown.nopgo  

進行測試:

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

然後啟用PGO:

$ ./markdown.withpgo  

進行測試:

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

運行結束後進行結果對比:

$ go install golang.org/x/perf/cmd/benchstat@latest  
$ benchstat nopgo.txt withpgo.txt
goos: linux
goarch: amd64
pkg: example.com/markdown/load
cpu: 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中,通過啟用PGO,可以獲得2%到4%的CPU使用率提升。性能分析文件包含了關於應用程式行為的豐富信息,而Go 1.20僅僅開始利用這些信息進行內聯優化。未來的發佈版本將繼續改進性能,因為編譯器的更多部分將利用PGO帶來的好處。

原文中效率提升了2.6%

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


孟斯特

聲明:本作品採用署名-非商業性使用-相同方式共用 4.0 國際 (CC BY-NC-SA 4.0)進行許可,使用時請註明出處。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 戀水無意



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ## 前言 在C語言中,指針是一種非常強大和靈活的工具,但同時也容易引發一些問題,其中包括空指針和野指針。 本文將帶你瞭解這兩個概念的含義、產生原因以及如何避免它們所導致的問題。 ## 一、人物簡介 - 第一位閃亮登場,有請今後會一直教我們C語言的老師 —— 自在。 ![](https://img2 ...
  • 今晚來聊聊我在**技術成長**中的一些感悟,跟大家分享下。 ## BALABALA 在大學的時候,我一個電腦專業相關的證書都沒考,自認為這些證書對我以後找工作沒什麼大的幫助。於是我把時間更多地花在研究八股文上,因為八股文在面試的時候是要用到的。 (**利益化**) > **我會對我做的事情利益化* ...
  • ### Kubernetes 概述 當下,我們很多項目於都在`Cloud Native`(雲原生)的上面,這種方法旨在使組織能夠確保可用性並快速響應和適應變化,雲原生其實就是一組本質上支持在不同雲環境(公共雲、私有雲或混合雲)上大規模構建、運行和管理應用程式的實踐和技術。 雲原生離不開兩個概念:`容 ...
  • # 下載 這就不多說了,直接官網下載 https://tomcat.apache.org/ 直接解壓 配置 環境變數 (提前安裝好java,配置好java的環境變數) 配置Tomcat環境變數前一定要配置好java的環境變數,尤其是JAVA_HOME 新建 `CATALINA_HOME` 環境變數, ...
  • 狀態機,包括了狀態和動作,某個**狀態**下,只能執行某些**動作**,如果**動作**不匹配,狀態是不會進行變更了,這樣就保護了我們狀態欄位的準備性,不能隨意改變,必須按著我們**設計的規則**進行狀態的輪轉。 # Stateless實現的狀態機 1. **Stateless**:Stateles ...
  • 來源:blog.csdn.net/qq_35387940/article/details/129167329 ## **前言** 平時做一些統計數據,經常從資料庫或者是從介面獲取出來的數據,單位是跟業務需求不一致的。 - 比如, 我們拿出來的 分, 實際上要是元 - 又比如,我們拿到的數據需要 乘以 ...
  • # 1.文件路徑 我們發現不管是寫入還是寫出操作,我們提供的都是文件名,其實這裡準確說應該是文件路徑。當我們簡單把文件名傳遞給open函數時,Python將在當前執行程式的文件所在的目錄中查找文件名所代表的文件。 根據組織文件的方式,可能需要打開不在當前執行程式文件所屬目錄中的文件。如果此時我們把該 ...
  • ## 初級指針 本篇主要介紹:`指針和變數的關係`、指針類型、`指針的運算符`、空指針和野指針、`指針和數組`、`指針和字元串`、const 和指針、以及`gdb 調試段錯誤`。 ### 基礎概念 > 指針是一種特殊的變數。存放地址的變數就是指針。 `int num = 1;` 會申請4個位元組的記憶體 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...