传统编译 vs PGO 编译
【摘要】 PGO = Profile-Guided Optimization,剖面引导优化,也叫"反馈驱动优化"。让编译器先看程序真实怎么跑,再决定怎么优化。 传统编译 vs PGO 编译传统编译:编译器只能靠静态分析猜。比如遇到一个 if-else,它不知道哪个分支更常走,只能凭经验猜,猜错了代码布局就不理想。PGO 编译:分两步走——采数:先编译一个带计数功能的版本,跑一遍典型业务负载,记录下"哪...
PGO = Profile-Guided Optimization,剖面引导优化,也叫"反馈驱动优化"。让编译器先看程序真实怎么跑,再决定怎么优化。
传统编译 vs PGO 编译
传统编译:编译器只能靠静态分析猜。比如遇到一个 if-else,它不知道哪个分支更常走,只能凭经验猜,猜错了代码布局就不理想。
PGO 编译:分两步走——
- 采数:先编译一个带计数功能的版本,跑一遍典型业务负载,记录下"哪个函数最热"“哪个分支走得最多”“哪个循环迭代多少次”。
- 重编译:把这份 profile 数据喂给编译器,编译器据此做决策:
- 把热函数排在一起,提高指令缓存命中
- 热分支直连,冷分支挪远
- 对热函数做更激进的优化(如内联、向量化)
- 寄存器分配优先照顾热路径
和 BOLT 的关系
两者思路一样,都是"用运行时数据指导优化",但作用层次不同:
| PGO | BOLT | |
|---|---|---|
| 操作对象 | 源码/编译中间表示 | 已编译的二进制 |
| 需要源码 | 需要 | 不需要 |
| 介入时机 | 编译期 | 链接之后 |
| 典型提升 | 5-15% | 在 PGO 基础上再 5-10% |
所以它们可以叠加:先 PGO 编译,再用 BOLT 对产物二次重排。很多大型项目(如 MySQL、MongoDB、LLVM 自身)就是这么做的。
PGO 的两种采数方式
- 插桩式 PGO:编译时加
-fprofile-generate,跑负载生成.gcda计数文件,再用-fprofile-use重编译。精度高,但二进制有开销。 - 采样式 PGO:用
perf等工具采样,生成 profile,再用-fprofile-use重编译。开销低,精度略差,但适合生产环境。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)