大家好,我是煎鱼。
Go1.20 行将公布,近期很多大佬提到一个关键词 PGO,说是有很大的进步,很猛 … 让我一愣一愣,不禁思考是什么?
明天就由煎鱼和大家一起学习。
疾速理解
PGO 是什么
Profile-guided optimization (PGO),翻译过去是应用配置文件疏导的优化。也被称为:
- profile-directed feedback(PDF)
- feedback-directed optimization(FDO)
PGO 是计算机编程中的 一种编译器优化技术,应用剖析来进步程序运行时性能。也就是能够进步 Go 运行时的性能。
该项优化是一个通用技术,不局限于某一门语言。像是:
- 罕用的 Chrome 浏览器,在 64 位版本的 Chrome 中从 53 版开始启用 PGO,32 位版在 54 版中启用。
- Microsoft Visual C++ 也同样有所应用。
- AutoFDO 进行了 PGO 的优化,间接将某数据中心中的 C/C++ 程序的性能进步了 5-15%(不必改业务代码)。
这个优化问题,一听就很振奋人心。
PGO 怎么优化
《Intel Developer Guide and Reference》中对 PGO 的优化和流程有一个根本介绍,如下内容,分享给大家。
PGO 通过放大代码大小、缩小分支谬误预测和从新组织代码布局以缩小指令缓存问题来进步应用程序性能。并向编译器提供无关应用程序中最常执行的区域的信息。通过理解这些畛域,编译器可能在优化应用程序时更具选择性和针对性。
PGO 由三个阶段组成。如下图:
- 检测程序。编译器从您的源代码和编译器的非凡代码创立并链接一个检测程序。
- 运行检测的可执行文件。每次执行插桩代码时,插桩程序都会生成一个动静信息文件,用于最终编译。
- 最终编译。当您第二次编译时,动静信息文件将合并到一个摘要文件中。应用此文件中的概要信息摘要,编译器尝试优化程序中最频繁的运行门路去执行。
这就是 PGO 这项优化的根本过程了。
新提案
背景
提案作者(Cherry Mui、Austin Clements、Michael Pratt)倡议向 Go GC 工具链减少对配置文件疏导优化 (PGO) 的反对,能够使得 工具链能依据运行时信息执行特定于应用程序和工作负载的优化。
阐明了就是想进步性能,不改业务代码。
用什么来做
PGO 须要用户参加来收集配置文件并将其反馈到构建过程中能力优化。这是一个大问题。
最合乎这个要求的,就是 pprof。最终敲定Go 团队将基于 runtime/pprof
来失去所需 profile,以此来实现 PGO。因为它合乎:采集样本开销低、多零碎兼容性强、Go 规范且被宽泛应用的基准。
也就是有 runtime/pprof
生成的 profile,就能搞 PGO 了!
反对到什么水平
PGO 第一个版本将会先反对 pprof CPU,间接读取 pprof CPU profile 文件来实现优化。预计将在 Go1.20 公布预览版本。
在 Go 工具链上,将在 go build 子命令减少 -pgo=<path>
,用于显式指定用于 PGO 构建的 profile 文件地位。
可能会有同学说,还得显式指定,太麻烦了?这 Go 团队也思考到了 …
只须要你将其 设置为:-pgo=auto
,就会主动去读取主目录下的 profile 文件,十分香!
如果不须要,那就间接 -pgo=off
就能齐全敞开 PGO。
Go1.20 实现 PGO 的预览版本,配置默认为 off,成熟后会默认为 auto。
从哪里先入手
Go 团队先会专一于 Go 编译器的开发,毕竟这是万物的开始,后续会在 cmd/go 做一些简略的反对。PGO 第一个入手的方向是:函数内联。这项被认为性价比是最高的。
将来瞻望上,还会蕴含:devirtualization(去虚拟化,一种编译器优化策略)、特定泛型函数的模板化、基本块排序和函数布局。
甚至后续会用于改良内存行为,例如:改良逃逸行为和内存调配。
看看这个 PGO 的将来瞻望,这个饼,我感觉画的又大又圆(远)…
超前实际
以下来自 @Frederic Branczyk 在《Exploring Go’s Profile-Guided Optimizations》一文中,提前应用 PGO 对 Go 官网曾经开发的函数内联进行了提前尝鲜。
步骤如下:
首先拉取已实现的 Go 源码并进行编译和导入。如下代码:
git clone https://go.googlesource.com/go
cd go
git fetch https://go.googlesource.com/go refs/changes/63/429863/3 && git checkout -b change-429863 FETCH_HEAD
cd src
./all.bash
cd ..
export PATH="$(pwd)/bin:$PATH" # or add the path to your bashrc/zshrc
进入到 PGO 的内联测试代码:
cd src/cmd/compile/internal/test/testdata/pgo/inline
做提前准备,生成 pprof cpu profile 文件:
go test -o inline_hot.test -bench=. -cpuprofile inline_hot.pprof
实现筹备动作后。咱们进行两次测试:一次不必 PGO,一次用 PGO,来进行比照。
不应用 PGO 的状况:
go test -run=none -tags=''-timeout=9m0s -gcflags="-m -m"2>&1 | grep"can inline"
./inline_hot.go:15:6: can inline D with cost 7 as: func(uint) int {return int((i + (wSize - 1)) >> lWSize) }
./inline_hot.go:19:6: can inline N with cost 20 as: func(uint) *BS {bs = &BS{...}; return bs }
...
应用 PGO 的状况:
go test -run=none -tags=''-timeout=9m0s -gcflags="-m -m -pgoprofile inline_hot.pprof"
用于如下比照:
go test -o inline_hot.test -bench=. -cpuprofile inline_hot.pprof -count=100 > without_pgo.txt
go test -o inline_hot.test -bench=. -gcflags="-pgoprofile inline_hot.pprof" -count=100 > with_pgo.txt
benchstat without_pgo.txt with_pgo.txt
name old time/op new time/op delta
A-10 960µs ± 2% 950µs ± 1% -1.05% (p=0.000 n=98+83)
从论断来看,引入 PGO 后有了 1% 的性能改良。当然,这只是一小段测试代码。不同的程序后果会不一样。
总结
PGO 是一门编译器优化技术,可能在不改业务代码的状况下,给你的应用程序带来肯定的性能晋升。在 Go PGO 中将会依靠 runtime/pprof 所生成的 profile 来实现(需革新),也算是做了一个不错的串联。
另外从需要出发点来看,这项优化感觉更多的来自开发同学的趣味优化,官网 issues 中并没有指出是因为什么用户痛点导致的要去开发这项性能。
不过后续如果遇到一些须要进一步优化的 Go 程序,PGO 将会是一个不错的抉择。毕竟不必改业务代码。
文章继续更新,能够微信搜【脑子进煎鱼了】浏览,本文 GitHub github.com/eddycjy/blog 已收录,学习 Go 语言能够看 Go 学习地图和路线,欢送 Star 催更。
Go 图书系列
- Go 语言入门系列:初探 Go 我的项目实战
- Go 语言编程之旅:深刻用 Go 做我的项目
- Go 语言设计哲学:理解 Go 的为什么和设计思考
- Go 语言进阶之旅:进一步深刻 Go 源码
举荐浏览
- Go for 循环有时候真的很坑。。。
- Go 十年了,终于想起要对立 log 库了!
- Go 只会 if err != nil?这是不对的,分享这些优雅的解决姿态给你!