如果将程序集编译为机器代码,那么程序集如何比更高级别的语言更快?我可以理解内联汇编比周围的HLL更快,但是对于整个汇编程序而不是C,例如,两者都被编译为机器代码并且应该以相同的速度运行。
答案 0 :(得分:2)
你的问题的前提不一定是真的。现代桌面CPU非常复杂且高度流水线化。因此,CPU的性能特征可能不直观。编写编译器的人发送很多的时间来研究和实现编译器后端的优化,专门用于处理器体系结构。
除非你知道完全你正在做什么(这几乎不是这种情况),否则一个优秀的现代编译器将创建高度优化的代码而无需人为干预。直接编写程序集的原因是编译器无法创建最佳代码或作为操作系统内核的一部分。
答案 1 :(得分:2)
处理器内核直接执行机器代码指令的日子早已不复存在。它们被翻译成微操作,类似于risc的指令,旨在保持现代超标量,无序执行核心,具有多个执行单元。其实际实现是制造秘密,并为每一代新的cpu架构进行更改。具有这种行为的第一个标志处理器之一是英特尔486,可在1989年上市。
机器代码指令的效率受到它之前的指令及其之后的指令的严重影响。细节不再受人类监督。它需要一台机器。紧挨着你的那个,执行编译器的代码生成器阶段。如果您使用具有即时编译器的VM语言,或者在客户的计算机上。一种执行模型,可以处理核心之间的细微架构差异。
答案 2 :(得分:1)
高级语言并不比汇编语言快。好的编译器将HLL程序转换为快速的机器指令序列。好的汇编程序员也会做同样的事情。结果与绩效观点无法区分。
高级语言旨在让编程更轻松,更快捷,而不是让程序更快。
答案 3 :(得分:0)
当PC缓慢而简单且编译器不亮时,用汇编语言编写的程序曾经更快。
我曾经在20世纪80年代写过大量的装配,因为你必须才能使用我们当时的PC。它是MHz而不是GHz。
现在我有时会看一下编译器生成的代码,看看它至少和我编写的代码一样好,但更容易生成。通常它比我能做得好得多。
这样做的一个结果是微软已经为他们的x64编译器删除了内联汇编,部分原因是大多数使用汇编优化的尝试都干扰了优化器并使其对周围代码产生不太理想的结果。净亏损!
答案 4 :(得分:0)
就像很多人在这里说的那样,编译器现在做得很好。然而,特别不是他们已经变得比人类更好 - 可能有一天(比某些人更好,显然,但不是“甚至不尝试,你永远不会击败他们”)。优化编译器是非常好的知道优化规则,但很难找到应用它们的机会。程序员非常了解特定变量在任何程序点可以具有的值,但编译器必须尝试从上下文中再次计算出来。抽象的解释有很长的路要走,但它并不完美,也不可能。编译器还不是很擅长优化缓存使用。他们正在慢慢地到达那里,但是目前你经常需要让高级代码难以获得正确的结果。编译器也非常糟糕地使用不是“基本数学”的指令,除非特别指示使用内部函数(这实际上是作弊 - 你几乎再次编写汇编)并且当你使用内部函数时产生的代码是通常not particularly good除此之外,它并不比直接在汇编中更容易(只有“下划线,下划线到处都是”更加混乱)。
那么,装配如何更快?你知道一切。编译器盲目遵循规则。
当然,假设您真的真的知道如何针对您的目标平台进行优化。如果你要以“显而易见的方式”编写程序集,那么你可能不会打败正确的编译器。你是否可以击败它们当然也很大程度上取决于编译器 - ICC和LLVM很难被击败,但另一方面,你可以在睡眠中击败.NET JIT编译器(是的,它是一个JIT编译器) ,但LLVM也是如此,如果你想要的话。)
如果您想知道如何击败编译器..
多次阅读所有内容here。然后练习很多,继续对所有内容进行基准测试,并针对相关的所有内容(这将是“内循环”类型的东西)与你最喜欢的编译器对抗 - 无论如何优化代码并不占用运行时的重要部分是没有意义的。最终你会一直击败它。它并不像人们想象的那么难,它需要大量的练习,你应该知道你的目标平台是如何工作的(你应该永远不必查看指令的延迟或吞吐量,它的执行端口和绝对不会创造多少μops。
答案 5 :(得分:0)
这取决于。现代RISC处理器非常难以手动优化,这会延迟分支,推测执行,繁重的流水线等。这取决于您要做什么,您正在使用哪个HLL,编译器有多好等等。
直到本世纪初的某个时候,X86架构比RISC(想想Sparc)更接近CISC(想想Vax),因此专家可以击败优秀的优化编译器。但是AMD正在认真对待英特尔的性能数据,因为他们的芯片实际上远远超过了RISC。结果是X86世界的手写程序集在性能上分裂。
对于大多数专业处理器,例如DSP芯片,性能提升仍然是手工编写的,但即使是DSP代码的高级用户也通常依靠预先编写的库来完成这些工作。