Profile-guided optimization

传统的C++代码编译链接器生成可执行文件,并没有考虑到代码实际执行的情况。比如代码中一个switch表达式,某条分支的逻辑在实际环境中执行的次数占绝大数,而编译链接器无从得知这些信息,也就没办法做出优化。Profile Guided Optimization (PGO),也叫做“按配置优化”,正是用来解决这个问题的。Visual Studio C/C++ 2005就开始提供了PGO功能,这些年一直在发展。很多Windows平台上的客户端程序,比如Firefox浏览器就使用了这种技术来优化性能。

PGO介绍

上图就是Visual Studio C/C++编译链接器实施PGO的3个阶段:

  • 检测阶段。这个阶段编译链接器插入了一些收集程序运行时性能数据的指令到生成的可执行程序中,比如在每个函数的入口点插入指令记录这个函数的调用者和次数。因为这些额外的收集性能数据的指令,这个阶段编译出的可执行程序比正常情况下编译出的可执行程序体积会大一些。
  • 训练阶段。检测阶段生成了可执行程序,然后训练阶段就是运行这个程序,操作一些场景,得到一些性能数据。
  • 优化阶段。根据训练阶段得到的数据,编译链接器重新生成优化后的可执行程序。

根据PGO训练阶段得到的函数之间调用关系和调用次数等性能数据,可以针对性的做很多优化:

  • 函数内联。比如A函数频繁的调用B函数,B函数也相对比较小,那么可以把B函数内联到A函数中。
  • 虚函数调用推测。C++中调用虚函数是运行时确定的。基于性能数据可以优化一些直接调用。
  • 寄存器分配。可以优化寄存器的分配。
  • 大小/速度优化。对于调用频繁的函数,速度优化为优先。对于调用不频繁的函数,大小优化为优先。
  • 函数布局。根据函数之间的调用关系,相关的函数的指令生成到可执行文件相同的section中。
  • 条件分支优化。比如在switch语句中,某个值的出现概率大大超过其他值。那么可以把这个值所在的分支从switch语句中抽取出来做特殊优化处理。
  • 死代码分离。将很少调用的代码跟频繁调用的代码分开,它们生成的指令放到可执行文件不同的section中。

事实上,PGO也提高了CPU cache的命中率和分支预测的成功率。

Visual Studio中使用PGO

除了community版本,Visual Studio已经把PGO功能集成到工程右键菜单里面,使用起来非常方便。

如上图所示,选择工程,右键菜单->按配置优化,选择“检测”就可以编译出检测阶段的可执行程序,同时在Release目录下面会生成pgo_demo.pgd的文件。后缀为pgd的文件里面会合并训练阶段的程序运行的性能数据。
然后再选择“运行检测/优化后的应用程序”,就开始训练阶段。退出程序之后会生成一个pgo_demo!1.pgc。后缀为pgc文件包含了这次程序运行的性能数据。可以运行程序,进行多次训练,每次运行都会生成一个数字编号自增的pgc文件。

最后选择“优化”菜单,pgc文件里面的信息就会被合并到pgd文件中。pgd文件中的数据我们可以通过vs安装目录下的pgomgr.exe查看。
我们通过”C:\Program Files\Microsoft Visual Studio 14.0\VC\bin\pgomgr.exe” /summary pgo_demo.pgd > pgo.txt 把pgd里面的信息输出到pgo.txt文件里面,其内容如下图:

里面显示了每个函数的调用情况。

另外,从Visual Studio编译输出窗口可以看到如下图信息,描述了所实施的优化:

命令行的方式使用PGO

虽然Visual Studio菜单已经集成了PGO,但是实施PGO需要人操作UI。因此VS还提供了命令行的方式使用PGO,方便我们程序自动化的实施PGO。

另外Visual Studio的PGO也在不停进化,可能不同版本的PGO使用的编译开关不相同,本文是以Visual Studio 2015来介绍的。

  • 检测阶段,编译代码加上/GL,链接加上/LTCG和/GENPROFILE开关
  • 优化阶段,链接加上/LTCG和/USEPROFILE开关

Chrome浏览器中使用PGO

Windows平台上,64位的Chrome已经在53版本使用上了PGO,32位的Chrome已经在54版本使用上了PGO。根据Chromim Blog上面的Making Chrome on Windows faster with PGO文章介绍,应用了PGO之后,新标签也加载的速度提高了14.8%,页面加载的速度提高了5.9%,浏览器启动时间提高了16.8%。

参考

  • Profile-Guided Optimizations https://msdn.microsoft.com/en-us/library/e7k32f4k.aspx
  • Build faster and high performing native applications using PGO https://blogs.msdn.microsoft.com/vcblog/2013/04/04/build-faster-and-high-performing-native-applications-using-pgo/
  • Making Chrome on Windows faster with PGO https://blog.chromium.org/2016/10/making-chrome-on-windows-faster-with-pgo.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注