【问题标题】:How can I prove or disprove the efficiency of compilation?我如何证明或反驳编译的效率?
【发布时间】:2013-09-14 20:55:10
【问题描述】:

这是一个不寻常的问题,但我确实希望有一个明确的答案。

关于编译器生成代码的效率,特别是指令的数量,我们办公室一直存在争论。我们为几乎没有循环的低功耗嵌入式系统编写代码。因此,发出的指令数量与功耗成正比。

我们的大部分代码看起来像这样(注意,没有动态内存分配,没有系统调用,很少的函数调用,很少的循环)。

foo += 3 * (77 + bar);
if (baz > 18 - qux)
    bar -= 19 + 7 >> spam;

我可以用-O3编译上面的sn-p并读取程序集,但是我自己写不出来。

我想证明或反驳的说法是,与手写汇编代码相比,编译器生成的代码“胖”2-4 倍(因此消耗的功率是手写汇编代码的 2-4 倍)。

我对您有经验的任何编译器都感兴趣。

来自this answer 我知道 GCC 和 clang 可以发出与 C 代码交错的程序集

gcc -g -c -Wa,-alh foo.cc

这些答案提供了坚实的基础:

When is assembly faster?

Why do you program in assembly?

如何衡量编译器生成代码的效率?

【问题讨论】:

  • 我认为您必须证明“指令数”==“功耗”。当你的处理器“什么都不做”时它会做什么?
  • 简单答案:基准测试。你可以整天争论速度或大小的优点。但在一天结束时,看到实际结果会让人感到满足。构建针对速度或大小优化的 exe,然后在机器上进行测试。使用正在讨论的方法再次构建它,然后根据第一种方法对其进行测试,依此类推。与简单的辩论相比,您将获得更明确的结果。
  • 另外,如果您真的关心代码大小,最好将 gcc 与 -Os 而非 -O3 进行比较:gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
  • @ryker 我认为这并不能真正说明 OP 的问题,因为他说他不能手动编写汇编代码 - 这是他需要进行基准测试的方法。跨度>
  • @JohnFaulkner 没错。一个人可以写出糟糕的汇编程序并说“看看编译器有多好”,但这是最糟糕的稻草人论点:)

标签: c assembly


【解决方案1】:

如果不能击败编译器,手动汇编至少可以匹配,因为至少,您可以从编译器生成的汇编代码开始,并对其进行调整以使其更好。要真正做好工作,需要了解 CPU 架构(流水线、功能单元、内存层次结构、乱序调度单元等),以便对每条指令进行调度,以获得最大效率。

要考虑的另一件事是指令的数量不一定与性能成正比,无论是速度还是功率(参见 Hennessey 和 Patterson 的 Computer Architecture: A Quantitative Approach)。基本上,除了指令数量(和时钟速率)之外,您还必须查看每条指令需要多少时钟周期才能知道需要多长时间。要知道会消耗多少能量,您还需要知道每条指令需要多少能量。

CPU 执行每条指令的方式会影响执行所需的周期数。例如,您的代码序列有一个 >> 运算符。编译器可能会将其转换为单个 ASR 指令,但在不了解架构的情况下,无法确定它可能需要多少个时钟周期——一些架构可以在一个周期内进行任意移位,而另一些架构则需要一个周期每个位移位。

内存访问也会影响循环次数和功耗。当有太多变量要存储在寄存器中时,其中一些必须存储在内存中。如果您正在访问片外内存并且具有相当高的 CPU 时钟频率,那么内存总线可能会非常耗电。避免读取和写入内存的更长指令序列(例如,通过两次计算相同的结果)可能会更便宜。

正如其他几个人所建议的那样,没有什么可以替代基准测试。假设您使用的是具有恒定输入电压的基于微控制器的系统,您最好的办法是使用每组替代代码测量系统的电流消耗,并查看哪个最好(一种方法是使用电流探头和数字存储示波器)。

即使你总能写出比编译器更好的汇编程序,开发时间和可维护性也是有代价的。在The Mythical Man Month Brooks 估计,当许多(如果不是大多数)程序员使用汇编程序编写代码时,工作量会增加 3-5 倍。除非你的代码真的很小,否则你最好只对装配中最关键的部分进行编码。尽管如此,编写程序集的人应该能够通过比较运行代码和运行代码来证明他们的(更昂贵的)代码是值得的。

