3

我正在编写一些速度非常重要的代码。我只是在编写测​​试用例后开始制作主要的二进制文件。对于我的测试运行器,我只是将所有内容提供给带有通配符的链接器。(如下)

在我看来,链接是 C++ 将事物粘合在一起的阶段 - 填充对函数的引用等并将所有内容放在一起以形成二进制文件。

# Do the linking for the test binary
$(BIN)test_cases: $(TEST)TestRunner.o
    $(CC) $(TEST)*.o $(SRC)*.o $(CPPUNITLINKS) $(MAINLINKS) -o $(BIN)test_cases

我的问题是,鉴于我希望以任何可能的方式加速我的程序,我会更好地链接“主”二进制文件所需的最少文件吗?这会导致更精简的可执行文件或更快的程序,还是编译器已经丢弃了它不需要的任何东西?

4

3 回答 3

2

当您将目标文件链接到程序中时,链接器将解析程序中任何未解析的符号。如果你想消除死代码(默认情况下 GCC 不这样做),你可以执行以下操作:

  1. -fdata-sections使用和-ffunction-sections标志构建目标文件(有关更多信息,请参阅GCC 手册);
  2. 使用优化标志链接目标文件,该-Wl,--gc-sections标志告诉链接器丢弃未引用的部分。

注意:只有未使用static的函数会被自动删除。

理论上冗余符号的存在只会影响结果程序的大小。但是,我偶然发现了一些帖子,其中人们报告在剥离死代码后性能提高了 1% 到 2%。当然,代码库必须足够大才能注意到这种效果。

请注意,有时这种方法可能无法正常工作。例如,我在某些系统上遇到过崩溃或链接问题,可能是由于此功能的实现中存在错误。

此外,不要认为这些标志在每种情况下都能提高性能和/或大小。通过标志打开此功能并且默认情况下不存在,这是有充分理由的。事实上,有时链接器可能会创建更大的对象和可执行文件和/或更慢的代码,更不用说您肯定也会遇到调试问题。

总而言之,使用此功能时要非常谨慎,并始终按照其他答案中的建议在前后分析您的代码。

最后,如果您真的追求速度,您可以查看我在一些有用的 GCC 优化标志上的其他答案

最后但并非最不重要的一点是,所谓的链接时间优化(LTO) 是一个巨大的新概念,它已被引入 GCC,并且最近变得或多或少地稳定使用。相应的标志是-lto,有关更多信息,请参见此处此处。虽然现在它是可用的,但在某些平台上并不是所有东西都是闪亮的。例如,在 Windows 上,GCC 端口 MinGW/MinGW-w64 仍在努力使 LTO 支持生产质量。

于 2013-10-16T20:14:06.863 回答
1

只要文件不是很大,用于制作二进制文件的文件数量对执行时间的影响很小。当然,如果构建程序所需的时间是您想要改进的,那么减少目标文件的数量可能是实现更快构建时间的一个步骤。

执行程序所需的时间很大程度上取决于实际执行的代码。如果您有 0、1、3、5、20、100 或 10000 个未被调用的函数,则不会产生可衡量的差异。

理解为什么你的代码运行缓慢的关键(如果它确实运行缓慢 - 可能只是执行你要求的工作需要很长时间)是使用一个称为分析器的工具。探查器有很多选项,它们在很大程度上都做同样的事情。在最基本的层面上,分析器会告诉您在每个功能上花费了多少时间,而这反过来会告诉您将精力集中在哪里。然后,指令分析器将允许您深入到各个指令,以查看编译器做了什么以及在函数中花费的时间。

于 2013-10-16T20:10:24.640 回答
1

加速任何程序的第一步是 PROFILE。一个好的配置文件将显示程序中每个函数使用的时间量。

使用来自分析的数据,找到调用次数最多的函数或花费最多时间的函数。这些是您应该集中精力优化的功能。

优化时,按需求优化(例如删除一些),然后按设计(选择不同的算法,删除函数),然后通过编码(重写更高效的代码,例如减少分支和跳转),最后通过使用平台特定代码(专门的组装说明)。编码优化的捷径是告诉编译器使用最大优化来提高速度。

如果要使用动态库或共享库,请将常用函数放入同一个库中。这允许操作系统仅根据需要加载较少的库。

于 2013-10-16T20:20:38.503 回答