VisualStudio2019中的链接器吞吐量改进

在visualstudio2019preview 2中,我们将编译器后端用于删减与二进制代码或数据无关的调试信息,并更改了PDB引擎中的某些哈希实现,以提高链接器吞吐量,这使得一些大型AAA游戏的链接时间减少了2倍多。

null

调试信息修剪

这是让编译器后端删掉任何符号记录未引用的任何用户定义类型(udt)的调试信息。这减少了保存调试信息的OBJ部分的大小,比如.debug$S保存符号的调试记录,.debug$T保存类型的调试记录(如果使用/Z7)。当使用/Zi或/Zi时,编译器会将类型的调试信息写入一个PDB文件中,该文件通常被设置为由一个目录下所有源文件的多个编译器共享。在这种情况下,我们不会从编译器生成的PDB中删除类型,但只会在底层UDT未被任何符号引用的情况下从.debug$S节中删除Su UDT记录。由于OBJs和LIBs中的调试部分较小,因此在生成PDB时,在类型合并和符号处理方面需要做的工作较少,因此它加快了链接速度,因为PDB生成通常占用大部分链接时间。链接器积极地执行内存映射文件I/O,因此较小的obj和lib可以减轻虚拟内存的压力,这对于处理大型二进制文件(如游戏开发中的二进制文件)时的链接速度至关重要。

编译器执行的类型修剪不是免费的,并且会降低编译吞吐量,特别是当编译器需要在选项/Zi或/Zi下生成PDB并且PDB服务器(mspdbsrv.exe)出于某种原因正在使用时,就像在智能构建系统中使用/MP一样,在智能构建系统中,构建驱动程序一次启动针对同一PDB文件的多个编译。由于链接通常是构建吞吐量的最大瓶颈,因此在编译中不使用mspdbsrv.exe时,我们默认启用类型修剪。我们认为这是一个很好的折衷方案,因为编译可以很容易地并行完成。在开发迭代(edit-build-debug)周期中,通常只需要重新编译一小部分源文件,链接时间在整个构建时间中占主导地位。如果要在涉及mspdbsrv.exe的情况下强制启用它,请添加编译器选项/d2prunedbinfo。

PDB中类型和全局符号哈希的改进

PDB文件存储关于类型的各种散列,以便在现有PDB文件中添加新的类型记录,以及在调试或概要文件时进行类型查询。PDB文件格式已经存在超过25年了,有很多由微软和其他公司开发的工具来处理PDB。虽然目前PDB中的类型散列处理大量类型的效率很低,但我们不想简单地切换到具有不同结构的高效散列,以保持PDB格式的兼容性。在预览2中,我们使用 XX散列 检查给定类型是否唯一。当类型合并完成后,是时候将所有内容提交到磁盘上的PDB文件中了,然后我们重新生成今天的PDB文件中使用的散列并将它们写出来。 XX散列 速度非常快。虽然它不满足加密应用程序的安全性要求,但是hash函数有一个很好的质量度量,我们在这里只使用它进行唯一性检查。

与提高类型合并吞吐量的方法类似,我们现在让链接器将公共符号的数量传递给PDB,这样PDB引擎就可以建立一个具有足够数量bucket的哈希表,从而减少哈希冲突。与类型合并一样,在提交到PDB之前,我们需要将hash的内存版本转换为磁盘格式。

在预览2中,对内部PDB散列的改进只有在从头开始生成PDB时才有效,因为从现有PDB中读取记录并重建快速内存版本的散列非常昂贵,其开销抵消了使用快速散列处理类型和符号可能带来的收益。

结果

这里是最新的Visual Studio 2017 15.9更新版本和Visual Studio 2019 Preview 2之间的比较。我们构建了一个AAA游戏标题和Google的Chrome。在下表中,带数字的前两行以秒为单位表示链接时间,最后一行以字节为单位表示链接器的总输入大小:

AAA游戏标题
链接时间(秒) VS 2017 15.9更新(基本) VS 2019预览2(差异) 基本/差异(越高越好)
/调试:完全 392.1 163.3 2.4
/调试:fastlink 72.3 31.2 2.32
输入大小(字节) 12,882,624,412 8,131,565,290 1.58
Google Chrome(x64版本)
链接时间(秒) VS 2017 15.9更新(基本) VS 2019预览2(差异) 基本/差异(越高越好)
/调试:完全 126.8 71.9 1.76
/调试:fastlink 30.3 21.5 1.41
输入大小(字节) 5,858,077,238 5,442,644,550 1.08
Google Chrome(x86调试版本)
链接时间(秒) VS 2017 15.9更新(基本) VS 2019预览2(差异) 基本/差异(越高越好)
/调试:完全 232.6 106.9 2.18
/调试:fastlink 43.8 38.8 1.13
输入大小(字节) 8,384,258,922 7,962,819,862 1.05

我们不认为在构建Chrome时链接器输入大小会像构建AAA游戏标题时那样大,因为Chrome的编译使用的是/Zi,编译器将类型写入PDB文件,而AAA游戏标题的编译使用的是/Z7,对于哪些类型的记录被写入OBJs中的.debug$T节,未引用的记录将被删除。我们还将看到,与fastlink-PDB链路时间相比,完整PDB链路时间往往从改进中获益更多。这是因为fastlinkpdb生成不涉及类型合并和全局符号的创建,因此后两个改进不适用。编译器完成的类型修剪通过减少链接器生成PDB所需的调试记录的原始工作量而使这两种链接都受益。

闭幕词

我们知道构建吞吐量对开发人员很重要,我们正在继续改进工具集的性能。在接下来的几个版本中,我们将致力于降低编译器在修剪未引用类型时的吞吐量成本,以及对各种PDB内部哈希的持续改进。如果您对我们有反馈或建议,请告知我们。我们可以通过以下评论和电子邮件联系到您( visualcpp@microsoft.com ),或者您可以通过 帮助->报告产品中的问题 在Visual Studio IDE中,或通过 开发者社区 . 你也可以在Twitter上找到我们 (@VisualC) )还有Facebook( msftvisualcpp软件 ).

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