【讨论】:

    【解决方案2】:

    如果问题是“我如何衡量编译器生成代码的效率”(您的实际问题),答案是“取决于情况”。这取决于您如何定义“效率”。大多数情况下,编译器旨在优化速度。当您更改优化级别 (-O1, -O2, -O3) 时,编译器将花费更多时间寻找“可以做的更聪明的事情,以使其更快一点”。这可能涉及循环展开、执行顺序、寄存器的使用以及许多其他事情。

    您的“效率”标准似乎不是编译器设计的标准:您说您想要“最少的周期”,因为您认为 == 最低功耗。但是,我认为“最快的执行”==“处理器可以再次进入待机模式的最短时间”。除非您认为处理器在“唤醒”模式下的功耗会随着指令的执行而发生显着变化,否则我认为可以肯定地说最快执行 == 最短唤醒时间 == 最低功耗。

    在这种情况下,“胖代码”无关紧要 - 它只是恢复速度。另请注意,并非所有指令都采用相同数量的时钟周期(尽管公平地说,这取决于处理器)。

    【讨论】:

      【解决方案3】:

      编辑,好吧,这很有趣...

      那些笼统地说编译器优于人类的人,实际上是没有检查过的人。编译器可以创建的任何东西都是人类可以创建的。但是编译器不能总是创建人类可以创建的代码。就是这么简单。对于从几行到几十行或更大的项目,手动修复编译器所做的优化变得越来越容易。编译器和目标有助于缩小这一差距,但总会有受过教育的人能够达到或超过编译器的输出。

      我想证明或反驳的说法是编译器生成 2-4X“胖”的代码(因此消耗 2-4X 倍 power) 与手写汇编代码相比。

      除非您将“更胖”定义为使用那么多功率。二进制文件的大小与功耗无关。如果整个问题/项目与功耗有关,编译器将不会考虑您选择的 bios 设置(假设您在谈论 pcs)、视频卡、硬盘、显示器、鼠标、键盘等。除了处理器,这只是方程式的一个(相对较小的)部分。即使它确实会有人制作一个只会使您的代码高效的编译器,他们也不能也不会为地球上的每个系统调整编译器。不会发生

      如果您正在谈论的是一个非常受控环境的手机,则应用程序可能会进行调整以节省电量,但​​编译器不是这方面的主人,而是用户,编译器完成了部分工作,其余部分由人手完成由程序员调整。

      I can compile the above snippet with -O3 and read the assembly, but I couldn't write it myself.
      

      如果你带着这种态度去做这件事,那么你就自然而然地失败了。是的,您可以遇到或击败编译器,期间。这是信心、意志力和时间/努力的问题。那句话意味着你还没有真正研究过这个问题,这就是你问你所问问题的原因。花点时间,做更多的研究,在 stackoverflow 上提出详细的问题(不是像这样的开放式问题),随着时间的推移,您将了解编译器做什么和不做什么以及为什么,特别是为什么它们不完美(对于任何一个或许多定义该意见的统治者)。这个问题完全是关于意见的,将引发激烈的战争,这样的问题将被关闭并最终从本网站上删除。而是编写、编译和发布代码段,并询问“为什么编译器会产生这个输出,为什么不把它变成 [this]?”的问题。这类问题更有可能获得真正的答案并留在这里供其他人学习。

      【讨论】:

      • 我同意你所说的大部分内容——直到你到达“......并最终消灭人类”。我想你在那儿有点得意忘形了。只需切断该死的东西的电源并向他们展示谁是老板。是时候在蒙大拿州的小木屋了。
      • 我不同意。虽然您当然可以找到人类可以做得更好的孤立案例,但总的来说,一个好的优化编译器将大大胜过人类汇编程序员。并且要更加更可靠地启动。我会说它非常“确定”。 (而且我已经编写了数万行汇编代码,可能还有一百万行 HLL 代码。)
      • 我为你感到高兴...我已经编写了相当数量的代码并检查了数百万行编译输出。许多编译器免费且昂贵,适用于许多目标。合适的人可以达到或超过编译器(我们有成千上万的人),普通人不会。无论好坏,让编译器完成工作并仅在您真正需要的地方修复它通常是一个好主意。
      • 在您回答所有编辑之后,您肯定会得到我的投票。即使,正如你所说,这个问题 - 主要是“基于意见” - 可能会被关闭/删除,所以你将再次失去代表。并不是说你太饿了以至于你会注意到。不过有趣的讨论。
      • rep 对我来说并不重要,不是因为我已经达到的水平,而是因为这不是这个网站真正关于 IMO 的内容。这是关于教育的。向前支付。通过指导其他人来回报你的导师......你马上就获得了我的 +1。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 1970-01-01
      • 1970-01-01
      • 2021-06-01
      • 2015-12-25
      • 1970-01-01
      相关资源
      最近更新 更多