哪个更快*在实践中*:体面的C代码,还是体面的手写汇编程序?

时间:2014-08-24 07:29:17

标签: c assembly

很久很久以前,在远处的星系中,我曾经用Delphi编写程序,然后如果我需要快速发生的事情,我会用手写的汇编程序编写这些例程。它产生的代码比编译器快得多。

但这是真的在实践中了吗?显然,手写汇编程序始终至少与编译的高级代码一样快原则。但是自那些黑暗时代以来,CPU已经走了很长一段路。现在,如果你试图优化你的汇编程序,你必须考虑指令的顺序,以便它们可以被流水线化或同时运行,分支预测的效果,以及其他一百万个东西;我怀疑它们不可能同时将它们全部放在人类RAM中。

这是否意味着一个体面的(但不是超人)程序员现在会通过编写C而不是编写手写汇编程序来生成更快的代码,至少在编写现代CPU时会这样做?

另一种可能性发生在我身上。优化是否在高级语言转换为汇编程序之前或之后发生?如果它之后......生成手写汇编程序可能会更快,然后通过编译器的优化过程吗?

最近出现的问题是我为编程挑战编写了一些代码,其中的本质是生成一个应该在Raspberry Pi上尽可能快地运行的例程。我本来可以用汇编语写它;但我的猜测是,精心编写的C会更快,即使Pi处理器在2014年并不那么复杂。

使问题更具体和具体:

  • 假设您想要编写超快速(整数)数字运算代码以在Raspberry Pi上运行。您已经编写了一些非常好的C代码,它们作为紧密循环运行来解决问题。是否值得在汇编程序中手工制作它以加快速度,或者在实践中是否会为您提供效率低下的东西?

3 个答案:

答案 0 :(得分:4)

对我而言,目前给出的答案都是正确的。答案取决于我们正在讨论的特定CPU架构。架构越复杂,手动编写高效的ASM代码就越困难。

光谱的一端是CISC核心,如x86。它们具有多个执行单元,长管道,每条指令的可变指令延迟等。在许多情况下,ASM代码看起来很干净"或者"最佳"事实上,人类并不是最适合CPU的,并且可以通过使用处理器手册黑暗角落的指令或技术来改进。编译器"知道"关于这一点,可以产生适当优化的代码。确实,在许多情况下,熟练的人可以改进发出的代码,但是使用正确的编译器和优化设置代码通常已经非常好了。此外,使用C代码,您不需要为每个新的CPU生成手动重新优化它(是的,优化通常取决于特定的CPU系列,而不仅仅是指令集),因此用C语言编写是一种方式"面向未来"你的代码。

另一方面是简单的RISC内核,例如8051(或其他简单的 8位控制器)。它们具有更简单的调度语义和更小的指令集。编译器在这里仍然做了不错的优化工作,但是手动编写一个不错的ASM代码(或修复发出的代码中的性能问题)也更加简单。

答案 1 :(得分:3)

手写汇编程序仍然比正常的C代码更快。如果你知道如何编写汇编程序,你就不会相信某些编译器会产生什么样的错误。我已经看到疯狂的东西,比如从内存中加载一个值并立即将其修改回来(最近两年前,我通常不再看汇编程序输出了)。 Torvalds对gcc lkml.org中的类似问题进行了最近的咆哮。

然而,即使手写汇编程序仍然更快,它通常不会有回报。最多,您需要在汇编程序中编写一些性能非常关键的短例程。剩下的最好留在C中以便携带。

答案 2 :(得分:2)

在实践中,使用优化编译器编译的正常C代码比汇编程序代码更快,特别是一旦您需要多于几十个源代码行。

当然,您需要一个优秀的,最新的优化编译器。我们欢迎您针对您的特定硬件(和软件)系统进行最近GCC的交叉编译。因此,请使用-O2 -mtune=native等选项(至少在x86上)

重点是最近的处理器需要,即使对于简单的"指令集,复杂的指令调度和寄存器分配,以及编译器都非常好。对于几百行,您不会耐心地编译汇编程序代码,而不是优秀的编译器可以发出它。

当然,可能有例外(您需要进行基准测试)。添加一些汇编程序代码的最经济有效的方法可能是在某些C函数中使用一些asm指令GCCextended asm facility非常好。