使用PGO构建更快、高性能的本机应用程序

我是Ankit Asthana,我是后台C++编译器的程序管理器。在今天的主题中,我想在博客中介绍一个非常酷的运行时编译器优化,名为 轮廓引导优化 (PGO)(我们队里简称为POGO或PGO)。PGO是由visualc和微软的研究小组在90年代末发起的,主要集中在安腾体系结构上。PGO最终被作为Visual StudioC/C++ 2005的一部分进行了交付,现在是一个关键的优化,为微软应用程序、应用程序提供了显著的性能提升。 其他公司 而且,在您阅读本文之后,甚至您的应用程序。

null

这个博客 提供 关于如何构建更快、更高性能的本机应用程序的指导。首先我们看一下PGO, 然后通过一个示例应用程序(NBody模拟),深入了解如何使用PGO通过几个简单的步骤来提高本机应用程序的性能。获取源代码( 附属的 ) 但是安装所需的 DirectX开发包 第一!

构建更快的本机应用程序

传统的编译器基于静态源文件执行优化。也就是说,他们分析源文件的文本,但是不使用关于潜在用户输入的知识,这些信息不是直接从源代码获得的。例如,看看下面的 伪代码:

图片[1]-使用PGO构建更快、高性能的本机应用程序-yiteyi-C++库

文本框1:示例代码段

编译时 哪支树枝折断了 函数编译器不知道“a 非虚拟化 和 开关柜扩展 编译器对函数的典型值知之甚少 *第 (防止非虚拟化优化)和 (防止交换机扩展优化)。当这些代码片段出现在不同的源模块(即不同的对象文件)中时,这些问题会进一步放大,因为传统的编译选项不会跨源模块边界进行优化。

基本的编译器和链接器模型并不是特别糟糕,但它错过了两个主要的优化机会。首先,事实并非如此 利用它可以从一起分析所有源文件中获得的信息,因为传统编译器只优化单个对象文件。其次,它不会根据应用程序的预期/概要行为进行任何优化。第一个机会可以通过使用( /德国劳埃德船级社 )编译器开关或( /LTCG公司 )执行整个程序优化的链接器开关,是能够升级应用程序的先决条件。一旦启用了整个程序优化,您就可以对应用程序进行升级了。所以,让我们现在真正进入PGO是什么。

PGO是一种运行时编译器优化,它利用从运行重要的或以性能为中心的用户场景收集的概要文件数据来构建应用程序的优化版本。PGO优化与传统的静态优化相比有一些显著的优势,因为它们基于应用程序在生产环境中可能的执行方式,从而允许优化器针对较热的代码路径(常见用户场景)优化速度,并针对较冷的代码路径(不太常见的用户场景)优化大小从而为应用程序生成更快更小的代码,从而显著提高了性能。

图片[2]-使用PGO构建更快、高性能的本机应用程序-yiteyi-C++库

图片[3]-使用PGO构建更快、高性能的本机应用程序-yiteyi-C++库

图1:PGO的三个阶段

PGO目前只能在传统桌面应用程序上使用,并且在x86和x64平台上受支持。执行PGO基本上是一个三相过程,如上图所示:

第一阶段被称为 仪表阶段 . 这个阶段需要用一组特殊的构建标志构建应用程序(即图1中的“compile”)。在此构建过程中,后端编译器将探测指令插入到生成的代码中,这些代码用于记录下一阶段的训练数据。插入的三种类型的探测是(函数入口探测、边缘探测和值探测)。函数入口探测用于收集函数被调用多少次的信息,边探测用于收集特定边被调用多少次的发生计数。使用在训练阶段从边缘探测器收集的数据,编译器可以了解在训练阶段“a>b”的频率 哪支树枝折断了 给定特定训练场景的代码片段。值探测非常特殊,因为它们用于构建值的直方图。例如,在 开关柜扩展 代码段将插入一个值探测器,用于为switch case index变量构建值的直方图 . 在训练阶段知道“i”的典型值后,编译器就可以针对常见情况进行优化,并执行优化,例如开关大小写扩展。总之,此阶段的最终结果是应用程序的插入指令版本(带有探测器)和空数据库文件(.pgd文件),用于保存下一阶段的培训数据。

第二阶段是 培训阶段 (即图1中的“运行”)。在此阶段中,用户运行应用程序的检测版本,并只执行常见的以性能为中心的用户场景。执行这些培训方案将创建(.pgc)文件,其中包含与每个用户方案相关的培训数据。这里收集的训练数据是从插入仪器阶段的探针中转储的。对这些场景的培训会产生 appname!#。 pgc文件(其中appname是正在运行的应用程序的名称,#是1+ 应用程序名# .pgc文件)。

