如何确定最快的链接顺序?

Posted

技术标签:

【中文标题】如何确定最快的链接顺序?【英文标题】:How do I determine the fastest link order? 【发布时间】:2012-11-02 06:33:51 【问题描述】:

我有大约 50 个不同的静态库链接到我的 c++ 项目中,链接平均需要 70 秒。

我发现这次库的链接顺序发生了变化。这是可以预料的,我猜如果链接器不必在它建立的整个符号表中继续搜索一组符号。

我想我可以使用“nm”来获得静态库之间的依赖关系图。但是,这只会给我一个“正确”的链接顺序。获得最快的链接顺序会涉及哪些因素?

我感觉它与上述依赖关系图有关,方法是通过遍历尝试最小化一些数量,但我真的不确定是哪个。

任何帮助将不胜感激。

我主要使用 intel 编译器和 gcc 编译器。当我用 top 检查它时,它们似乎都在使用 GNU ld 链接器。希望这会有所帮助...

所以只是为了澄清一下我想问的问题,我已经知道如何从一组静态库中获得 1-pass ordering。我自己编写了这个脚本,但正如奥拉夫在下面的回答所暗示的那样,有一些众所周知的工具可以做到这一点。

我的问题是,我已经有两个 1-pass 链接排序,其中一个在 ~85 秒内运行,另一个在 ~70 秒内运行。很明显,我们仍然可以在 1-pass 订单中进行更多优化。

【问题讨论】:

可能是符号/未解析符号的列表,但这更像是一种预感而不是知识。旁注:您必须说明您对哪个链接器感兴趣,因为不同的链接器具有完全不同的行为(例如,ibm 对库列表进行多次迭代,直到它解决所有问题或取得进展) 我确实声明我正在使用 intel 编译器套件,所以它会是 ld(至少当我检查 top 时它似乎正在运行 ld)。我也时不时使用 gcc 编译器套件,所以这也是 ld。 只是一个粗略的想法:编写一个脚本来排列库的所有可能顺序并以编程方式测量链接时间。 @g-makulik 我有没有提到我有大约 50 个链接时间约为 70 秒的库? 完全不相关的建议,假设您这样做不仅是为了好玩,也是为了钱:将 SSD 作为工作磁盘。这应该比花时间调整链接顺序更能加快链接速度...... 【参考方案1】:

您说的是基于对象和库的顺序的一次性排序,但是如果它正在通过静态库进行搜索,则不能保证静态库中的任何内容都将按任何特定顺序进行,实际上您可以只有当你ar它时,才能通过以某种方式订购静态库来控制它。

此外,在不了解链接器如何使用静态库 (y|ies) 的情况下,可以做出的两个最佳假设是:

    它创建一个符号哈希表,引用提供或需要它们的对象;如果这是一个准确的假设,那么您可以在静态库上获得的最佳下限是填充此类哈希表并从中读取所需的时间。 它根据存档索引中给出的顺序盲目地从存档中读取。

为了尝试找到最佳链接时间的下限,请尝试将存档中的所有或部分对象链接为可重定位对象;对于子集,如果可能,识别所有实际链接的对象。

lorder 的手册页表明您可以使用 ar ts <archive> 获得相同的结果...它将为您打印有序列表。 ar 的手册页似乎表明使用 s 标志运行 ar 将自动将该最佳排序存储在存档的索引中。

另外,请注意可能存在循环依赖关系,但如果您已经搞砸了tsort,您应该已经意识到这一点。

最后,我要告诉你最后一条信息。您想要的是可以解决 NP 完全问题的东西。祝你好运。


最近一段时间,我一直在运行一些时间测试,以进行我正在处理的构建;我已将s 标志添加到我的ARFLAGS 以查看它有什么效果。

总的来说,它似乎增加了我的构建时间,但我相信有一个合乎逻辑的解释:

大多数可执行文件/共享对象不使用静态链接 它正在构建每个静态库的 PIC 和非 PIC 版本

如果我们更多地使用静态库,我们可能会看到这样做的好处。

【讨论】:

我很久没有访问这个问题了......无论如何,“大多数可执行文件不使用静态链接”是什么意思。您是指您的高管吗? 是的;我们构建中的大多数可执行文件都专门链接到动态库。【参考方案2】:

作为替代方案,为什么不尝试将库编译为共享库而不是静态库?

在我工作的地方,一个大型项目的链接时间约为 6 分钟,这仅适用于 5 个库!

我的解决方案是(对于调试版本),按字母顺序创建 .so 文件(libA.so、libB.so 等),这样每个单独的链接不会太长,最终链接要短得多,因为所有 (部分)链接之前已经完成。发布版本是以老式方式构建的,因为我的新方法存在感知“危险”。

使用这种方法,我设法将 1 个模块的编译/链接周期从 6 分钟缩短到 10 秒。

【讨论】:

【参考方案3】:

根据comparing ld to gold的信息,ld的速度受符号表大小的影响。随着符号表从处理目标文件中增长,链接步骤变得越慢。因此,如果您有两个不同的 1-pass 链接顺序,则将具有大量符号的库按该顺序稍后修复的那个应该链接得更快。您应该能够修改拓扑排序以在排序标准中包含符号计数。

【讨论】:

【参考方案4】:

过去,静态库中对象的顺序很重要。您可以使用以下方法对对象进行相应的排序:

$ 领主 *.o |排序

也许你可以对你的主要对象和库做同样的事情,例如lorder main.o test.o libsome.a libthing.a | tsort。看man lorder

【讨论】:

这听起来像是一个有趣的实用程序,但我没有安装它。你能告诉我有它的包裹吗? 我在 Debian/Ubuntu 上。 dpkg -S lorder tsort 给了我bsdmainutilscoreutils 谢谢!此外, lorder 似乎只给出了一个偏序图,所以我想它相当于我自己生成此信息的脚本。这只会给我们一个“正确”的总订单,但不一定会导致最快的总订单。 @owagh 手册页说它将库排序到最佳,链接时可以一次性加载符号。 正如手册页本身所暗示的,可能有多个这样的 1-pass 排序。我已经有两个 1-pass ordering(这就是我所说的“正确”),其中一个是 90 年代的链接,另一个是 70 年代的链接。

以上是关于如何确定最快的链接顺序?的主要内容,如果未能解决你的问题,请参考以下文章

以最快的方式重新排序字母以按字典顺序排在第一位

使用 MySQL 生成非顺序、仅限整数的 UUID 的最快方法?

Go 语言 map 如何顺序读取?

在 Pyspark 中按顺序应用多个正则表达式进行文本清理的最快方法

确定一个值是不是在 Java 中的一组值中的最快方法是啥?

最快的数据结构,按顺序返回一系列项目