跳至正文

编译优化PGO

PGO的介绍

基本概念

PGO是一个可以平均提高任何程序5%~8%性能的技术,全称是Profile Guided Optimization,它的思路其实很简单,就是编译器在对变量和函数如何放置排布和使用问题上,其实是有很大的自由权利的。

这里没有一个绝对的最优解,同一段代码,在对于不同应用场景的最优排布方式可能是不同的,传统编译方式都是以块代码进行排布和优化。

而PGO技术就是自适应编译,通过对程序增加探针进行profile,运行程序之后,再在下一次编译时根据profile结果进行结构的优化调整。

具体优化

在开始介绍PGO的过程之前,先介绍一下作为一个编译器,有哪些决定可以去做,并且会怎样影响到程序的效率。

  • Inlining – 根据函数的调用数量和频次,编译器可以做出更好的内联决定。
  • Virtual Call Speculation – 如果一个特定的继承类经常被传递给一个函数,那么它的重载函数可以被inline(内联),这会减少虚表(vtable)的查询次数。
  • Basic Block Reordering(基础结构重新排序) – 尽量将执行顺序最多的路径的代码块放在一起,这样可以提高指令缓存的命中来实现。同时将使用较少的代码挪到最底部,结合下面的“function layout”一起可以显著减少大型应用程序的工作集(一个时间间隔内使用的页面数)。
  • Size/Speed Optimization – 根据profile信息,编译器可以找到常用的函数的使用情况,可以将常用的函数进行加速,不常用的函数的代码体积减少。
  • Function Layout – 将经常被关联调用的函数放在同一个代码段落里,来减少工作集。
  • Conditional Branch Optimization – 比如if/else,如果条件经常为false,则else的代码块会放置在if代码块之前,提高指令缓存命中。

PGO的阶段

PGO分为三个阶段:

instrumental phase

file

在这个阶段链接器将cli文件传递给Bakend编译器,Bakend编译器会插入一些探针指令,并且会和可执行文件一起生成一个.pgd文件,这是一个后续其他阶段会用到的数据库文件。

training phase

第二阶段是训练阶段,在具体场景下运行程序,前面插入的探针将会记录运行时的信息,数据会被存放在.pgc文件中,每次运行都会产生一个appname!#.pgc的文件,如上图,第一次运行会产生App!1.pgc,第n次会产生App!n.pgc。

在这里训练时要注意,训练时的场景要尽量和实际使用场景相同。

PG Optimization Phase

第3部分是PG优化部分,会将pgc文件合并成pgd文件,被Bakend编译器做决策时提供数据支持,生成更高效的可执行文件。

PGO如何使用

在windows, mac, ad, ios不同平台下的编译工具和使用方式不同,但整体的步骤如前文所述,不同的工具都是这样异曲同工。

等后面实际应用到这个技术的时候再添加具体的步骤吧。

引用

https://devblogs.microsoft.com/cppblog/pogo/

发表回复

您的电子邮箱地址不会被公开。