Performance 汇编中的指令成本激增
我一直对组装过程中的跳跃成本感到好奇Performance 汇编中的指令成本激增,performance,assembly,x86,Performance,Assembly,X86,我一直对组装过程中的跳跃成本感到好奇 cmp ecx, edx je SOME_LOCATION # What's the cost of this jump? 它是否需要在查找表中搜索每个跳转,或者它是如何工作的?最初(例如8086)跳转的成本与mov的成本没有太大区别 后来CPU添加了缓存,这意味着一些跳转更快(因为它们跳转到的代码在缓存中),而一些跳转较慢(因为它们跳转到的代码不在缓存中) 甚至在后来,CPU添加了“无序”执行,其中条件分支(例如,je SOME_LOCATION)将不得
cmp ecx, edx
je SOME_LOCATION # What's the cost of this jump?
它是否需要在查找表中搜索每个跳转,或者它是如何工作的?最初(例如8086)跳转的成本与mov的成本没有太大区别
后来CPU添加了缓存,这意味着一些跳转更快(因为它们跳转到的代码在缓存中),而一些跳转较慢(因为它们跳转到的代码不在缓存中)
甚至在后来,CPU添加了“无序”执行,其中条件分支(例如,je SOME_LOCATION
)将不得不等待,直到“先前的指令碰巧并行执行”中的标志变为已知
这意味着
mov esi, edi
cmp ecx, edx
je SOME_LOCATION
可能比重新排列要慢
cmp ecx, edx
mov esi, edi
je SOME_LOCATION
以增加了解旗帜的机会
甚至在后来,CPU添加了推测性执行。在这种情况下,对于条件分支,CPU只是在它实际知道之前(例如,在知道标志之前)猜测它将分支到哪里,如果它猜错了,它将假装它没有执行错误的指令。更具体地说,推测执行的指令在管道开始时被标记,并在管道结束时(失效时)保持,直到CPU知道它们是否可以提交到可见状态或是否必须丢弃
在那之后,事情变得更加复杂,有了更奇特的分支预测方法,额外的“分支目标”缓冲区,等等
改变代码段的远跳代价更高。在实模式下,这并不坏,因为当CS
发生变化时,CPU通常只执行“CS.base=value*16”。对于保护模式,它是一个表查找(查找GDT或LDT条目),解码条目,根据条目的类型决定要做什么,然后是一堆保护检查。对于长模式,它有点相似。所有这些都增加了更多的不确定性(例如,表项是否在缓存中?)
除此之外,还有TLB失误等问题。例如,jmp[indirectAddress]
可能导致indirectAddress
处的TLB未命中,然后是堆栈顶部的TLB未命中,然后是新指令指针处的TLB未命中;其中,每次TLB未命中可能需要几百个周期
大部分;跳转的成本可以是0个周期(对于正确预测的跳转)到1000个周期之间的任何值;取决于它是哪个CPU,什么类型的跳转,缓存中有什么,分支预测预测预测什么,缓存/TLB未命中,RAM有多快/慢,以及我可能忘记的任何事情。最初(例如8086),跳转的成本与mov的成本没有太大区别
后来CPU添加了缓存,这意味着一些跳转更快(因为它们跳转到的代码在缓存中),而一些跳转较慢(因为它们跳转到的代码不在缓存中)
甚至在后来,CPU添加了“无序”执行,其中条件分支(例如,je SOME_LOCATION
)将不得不等待,直到“先前的指令碰巧并行执行”中的标志变为已知
这意味着
mov esi, edi
cmp ecx, edx
je SOME_LOCATION
可能比重新排列要慢
cmp ecx, edx
mov esi, edi
je SOME_LOCATION
以增加了解旗帜的机会
甚至在后来,CPU添加了推测性执行。在这种情况下,对于条件分支,CPU只是在它实际知道之前(例如,在知道标志之前)猜测它将分支到哪里,如果它猜错了,它将假装它没有执行错误的指令。更具体地说,推测执行的指令在管道开始时被标记,并在管道结束时(失效时)保持,直到CPU知道它们是否可以提交到可见状态或是否必须丢弃
在那之后,事情变得更加复杂,有了更奇特的分支预测方法,额外的“分支目标”缓冲区,等等
改变代码段的远跳代价更高。在实模式下,这并不坏,因为当CS
发生变化时,CPU通常只执行“CS.base=value*16”。对于保护模式,它是一个表查找(查找GDT或LDT条目),解码条目,根据条目的类型决定要做什么,然后是一堆保护检查。对于长模式,它有点相似。所有这些都增加了更多的不确定性(例如,表项是否在缓存中?)
除此之外,还有TLB失误等问题。例如,jmp[indirectAddress]
可能导致indirectAddress
处的TLB未命中,然后是堆栈顶部的TLB未命中,然后是新指令指针处的TLB未命中;其中,每次TLB未命中可能需要几百个周期
大部分;跳转的成本可以是0个周期(对于正确预测的跳转)到1000个周期之间的任何值;取决于它是哪个CPU,什么类型的跳转,缓存中有什么,分支预测预测预测什么,缓存/TLB未命中,RAM有多快/慢,以及我可能忘记的任何内容。不,跳转不进行搜索。汇编程序将标签解析为一个地址,在大多数情况下,该地址会转换为当前指令的偏移量。地址或偏移量在指令中进行编码。在运行时,处理器将地址加载到IP寄存器或将偏移量添加到IP寄存器的当前值(以及@Brendan讨论的所有其他影响)
有一种类型的跳转指令可用于从表中获取目标。跳转指令从内存位置读取地址。(该指令指定了一个位置,因此仍然没有“搜索”。)该指令可能如下所示:
jmp table[eax*4]
其中eax是表中包含要跳转到的地址的项的索引。否,跳转不进行搜索。汇编程序将标签解析为一个地址,在大多数情况下,该地址会转换为当前指令的偏移量