编译器会优化未使用的链接文件吗?

时间:2013-10-16 19:57:06

标签: c++ performance gcc compilation linker

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

在我看来,链接是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

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

3 个答案:

答案 0 :(得分:2)

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

  1. 使用-fdata-sections-ffunction-sections标记构建对象文件(有关详细信息,请参阅 GCC manual );
  2. 使用-Wl,--gc-sections优化标记链接目标文件,该标志告诉链接器放弃未引用的部分。
  3. 注意:只有未使用的static功能会被自动删除。

    理论上,冗余符号的存在只会影响结果程序的大小。但是,我偶然发现了一些帖子,人们在删除死代码后报告性能提升1%到2%。当然,代码库必须具有相当大的尺寸才能注意到这种影响。

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

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

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

    最后,如果你真的在追赶速度,你可以检查 my other answer on some useful GCC optimization flags

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

答案 1 :(得分:1)

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

执行程序所花费的时间非常基于实际执行的代码。如果您有0,1,3,5,20,100或10000个未被调用的函数将不会产生可测量的差异。

理解为什么你的代码运行缓慢的关键(如果它运行得很慢 - 可能只是执行你要求的工作需要很长时间)就是使用一个名为profiler的工具。对于剖析器有很多选择,他们都做了很多相同的事情。在最基本的层面上,探查器会告诉您每个功能花费了多少时间,而这反过来又会告诉您在哪里集中精力。然后,指令分析器将允许您深入查看单个指令,以查看编译器已完成的操作以及在函数中花费的时间。

答案 2 :(得分:1)

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

使用分析中的数据,找到被调用最多的函数或花费最多时间的函数。这些是您应该专注于优化的功能。

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

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