我知道在现代处理器上按位运算是如此之快,因为它们可以并行地以32或64位进行操作,因此按位运算仅需一个时钟周期。但是加法是一个复杂的操作,至少包含一个(可能多达十二个)按位运算,因此我自然认为它会慢3-4倍。经过一个简单的基准测试,我惊讶地发现加法运算与任何按位运算(XOR,OR,AND等)完全一样快。谁能阐明这一点?
我知道在现代处理器上按位运算是如此之快,因为它们可以并行地以32或64位进行操作,因此按位运算仅需一个时钟周期。但是加法是一个复杂的操作,至少包含一个(可能多达十二个)按位运算,因此我自然认为它会慢3-4倍。经过一个简单的基准测试,我惊讶地发现加法运算与任何按位运算(XOR,OR,AND等)完全一样快。谁能阐明这一点?
Answers:
加法速度很快,因为CPU设计人员已加入了使其快速化所需的电路。与按位运算相比,它确实需要进行更多的门操作,但是它经常被CPU设计人员认为是值得的。参见https://en.wikipedia.org/wiki/Adder_(electronics)。
两者都可以足够快地在单个CPU周期内执行。它们的速度不一样-加法比按位操作需要更多的门和更多的延迟-但它足够快,处理器可以在一个时钟周期内完成。指令解码和控制逻辑存在每条指令的等待时间开销,并且其等待时间明显大于执行按位运算的等待时间,因此两者之间的差异被该开销所淹没。 AProgrammer的答案和Paul92的答案很好地解释了这些效果。
有几个方面。
按位运算和相加的相对成本。天真的加法器的门深度与单词的宽度成线性关系。有一些替代的方法会降低深度(IIRC的深度然后对数取决于单词的宽度),而这种方法的门成本更高。其他人已经提供了此类技术的参考,我只是指出,由于需要增加延迟的控制逻辑,因此差异也没有考虑到操作成本时那么重要。
然后是一个事实,即处理器通常是有时钟的(我知道一些研究或特殊用途的无时钟设计,但我什至不确定某些产品是否可以在市场上买到)。这意味着无论操作速度如何,都将花费时钟周期的整数倍。
最后,还有微体系结构方面的考虑:您确定要衡量所需的内容吗?如今,处理器倾向于流水线化,多标量,无序执行等。这意味着他们能够在完成的各个阶段同时执行几条指令。如果要通过度量显示某个操作比另一个操作花费更多的时间,则必须考虑这些方面,因为它们的目标是隐藏那些差异。使用独立数据时,添加和按位操作的吞吐量可能会完全相同,但是以其他方式衡量时延或引入操作之间的依赖关系可能会显示出来。而且,您还必须确保度量的瓶颈在于执行,而不是例如内存访问。
paddw
在每个时钟2个运行vector-int加号(例如),但pand
在每个时钟3个运行布尔值(如)。(Skylake在所有三个向量执行端口上都添加了向量加法器。)
CPU循环运行。在每个周期中,都会发生一些事情。通常,一条指令需要花费更多的周期来执行,但同时会以不同的状态同时执行多条指令。
例如,一个简单的处理器可能为每个指令包含3个步骤:获取,执行和存储。在任何时候,都会处理3条指令:一条正在获取,一条正在执行,一条存储其结果。这称为管道,在此示例中分为3个阶段。现代处理器具有超过15个阶段的流水线。但是,加法以及大多数算术运算通常都在一个阶段中执行(我说的是ALU加2的运算,而不是指令本身-取决于处理器架构,指令可能需要从内存中提取参数,执行条件,将结果存储到内存的更多周期)。
一个周期的持续时间由最长的关键路径决定。基本上,这是准备阶段中某个阶段完成所需的最长时间。如果要使CPU更快,则需要优化关键路径。如果无法减小关键路径本身,则可以将其分为流水线的两个阶段,现在您可以以几乎两倍的频率为CPU计时(假设没有其他关键路径可以阻止您这样做) )。但这带来了开销:您需要在管道的各个阶段之间插入一个寄存器。这意味着您并没有真正获得2倍的速度(寄存器需要时间来存储数据),并且使整个设计变得复杂。
已经存在执行加法的相当有效的方法(例如,进位超前加法器),加法不是处理器速度的关键途径,因此将其分为多个周期没有意义。
另外,请注意,虽然这对您来说似乎很复杂,但是在硬件中,可以并行完成非常快的事情。
处理器采用时钟控制,因此即使某些指令的执行速度明显快于其他指令,它们也可能花费相同的周期数。
您可能会发现,在寄存器和执行单元之间传输数据所需的电路比加法器复杂得多。
注意,简单的MOV(寄存器到寄存器)指令比按位逻辑执行的计算更少,但MOV和ADD通常都需要一个周期。如果将MOV的速度提高一倍,则CPU的时钟速度将提高一倍,而ADD将是两个周期。
加法非常重要,不要让它等待进位在64位累加器中波动:这是一个超前进位加法器,它们基本上是8位CPU(及其ALU)及更高版本的一部分。实际上,现代处理器往往也不需要太多的执行时间来进行完整乘法运算:进位超前实际上是处理器设计者工具箱中的一个非常古老的工具(且价格相对可承受)。
lea
指令)。
我认为您很难找到一个处理器,其加法运算比按位运算要多。部分原因是大多数处理器必须在每个指令周期内至少执行一次加法运算,只是为了增加程序计数器的数量。仅仅按位操作并没有那么有用。
(指令周期而不是时钟周期-例如6502由于未流水线且没有指令缓存,因此每条指令至少需要两个时钟周期)
您可能缺少的真正概念是关键路径:在芯片内,可能在一个周期内执行的最长操作在硬件级别上决定了芯片的时钟频率。
例外情况是(很少使用和很少商业化的)异步逻辑,它确实会根据逻辑传播时间,设备温度等以不同的速度执行。
在门级,您正确地进行加法需要更多的工作,因此需要更长的时间是正确的。但是,该成本是无关紧要的,无关紧要。
现代处理器采用时钟。除了该时钟频率的倍数之外,您无法执行任何其他操作。如果将时钟速率提高,以最大程度地提高按位运算的速度,则必须花费至少2个周期进行加法运算。由于您实际上并不需要整个2个周期的时间,因此大部分时间将花在等待周围。您只需要1.1(或类似的数字)。现在,您的芯片添加速度比市场上其他任何产品都要慢。
更糟糕的是,仅添加或执行按位运算的行为只是一个周期中发生的一小部分。您必须能够在一个周期内获取/解码指令。您必须能够在一个周期内执行缓存操作。许多其他事情与简单的加法或按位运算在相同的时间范围内进行。
当然,解决方案是开发一个庞大的深度管道,将这些任务分解成适合按位运算定义的微小循环时间的微小部分。奔腾4以这些深入的术语表达了思想的局限性。出现各种问题。尤其是,分支变得异常困难,因为一旦拥有确定要采用哪个分支的数据,就必须冲洗管道。
现代处理器采用时钟控制:每个操作都需要一定数量的时钟周期。处理器的设计者确定时钟周期的长度。那里有两个考虑因素:一是硬件的速度,例如以单个NAND门的延迟来衡量。这取决于所使用的技术以及诸如速度与功率使用之间的权衡。它独立于处理器设计。第二,设计人员确定一个时钟周期的长度等于单个NAND门的n个延迟,其中n可能是10或30,或任何其他值。
该选择n限制了可以在一个周期内处理的复杂操作的程度。将有16个但不能以15个NAND延迟完成的操作。因此,选择n = 16表示可以在一个周期内完成此操作,选择n = 15表示无法进行此操作。
设计人员将选择n,以便许多重要的操作可以在一个或两个或三个周期内完成。n将被选择为局部最优:如果将n替换为n-1,则大多数操作会快一些,但是某些操作(确实需要完整的n个NAND延迟的操作)会慢一些。如果很少有操作会减慢速度,从而使平均程序执行速度更快,那么您将选择n-1。您也可以选择n + 1。这会使大多数操作变慢一些,但是如果您有许多操作无法在n个延迟内完成,但可以在n + 1个延迟内完成,那么它将使处理器整体速度更快。
现在您的问题:加法和减法是如此常见,以至于您希望能够在一个周期内执行它们。结果,AND,OR等执行速度更快并不重要:他们仍然需要一个周期。当然,“计算”“与”,“或”等单位有很多时间来打动拇指,但这无济于事。
请注意,不仅可以在n个NAND延迟内完成操作:例如,可以通过增加一些聪明点来加快添加速度,通过增加聪明点来加快速度,通过投入大量的硬件来加快速度。 ,最后一个处理器可能包含非常快,非常昂贵的电路以及更慢和更便宜的电路,因此可以通过花更多的钱来使一个操作足够快。
现在,您可以使时钟速度如此之高/周期如此之短,以至于只有简单的位操作在一个周期内执行,而其他所有操作都在两个或更多周期内执行。这很可能会减慢处理器的速度。对于需要两个周期的操作,通常将不完整的指令从一个周期移至下一个周期会产生开销,因此两个周期并不意味着您有两倍的执行时间。因此,要在两个周期内进行加法运算,就无法使时钟速度加倍。
让我纠正一些在您现有答案中未明确提及的事情:
我知道在现代处理器上按位运算是如此之快,因为它们可以并行运行在32位或64位上,
这是真的。通常将CPU标记为“ XX”位(并非总是如此)意味着它的大多数通用结构(寄存器宽度,可寻址RAM等)的大小均为XX位(通常为“ +/- 1”或类似大小)。但是关于您的问题,您可以放心地假设具有32位或64位的CPU将在恒定时间内对32位或64位进行任何基本位操作。
因此按位运算仅需一个时钟周期。
这个结论不一定是事实。尤其是具有丰富指令集(google CISC与RISC)的CPU,即使是简单的命令,也很容易占用多个周期。通过交织,甚至简单的命令也可能会分解为3个时钟的fetch-exec-store(作为示例)。
但是加法是一个复杂的操作
不,整数加法是一个简单的操作;减法也是如此。在全硬件中实现加法器非常容易,并且它们像基本位操作一样立即执行自己的工作。
它至少包含一个(可能多达十二个)按位运算,所以我自然认为它会慢3-4倍。
它将占用三到四倍的晶体管,但是相比之下,可以忽略的整体情况。
经过一个简单的基准测试,我惊讶地发现加法运算与任何按位运算(XOR,OR,AND等)完全一样快。谁能阐明这一点?
是:整数加法是按位运算(比其他数多一些,但仍然有一点)。不需要分阶段进行任何操作,也不需要复杂的算法,时钟或其他任何方法。
如果您希望添加比CPU体系结构更多的位,则必须分阶段进行。但这是另一个复杂性级别(编程语言级别,而不是汇编/机器代码级别)。在过去(或今天在小型嵌入式CPU上),这是一个常见问题。对于PC等,对于最常见的数据类型,它们的32位或64位就足够了,这开始成为讨论的重点。
imul rax, rcx
,在Intel Sandybridge系列和AMD Ryzen上具有3c延迟,每1c吞吐量有1个)。即使是64位全乘法(在rdx:rax中生成128位结果)也具有相同的延迟和吞吐量,但实现为2微码(在不同端口上并行运行)。(有关说明表和出色的微体系结构指南,请参见agner.org/optimize)。
uint32_t
这是两个值的加法,今天对于32位目标上的int64_t仍然适用。AVR是8位RISC微控制器,因此32位整数需要4条指令:godbolt.org/g/wre0fM