以下汇编代码的速度要快多少:
shl ax, 1
与以下C代码对比:
num = num * 2;
我怎么能找到?
答案 0 :(得分:25)
您的程序集变体可能更快,可能更慢。是什么让你认为它必然更快?
在x86平台上,有很多方法可以将某些东西乘以2.我希望编译器可以add ax, ax
,这比shl
更直观,因为它不涉及可能存储的常量(在您的情况下为“1”)。
另外,很长一段时间,在x86平台上,用常数乘以东西的首选方法不是移位,而是lea
操作(如果可能的话)。在上面的示例中,lea eax, [eax*2]
。 (乘以3将通过lea eax, [eax*2+eax]
)
对于新手来说,轮班操作的信念在某种程度上“更快”是一个很好的老故事,今天几乎没有相关性。而且,和往常一样,大多数情况下,您的编译器(如果它是最新的)对基础硬件平台的了解要远远超过那些对轮班操作非常热爱的人。
答案 1 :(得分:8)
这是否是一个学术问题?我假设你明白它属于“理发减肥”的一般范畴。
答案 2 :(得分:5)
如果您使用GCC,请询问使用选项-S查看生成的程序集。您可能会发现它与汇编程序指令相同。
要回答原始问题,在Out-Of-Order处理器上,指令速度是通过吞吐量和延迟来衡量的,您可以使用rdtsc汇编指令来测量两者。但是其他人为你做了很多处理器,所以你不需要打扰。 PDF
答案 3 :(得分:4)
在大多数情况下,它不会有所作为。乘法在几乎所有现代硬件上都很快。特别是,它通常足够快,除非你有精心设计的手动优化代码,否则管道将隐藏整个延迟,你将看不到两种情况之间的速度差异。
您可以在单独执行它们时测量乘法和移位的性能差异,但在其余编译代码的上下文中通常没有任何差异。 (正如我所指出的,如果代码经过精心优化,这可能不成立。)
现在,也就是说,移位通常仍然比乘法更快,并且几乎任何合理的编译器都会将固定的2次幂乘法映射到移位中(假设语义在目标体系结构上实际上是等效的)。
编辑:如果您真的关心这件事,可能还需要尝试一件事x+x
。我知道至少有一种架构,它实际上可以比移动更快,具体取决于周围环境。
答案 4 :(得分:3)
如果你有一个不错的编译器,它将生成相同或类似的代码。最好的方法是反汇编并检查创建的代码。
答案 5 :(得分:3)
正如你在这里看到的那样,答案取决于许多事情。编译器对C代码的作用取决于很多东西。如果我们正在谈论x86-32,那么通常应该适用以下内容。
在基本级别,C代码表示一个内存变量,需要至少有一条指令乘以2:“shl mem,1”,在这种简单的情况下,C代码会慢一些。
如果num是局部变量,编译器可能会决定将它放在寄存器中(如果它经常使用和/或函数足够小)然后你将得到你的“shl reg,1”指令 - 也许
最快的指令与它们在处理器中的实现方式有关。 Shl可能不是最佳选择,因为它影响C和Z标志,这会降低它的速度。几年前,建议是“lea reg,[reg + reg]”(所有reg都是相同的)因为lea没有影响任何标志,并且存在变体,例如(在x86-32平台上使用eax寄存器作为示例):
lea eax,[eax+eax] ; *2
lea eax,[eax+eax*2] ; *3
lea eax,[eax+eax*4] ; *5
lea eax,[eax+eax*8] ; *9
我不知道今天的规范是什么,但你的编译器可能会这样。
至于在rdtsc指令上测量信息搜索,这是最实用的时钟周期,是最实用的时钟周期。
答案 6 :(得分:1)
将它们置于一个循环中,计数器如此之高,以至于在最快的情况下运行至少一秒钟。使用您最喜欢的计时机制来查看每个计时器的持续时间。
组装案例应在与用于纯C测试的相同C程序中使用内联汇编完成。否则,你不是在比较苹果和苹果。
顺便说一句,我认为你应该加上第三个测试:
num <<= 1;
接下来的问题是,它是否与装配版本完全相同。
答案 7 :(得分:1)
如果对于目标平台,向左移动是将数字乘以2的最快方法,那么编译器编译代码时可能会这样做。查看反汇编以查看
所以,对于那一行,它的速度可能完全相同。但是,由于您不太可能只有一行包含这一行,您可能会发现编译器会推迟移位直到使用该值,或者将其与周围的代码混合在一起,从而使其不那么明确。一个好的优化编译器通常可以很好地击败穷人到平均手写程序集。
答案 8 :(得分:0)
如果编译器现在最新(vc9)确实做得很好,它会大幅超越vc6并且这不会发生,这就是为什么我甚至更喜欢使用VC6来运行比编译代码更快的代码用-O3和VC9用/ Ox
进行混合