我记得在哪里读过要真正优化的东西。加速代码的某些部分,程序员用汇编语言编写该部分。我的问题是 -
我正在努力理解这个概念&非常感谢任何帮助或链接。
UPDATE:根据dbemerlin的要求改写第3点 - 因为您可能能够编写比编译器生成的更有效的汇编代码,但除非您是汇编专家,否则您的代码可能会运行得更慢,因为编译器比大多数人都能更好地优化代码。
答案 0 :(得分:27)
恢复汇编语言的唯一时间是
CPU指令在C ++中没有功能等价物(例如,单指令多数据指令,BCD或十进制算术运算)
<cstdlib>
有div
/ldiv
等等及时获得商数和余数)OR
出于某种莫名其妙的原因 - 优化器未能使用最佳CPU指令
... AND ... 的
简单地使用内联汇编来执行一个可以用C ++轻松表达的操作 - 比如添加两个值或搜索字符串 - 会起到反作用,因为:
gcc -S
)或反汇编机器代码#ifdef
- 适用于您的平台我认为值得记住的一个观点是,当C被引入时,它必须赢得许多硬核汇编语言程序员,他们对生成的机器代码感到困惑。机器当时拥有较少的CPU功率和RAM,你可以打赌人们对最微小的东西感到困惑。优化器变得非常复杂并且不断改进,而像x86这样的处理器的汇编语言变得越来越复杂,执行管道,缓存和其他因素也越来越复杂。您不能再添加每个指令周期表中的值。编译器编写者花时间考虑所有这些微妙因素(特别是那些为CPU制造商工作的因素,但这也增加了其他编译器的压力)。现在,对于汇编程序员来说,平均 - 在任何非平凡的应用程序上 - 显着提高代码效率比使用良好的优化编译器产生的效率更加不切实际,并且它们极可能会变得更糟。因此,组装的使用应限制在真正产生可衡量和有用的差异的时间,值得耦合和维护成本。
答案 1 :(得分:14)
首先,您需要对程序进行概要分析。然后,您可以在C或C ++代码中优化最常用的路径。 Unless advantages are clear you don't rewrite in assembler。使用汇编程序会使代码更难维护而且便携性更低 - 除非在极少数情况下,否则它是不值得的。
答案 2 :(得分:10)
(1)是的,最简单的尝试方法是使用内联汇编,这是依赖于编译器的,但通常看起来像这样:
__asm
{
mov eax, ebx
}
(2)这是非常主观的
(3)因为您可能能够编写比编译器生成的更有效的汇编代码。
答案 3 :(得分:4)
现在使用汇编语言的原因很少,即使像SSE这样的低级构造和旧的MMX在gcc和MSVC中都有内置的内在函数(icc我打赌但我从未使用它)。
老实说,如今优化者非常咄咄逼人,以至于大多数人甚至无法匹配他们在集会中编写代码的一半表现。您可以更改数据在内存中的排序方式(用于本地)或告诉编译器更多关于您的代码(通过#pragma
),但实际上编写汇编代码...怀疑您将从中获得额外的任何内容。
@VJo,请注意,在高级C代码中使用内在函数可以让您进行相同的优化,而无需使用单个汇编指令。
值得一提的是,有关下一代Microsoft C ++编译器的讨论,以及它们将如何从中删除内联汇编。这充分说明了它的必要性。
答案 4 :(得分:3)
您应该阅读经典书籍Zen of Code Optimization
以及Michael Abrash后续Zen of Graphics Programming
。
总结在第一本书中,他解释了如何将装配编程推向极限。在后续文章中,他解释说程序员应该使用像C这样的更高级别的语言,并且只在必要时尝试使用汇编来优化一些非常具体的点。
这种改变的一个动机是他看到,与从高级语言编译的代码(maube编译器)相比,下一代同一处理器系列中针对一代处理器的高度优化程序可能会(稍微)变慢。例如,使用新指令。
另一个原因是编译器非常好并且现在正在积极地进行优化,通常会有更多的性能来获得将C代码转换为汇编的算法。即使对于GPU(图形卡处理器)编程,您也可以使用C使用cuda或OpenCL进行编程。
还有一些(罕见的)应该使用汇编的情况,通常是为了对硬件进行非常精细的控制。但即使在OS内核代码中,它通常也是非常小的部分而且代码不多。
答案 5 :(得分:3)
答案 6 :(得分:2)
看看here,那个家伙使用汇编代码改进了6次性能。所以,答案是:它仍在完成,但编译器做得非常好。
答案 7 :(得分:2)
这取决于。在某些情况下它仍在(仍然)完成,但在大多数情况下,它是不值得的。现代CPU非常复杂,为它们编写高效的汇编代码同样复杂。因此,大多数情况下,手动编写的程序集最终会比编译器为您生成的程序集慢。
假设在过去几年中发布了一个不错的编译器,通常可以调整您的C / C ++代码,以获得与使用程序集相同的性能优势。
这里的评论和答案中很多人都在谈论他们在集会中重写了“N次加速”,但这本身并不意味着太多。通过重写C函数来评估C 中的流体动力学方程,通过应用许多相同的优化,如果你在汇编中编写它,通过了解硬件,我得到了13倍的加速,通过剖析。最后,它足够接近CPU的理论峰值性能,在组装中重写它会有无点。通常,这不是限制因素的语言,而是您编写的实际代码。只要你没有使用编译器有困难的“特殊”指令,就很难打败编写良好的C ++代码。
装配不是神奇地更快。它只需要编译器退出循环。这通常是一件坏事,除非你真的知道你正在做什么,因为编译器执行了很多优化,而这些优化实际上非常痛苦。但在极少数情况下,编译器只是不理解您的代码,并且无法为它生成有效的程序集,而那么,自己编写一些程序集可能会很有用。除了驱动程序开发之类的东西(你需要直接操作硬件)之外,我唯一能想到编写程序集可能值得的地方就是如果你遇到无法从中生成高效SSE代码的编译器内在函数(如MSVC)。即使在那里,我仍然开始在C ++中使用内在函数,并对其进行概要分析并尝试尽可能地调整它,但由于编译器不是很擅长这一点,最终可能值得重写代码在集会中。
答案 8 :(得分:1)
在我的工作中,我在嵌入式目标(微控制器)上使用汇编进行低级访问。
但对于PC软件,我认为它不是很有用。
答案 9 :(得分:1)
我有一个我已经完成的装配优化的例子,但它又是一个嵌入式目标。你也可以看到一些用于PC的汇编编程的例子,它创建了非常小而快的程序,但通常不值得努力(查找“用于windows的程序集”,你可以找到一些非常小而漂亮的程序)。
我的例子是当我编写打印机控制器时,有一个应该每50微秒调用一次的函数。它必须或多或少地进行比特的重新洗牌。使用C我已经能够在大约35微秒内完成它,并且使用汇编我已经在大约8微秒内完成了它。这是一个非常具体的程序,但仍然是真实和必要的。
答案 10 :(得分:1)
在某些嵌入式设备(手机和PDA)上,它很有用,因为编译器不是非常成熟,并且可能生成极其缓慢甚至不正确的代码。我个人不得不解决或编写汇编代码来修复基于ARM的嵌入式平台的几个不同编译器的错误输出。
答案 11 :(得分:1)
“这种做法仍在进行吗?” ->在图像处理,信号处理,AI(例如有效矩阵乘法)等中完成。我敢打赌,我的Macbook触控板上滚动手势的处理也是部分汇编代码,因为它是立即执行的。 ->甚至可以在C#应用程序中完成(请参见https://blogs.msdn.microsoft.com/winsdk/2015/02/09/c-and-fastcall-how-to-make-them-work-together-without-ccli-shellcode/)
“用汇编语言编写代码是否有点麻烦和古朴?” ->这是锤子或螺丝刀之类的工具,某些任务需要制表师螺丝刀。
答案 12 :(得分:0)
答案 13 :(得分:-1)
使用此:
__asm__ __volatile__(/*assembly code goes here*/);
__asm__
也可以是asm。
__volatile__
阻止编译器进行进一步的优化。