我们好,我是煎鱼。

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 是啥,咋就让 Go 更快更猛了?

  • **检测程序。**编译器从您的源代码和编译器的特殊代码创立并链接一个检测程序。
  • **运转检测的可履行文件。**每次履行插桩代码时,插桩程序都会生成一个动态信息文件,用于终究编译。
  • **终究编译。**当您第二次编译时,动态信息文件将合并到一个摘要文件中。运用此文件中的概要信息摘要,编译器尝试优化程序中最频频的运转路径去履行。

这便是 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 是啥,咋就让 Go 更快更猛了?

看看这个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   960s  2%   950s  1%  -1.05%  (p=0.000 n=98+83)

从定论来看,引入 PGO 后有了 1% 的功用改善。当然,这只是一小段测验代码。不同的程序成果会不一样。

总结

PGO 是一门编译器优化技能,能够在不改事务代码的状况下,给你的应用程序带来一定的功用提高。在 Go PGO 中将会依托 runtime/pprof 所生成的 profile 来完结(需改造),也算是做了一个不错的串联。

别的从需求起点来看,这项优化感觉更多的来自开发同学的兴趣优化,官方 issues 中并没有指出是因为什么用户痛点导致的要去开发这项功用。

不过后续如果遇到一些需求进一步优化的 Go 程序,PGO 将会是一个不错的挑选。究竟不必改事务代码。

文章持续更新,能够微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blo… 已收录,学习 Go 言语能够看 Go 学习地图和道路,欢迎 Star 催更。

Go 图书系列

  • Go 言语入门系列:初探 Go 项目实战
  • Go 言语编程之旅:深化用 Go 做项目
  • Go 言语规划哲学:了解 Go 的为什么和规划考虑
  • Go 言语进阶之旅:进一步深化 Go 源码

引荐阅读

  • Go for 循环有时候真的很坑。。。
  • Go 十年了,总算想起要一致 log 库了!
  • Go 只会 if err != nil?这是不对的,共享这些高雅的处理姿态给你!