【问题标题】:Size optimization options尺寸优化选项
【发布时间】:2015-10-13 15:10:05
【问题描述】:

我正在尝试整理一个嵌入式项目,其中开发人员选择将所有 h 和 c 文件包含到一个 c 文件中,然后他们可以使用 -whole-program 选项编译该文件以获得良好的大小优化.

我讨厌这个,并决心把它变成一个传统的程序,只使用 LTO 来达到同样的效果。

开发套件中包含的版本是; aps-gcc (GCC) 4.7.3 20130524 (Cortus) GNU ld (GNU Binutils) 2.22

一个 .o 文件 .text 为 0x1c7ac,分成 67 个 .o 文件 .text 出来为 0x2f73c,我添加了 LTO 内容并将其减少到 0x20a44,很好但还远远不够。

我已经尝试过 --gc-sections 并使用链接器插件选项,但他们没有进一步改进。

任何建议,我是否看到了 LTO 的正确改进?

【问题讨论】:

  • 升级工具链版本是一种选择吗?
  • 我打算提出同样的建议,IIRC 更高版本的 GCC 在 LTO 领域做出了显着改进。此外,使用配置文件反馈来进一步减小可执行文件大小。当然,用-Os 编译。
  • 为什么不制作一个在编译时创建单个大文件的工具,在为最终生产进行编译时。这就是 sqlite 团队所做的
  • 正在努力升级,对于免费工具来说非常困难,宣传册表明 4.9.1 即将推出。
  • 我有一个想法,我可以运行双重构建,发布编译包含所有内容的东西,独立调试构建对象。到目前为止,当我破坏代码时,我因目标内存不足而感到困惑,所以我无法在重构时继续测试。这一切都因为代码继续作为一个巨大的整体块的开发而变得困难,每个单独的 C 文件都会看到之前解析的那些文件的包含,因此各个文件的编译方式不同或根本不独立。

标签: c gcc lto


【解决方案1】:

要使 LTO 完美运行,您需要在链接阶段提供与编译阶段相同的信息和优化算法。 GNU 工具无法做到这一点,我相信这实际上是创建 LLVM/Clang 的动机之一。

如果您想详细检查差异,我建议您为每个选项生成一个 Map 文件(ld 选项 -Map <filename>),并查看是否有未内联的函数或更大。您可以通过将函数的定义移动到头文件中并将其定义为extern inline,从而有效地将其转换为宏(这是一个 GNU 扩展)来手动解决内联的缺失。

较大的函数可能不会受到持续传播的影响,我认为您对此无能为力。您可以通过仔细声明constleafnoreturnpurereturns_nonnull等函数属性来进行一些改进。这些有效地保证函数将以特定方式运行,如果使用单个编译单元,编译器可能会检测到该方式,并允许进行额外的优化。

相比之下,Clang 可以将你的目标代码编译成一种特殊的字节码(LLVM 代表 Low Level Virtual Machine,就像 JVM 是 Java 虚拟机,并且运行字节码)然后可以在链接时执行这个字节码的优化(或者实际上是运行时,这很酷)。由于无论你是否使用 LTO,这个字节码都会被优化,并且优化算法在编译器和链接器之间是通用的,理论上无论你是否使用 LTO,Clang/LLVM 都应该给出完全相同的结果。

不幸的是,现在 C 后端已从 LLVM 中删除,我不知道有任何方法可以将 LLVM LTO 功能用于您所针对的自定义 CPU。

【讨论】:

    【解决方案2】:

    在我看来,之前开发者选择的方法是正确的。该方法为编译器提供了最多的信息,从而为您提供了执行所需优化的最多机会。这是一种糟糕的编译方式(任何更改都需要编译整个项目),因此将其标记为一个选项是个好主意。

    当然,您必须针对这样的构建运行所有集成测试,但这应该是微不足道的。除了编译时间(这不应该成为问题,因为您不需要一直以这种方式构建......仅用于集成测试)之外,所选方法的缺点是什么。

    【讨论】:

      猜你喜欢
      • 2010-12-28
      • 1970-01-01
      • 1970-01-01
      • 2012-10-28
      • 2011-05-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 2021-12-23
      相关资源
      最近更新 更多