3

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

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

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

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

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

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

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

这个答案我知道GCC和clang可以发出与C代码交错的程序集

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

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

什么时候组装更快?

为什么要在汇编中编程?

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

4

3 回答 3

3

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

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

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

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

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

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

于 2013-09-11T01:41:49.280 回答
2

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

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

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

于 2013-09-11T01:06:56.130 回答
1

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

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

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

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

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

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

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

于 2013-09-11T00:57:29.487 回答