【问题标题】:Are multiple compilation units still worthwhile when (execution time) >>> (compile time)?当(执行时间)>>>(编译时间)时,多个编译单元仍然值得吗?
【发布时间】:2012-07-26 06:17:26
【问题描述】:

根据我的理解,创建具有多个编译单元的程序的主要好处是组件的可重用性和在合并小的更改时更短的编译时间。

我还认为(可能是错误的)与此相关的惩罚是,在它们自己的编译单元中定义的函数不能声明为“内联”。
[我认识到这个关键字实际上并没有强制编译器内联扩展函数,但我的理解是它为编译器提供了更大的优化灵活性,因此值得尽可能包括在内。]

到目前为止一切顺利吗?

我真正的问题是,当程序解决复杂的建模问题时,成本/收益分析是否仍然有利于多个编译单元,并且需要在集群上迭代其主循环数月才能生成有用的输出。

假设一个多编译单元程序需要几分钟来编译,而重新配置为单个编译单元的相同程序需要几个小时来编译...如果单个编译单元将所有函数声明为内联并因此呈现更多优化机会,我认为执行时间可以减少几个百分点似乎是合理的,而不是弥补额外的编译时间。

对于这种情况是否有很好的经验法则,还是严重依赖于情况?

【问题讨论】:

  • 现在在每个人都发送垃圾邮件“过早优化”之前。我会说是的,确实有可能从将所有内容塞进一个编译单元中获得超过几个百分比的收益。我已经完成并亲眼目睹了。
  • 对于性能问题,数据胜过争论。测试和测量。
  • 很容易低估在编写代码时点击“编译”的次数,即使您的更改微不足道。

标签: c++ compilationunit


【解决方案1】:

正如其他人已经说过的,将程序分解为不同的编译单元的主要好处是可读性。 更短的编译时间在某种程度上是这个想法的一个很好的副作用。

如果您关心内联,可以求助于Link Time Code Generation and Link-Time Optimization。将程序分解为编译单元和 LTO 看起来是理想的解决方案,尽管尚不清楚当函数的完整定义可用时编译器执行的优化类型是否可以由 LTO 执行。 例如,我不知道 LTO 是否可以支持 C++ 中的返回值优化,因为它是在高级抽象上完成的。需要进行性能测试。 (编辑:即使在没有 LTO 和此类高级技巧的情况下也执行 RVO,至少在 gcc 和 clang [我尝试过] 上。很可能,这种优化是通过更改函数的 ABI 来执行的,它需要一个指向必须在函数中构造和返回的对象的“隐藏指针”。)

第三种可能值得研究的解决方案是使用类似sqlite amalgamation 的方法,将不同的编译单元放入一个巨大的 .c 文件中。 不过,看起来需要相当繁重的用户制造基础设施。

【讨论】:

    【解决方案2】:

    一些编译器/链接器能够自动内联函数,即使它们在一个编译单元中定义并在另一个编译单元中使用。微软的链接器当然可以做到这一点。

    对我来说,将代码拆分为单独的编译单元的主要好处是代码的整体组织,我总是根据这个事实而不是您的考虑来做出决定。也不要忘记,大型程序通常一次由多个人完成。显然,单独的编译单元是一个很大的好处。

    简而言之,我认为这在很大程度上取决于情况。不过,我认为您的情况很少见。

    【讨论】:

    • 应该补充一点,你对 inline 关键字的描述是错误的。编译器可以内联未声明为内联的函数,也可能无法内联声明为内联的函数。 inline 关键字的真正含义是避免在头文件中定义函数时出现多次定义错误。它告诉编译器/链接器它可能会看到这个函数被定义了好几次,如果是这样就不是错误。
    【解决方案3】:

    不要忘记 80-20 规则。 80% 的程序运行时间花费在 20% 的代码中。也许您可以将这 20% 放在一个编译单元中,而其余的则井井有条?

    关于源代码组织,您仍然可以将算法放入标头(作为模板或作为内联函数),然后从它们中组合源代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-29
      • 1970-01-01
      • 1970-01-01
      • 2010-10-25
      • 2012-07-04
      • 1970-01-01
      • 2013-08-15
      相关资源
      最近更新 更多