如何证明或反驳编译的效率?

时间:2013-09-11 00:38:18

标签: c assembly

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

我们的办公室长期以来一直在讨论编译器如何有效地生成代码,特别是指令数量。我们为低功耗嵌入式系统编写代码,几乎没有循环。因此,发出的指令数与消耗的功率成正比。

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

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

我可以使用-O3编译上面的代码段并阅读程序集,但我自己无法编写。

我想证明或反驳的主张是,与手写汇编代码相比,编译器会生成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?

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

3 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:2)

如果没有击败编译器,手部组件总是至少匹配,因为至少,您可以从编译器生成的汇编代码开始并调整它以使其更好。要真正做好,您需要了解CPU架构(管道,功能单元,内存层次结构,无序调度单元等),以便您可以安排每条指令以实现最高效率。

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

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

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

正如其他几位人士所说,基准测试无可替代。假设您正在使用具有恒定输入电压的基于微控制器的系统,您最好的选择是使用每组替代代码来测量系统的电流消耗,并查看哪种方法最佳(一种方式是使用电流探头和数字存储示波器)。

即使您总是可以编写比编译器更好的汇编程序,但开发时间和可维护性也会降低成本。在The Mythical Man Month布鲁克斯估计,当许多(如果不是大多数)程序员在汇编程序中编写代码时,他们的工作量增加了3-5倍。除非您的代码非常小,否则最好只编写汇编中最关键的部分。即便如此,编写程序集的人应该能够通过比较运行代码与运行代码来证明他们的(更昂贵的)代码是值得的。

答案 2 :(得分:1)

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

那些使编译器胜过人类的一揽子声明的人是那些没有真正检查过的人。编译器可以创建人类可以创建的任何东西。但是编译器不能总是创建人类可以创建的代码。就这么简单。对于从几行到几十行或更大行的任何项目,可以更轻松,更轻松地手动修复编译器所做的优化。编译器和目标帮助弥补了这一差距,但总会有受过教育的人能够达到或超过编译器输出。

  

我想证明或反驳的主张是编译器产生的   代码是2-4X“更胖”(因此消耗2-4倍   与手写汇编代码相比。

除非你定义“更胖”意味着使用那么大的力量。二进制的大小和功耗无关。如果整个问题/项目与功耗有关,编译器将不会考虑您选择的BIOS设置(假设您正在谈论PC),视频卡,硬盘,显示器,鼠标,键盘等。除了处理器之外,只有一个(相对较小)的等式部分。即使它确实会有人制作一个只能使你的代码有效的编译器,他们也不能为这个星球上的每个系统调整编译器。不会发生的。

如果你正在谈论一个非常受控环境的手机应用程序可能会调整以节省电力,但编译器不是那个主人,它是用户,编译器做其中的一部分剩下的就是手由程序员调整。

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

如果你以这种态度进入这个态度,那么你自动失败了。是的,你可以遇到或击败编译器,期间。这是一个充满信心,力量和时间/精力的问题。那句话意味着你没有真正研究过这个问题,这就是为什么你要问的问题。花一些时间,做一些更多的研究,在stackoverflow上问一些详细的问题(不是像这样的开放式问题),随着时间的推移,你会理解编译器做什么和不做什么以及为什么,特别是为什么它们不完美(对于任何一个)或许多统治者,通过这些统治者来定义这种观点)。这个问题完全是关于意见,并将引发火焰战争,并将关闭并最终从该网站中删除。而是编写和编译并发布代码段,并询问有关“为什么编译器会产生此输出,为什么不将它改为[this]?”这些问题有更好的机会获得真正的答案,留在这里供其他人学习。