【问题标题】:How is Assembly faster than HLL's?组装比 HLL 快多少?
【发布时间】:2012-03-03 14:14:02
【问题描述】:

如果它们都被编译成机器代码,汇编语言比高级语言更快吗?我可以理解内联汇编比周围的 HLL 更快,但是对于整个汇编程序与 C 相比,两者都被编译为机器代码并且应该以相同的速度运行。

【问题讨论】:

  • 您的问题包含不正确的假设。并非所有的手写汇编代码都比编译器生成的等效代码更快。
  • 还有,为什么你明白内联汇编更快,而整个程序却不行?

标签: assembly


【解决方案1】:

您问题的前提不一定正确。现代桌面 CPU 非常复杂且高度流水线化。因此,CPU 的性能特征可能并不直观。编写编译器的人会花费大量时间在编译器后端专门针对处理器架构进行研究和实施优化。

除非您确切地知道自己在做什么(几乎从来不是这样),否则一个好的现代编译器将在无需人工干预的情况下创建高度优化的代码。直接编写汇编的原因是编译器无法创建最优化的代码,或者作为操作系统内核的一部分。

【讨论】:

    【解决方案2】:

    高级语言并不比汇编语言快。好的编译器将 HLL 程序翻译成快速的机器指令序列。优秀的汇编程序员也会做同样的事情。从性能的角度来看,结果是无法区分的。

    高级语言旨在使编程更容易和更快,而不是使程序更快。

    【讨论】:

      【解决方案3】:

      处理器内核实际直接执行机器代码指令的日子已经一去不复返了。它们被翻译为微操作、类似 RISC 的指令,旨在保持现代超标量、无序执行能力的核心与多个执行单元运行。其实际实现是制造秘密,并且随着每一代 cpu 架构的变化而变化。具有这种行为的第一个标志性处理器之一是 1989 年推出的 Intel 486。

      机器码指令的效率很大程度上受它之前和之后的指令的影响。其细节无法再由人类监督。它需要一台机器。你旁边的那个,执行编译器的代码生成器阶段。如果您使用带有即时编译器的 VM 语言,或者在您客户的机器上。一种可以处理内核之间细微架构差异的执行模型。

      【讨论】:

        【解决方案4】:

        用汇编语言编写的程序过去更快,当时 PC 又慢又简单,编译器也不聪明。

        我曾经在 1980 年代编写过很多程序集,因为您必须才能使用我们当时拥有的 PC。它是 MHz,而不是 GHz。

        现在,我有时只是查看编译器生成的代码,发现它至少与我可以编写的代码一样好,但更容易生成。通常它比我能做的要好得多。

        这样做的一个影响是,Microsoft 已为其 x64 编译器删除了内联汇编,部分原因是大多数使用汇编进行优化的尝试只是扰乱了优化器,使其对周围代码产生的优化结果不太理想。净亏损!

        【讨论】:

          【解决方案5】:

          就像这里的许多人所说的那样,编译器现在做得很好。然而,具体情况并非如此,他们已经变得比人类更好——也许有一天(比某些人类更好,是的,很明显,但不是“甚至不尝试,你永远不会打败他们”)。优化编译器非常了解优化规则,但很难找到应用它们的机会。程序员非常了解特定变量在任何程序点可以具有的值,但是编译器必须尝试从上下文中再次找出它。抽象解释有很长的路要走,但它并不完美,也不可能完美。编译器还不太擅长优化缓存使用。他们正在慢慢到达那里,但目前您经常不得不使高级代码变得丑陋以获得正确的结果。编译器在使用不是“基本数学”的指令方面也是出了名的糟糕,除非特别指示要使用内部函数(本质上是作弊——你几乎又要编写汇编了),并且当你确实使用内部函数时,结果代码是通常是not particularly good,而且它并不比直接在汇编中编写更容易(只是“下划线,到处都是下划线”更混乱)。

          那么,组装速度如何更快?你什么都知道。编译器盲目地遵循规则。

          当然,这一切都假设您真的真的知道如何针对您的目标平台进行优化。如果您要以“显而易见的方式”编写程序集,那么您可能不会击败合适的编译器。当然,您能否击败它们也很大程度上取决于编译器 - ICC 和 LLVM 很难被击败,但另一方面,您可以在睡眠中击败 .NET JIT 编译器(是的,它是 JIT 编译器,但 LLVM 也是如此,如果你愿意的话)。


          如果你想知道如何击败编译器..

          阅读所有内容here,多读几遍。然后进行大量练习,继续对所有内容进行基准测试,并针对所有相关内容与您最喜欢的编译器进行对比(这将是“内循环”类型的东西 - 优化不占用运行时大部分时间的代码是没有意义的) .最终,您将始终如一地击败它。它并不像人们想象的那么难,它只需要大量的练习,你应该知道你的目标平台是如何工作的(你永远不必查看指令的延迟或吞吐量、它的执行端口和绝对不是它创建了多少微操作)。

          【讨论】:

          • 问题是,即使我们在“无所不知”的情况下理论上可以击败编译器,但前提条件很可能在下个月发生变化。编译器可以在 30 秒内重新优化,但人类必须重新开始。这几乎不值得付出努力。
          • @BoPersson 这当然是真的,但我真的不喜欢人们如何让它听起来像是不可能的......问题只是它几乎不值得
          【解决方案6】:

          这取决于。现代 RISC 处理器极难手动优化,延迟分支、推测执行、繁重的流水线等。这取决于您要做什么、使用的 HLL、编译器的好坏等。

          直到本世纪初的某个时候,X86 架构更接近于 CISC(想想 Vax)而不是 RISC(想想 Sparc),因此专家可以击败优秀的优化编译器。但是 AMD 正在认真地踢英特尔的性能数据,因为他们的芯片在幕后实际上是更多的 RISC。结果是 X86 世界的手写程序集在性能上出现了分裂。

          对于大多数专用处理器(例如 DSP 芯片)而言,性能提升仍然是通过手写汇编来实现的,但即使是 DSP 代码的高级用户通常也依赖预先编写的库来完成艰巨的任务。

          【讨论】:

            猜你喜欢
            • 2010-09-13
            • 2014-05-04
            • 2011-04-17
            • 2018-04-10
            • 1970-01-01
            • 2019-11-18
            • 2011-05-30
            • 1970-01-01
            相关资源
            最近更新 更多