最后一个PGO阶段 是 优化阶段 (即图1中的“重新编译”)。在此阶段,将最后一次重建应用程序,以生成应用程序的优化版本。在幕后,(.pgc)训练数据文件合并到插入指令阶段创建的空程序数据库文件(.pgd)中。然后,编译器后端使用这个程序数据库文件对生成应用程序高度优化版本的代码做出更智能的优化决策。

PGO用户中的一个常见误解是,每次构建产品时,最终用户都需要执行所有三个步骤(检测、培训和优化)。这是不正确的,优化的PGO构建可以重复构建(没有插装和训练步骤),直到源代码库与上次对应用程序进行PGO训练时有很大的差异。对于大型开发团队,理想的工作流是让一个开发人员执行PGO并将培训数据(.pgd)检查到源存储库中。团队中的其他开发人员应该能够同步他们的代码存储库,并使用培训数据文件直接构建PGO优化的构建。当计数在一段时间内过时时,应用程序将接受PGO再培训。

使用轮廓引导优化

既然我们对PGO有了一点了解,那么让我们来了解一下如何为本机应用程序启用PGO。可以使用visualstudio和Developer命令提示符对应用程序进行PGO化。在本博客中,我们将重点介绍visualstudio中的PGO’izing应用程序(Nbody模拟示例)。如果您对从命令行使用PGO很好奇,请参阅以下内容 文章 . 在VisualStudio中加载解决方案(图2)并选择产品之后 构建配置(即发布) 你们都准备好了。

图片[4]-使用PGO构建更快、高性能的本机应用程序-yiteyi-C++库

图2:VisualStudio中加载的NBody解决方案

请记住,从上一节开始,将应用程序升级是一个三步过程(工具、培训和优化)。要创建插入指令的应用程序版本,请右键单击项目(即“NBodyGravityCPU”),然后在“Profile Guided Optimization”菜单下选择“Instrument”,如下图3所示。

图片[5]-使用PGO构建更快、高性能的本机应用程序-yiteyi-C++库

图3:创建应用程序的插入指令的版本

这将导致VisualStudio生成应用程序的插入指令的版本。一旦您的应用程序的检测版本完成,我们就可以进入您的应用程序的培训阶段。使用“配置文件引导优化菜单”下的“运行检测/优化应用程序”菜单项启动检测版本的应用程序。在这个示例应用程序中,让示例运行max bodies(15360)是一个合理的培训场景,因为这是以性能为中心的稳定状态用户场景。在FPS(每秒帧数)和GFlop(这是该应用程序的关键性能指标)稳定之后(图4),您可以关闭该应用程序。关闭应用程序将完成培训阶段,并将培训数据刷新到.pgc文件中。默认情况下,.pgc文件将出现在“build configuration,即Release”目录中。例如,由于本次培训NBodyGravityCPU!1.pgc已创建。

图片[6]-使用PGO构建更快、高性能的本机应用程序-yiteyi-C++库

图4:NBody仿真应用程序

请注意,N-Body模拟示例是一个相当简单的应用程序,仅用于解释执行PGO的流程。应用程序自然会有许多复杂的训练场景。例如,用户可能有不相交的训练场景,并且在执行或时间间隔内发生。为了记录这些训练场景,最好的方法是使用 pgosweep公司 在生成插入指令的生成(从visualstudio)之后,从提升的开发人员命令提示符使用命令行工具。

图片[7]-使用PGO构建更快、高性能的本机应用程序-yiteyi-C++库

文本框2:PGO生成输出日志

执行PGO的最后一个阶段是创建应用程序的优化版本。现在从Profile Guided Optimization菜单中选择Optimization(优化)(图3)。这将触发应用程序的优化构建。如果您仔细查看构建日志,您将看到下面概述PGO活动的文本部分。

正如本博客前面提到的,在优化阶段,培训数据文件“.pgc(s)”被合并到程序数据库文件“.pgd”中,然后由后端编译器优化矩阵使用。一般来说,除了所有函数都是为速度而构建的小程序外,速度与大小的优化标准只是由给定函数的动态指令计数的%%决定的。具有高指令计数(即热)的函数是为了速度而编译的,而具有低动态指令计数(即冷)的函数是为了大小而编译的。

作为中型或大型组件的一般经验法则,应该有<5%%的方法进行编译以提高速度。构建应用程序的优化版本后,您就可以在优化的应用程序上运行您的培训场景,以测量性能增益。

此时,您应该准备好为您的本机应用程序试用PGO。试一下,然后给我们回电话。我的下一篇博客将详细介绍一些PGO的案例研究,并讨论PGO如何优化您的应用程序,敬请关注!如果你想让我们在博客上讨论一些其他与PGO相关的场景,请告诉我们 J .

NBody.zip文件

© 版权声明
THE END
喜欢就支持一下吧
点赞1 分享