您的位置:首页 > 运维架构 > 网站架构

Intel, AMD及VIA CPU的微架构(8)

2017-11-03 11:44 393 查看

3.15.      在更旧处理器上的间接跳转

间接跳转,间接调用,以及返回每次都可能去不同的地址。在比PM及K10更旧的处理器中,间接跳转或间接调用的预测方法只是预测它将去到与上一次执行相同的目标。在第一次看到间接跳转或间接调用时,它被预测去到紧接着的指令。因此,间接跳转或调用总是应该后接有效的代码。不要在一个间接跳转或调用后立即放置一系列跳转地址。这样一个列表最好放在数据段,而不是代码段。

一个多路分支(switch语句)要么被实现为一个使用一组跳转地址的间接跳转,要么被实现为一棵分支指令树。间接跳转有在许多处理器上预测不佳的缺点,但分支树也有其他缺点,即它消耗更多BTB项,许多处理器对稠密或连续分支性能不佳。

3.16.      返回(所有处理器,除了P1)

一个更好的方法用于返回。一个称为返回栈缓冲的后进先出缓冲,在每次执行一条调用指令时,记录返回地址,并使用之预测对应的返回将去哪里。当从几个不同地点调用相同的例程时,这个机制确保返回指令被正确预测。

P1没有返回栈缓冲,但对返回使用与间接跳转的相同方法。更后的处理器有一个返回栈缓冲。在PMMX中,这个缓存的大小是4,在Atom中是8,在AMD k8中是12,在PPro、P2、P3、P4、P4E、PM、Core及Nehalem中是16,在AMDK10中是24。这个尺寸看起来相当小,但在大多数情形下足够了,因为就执行而言,仅最里层例程要紧。在深度嵌套递归函数中,返回栈缓冲可能会不足够。

为了使这个机制工作,你必须确保所有的调用都有匹配的返回。永远不要不使用return跳出一个例程,也永远不要将一个return用作间接跳转。不过,在16与32位模式中以JMPMYPROC替换CALLMYPROC / RET序列是可以的。在64位模式中,遵循栈对齐标准,你可以JMP MYPROC替换SUBRSP, 8 / CALL MYPROC / ADD RSP, 8。

在大多数处理器上,你必须确保远程调用与远程返回匹配,近程调用与近程返回匹配。在16位代码中这可能是有问题的,因为汇编器将以PUSHCS后接一个近程调用来替换对在同一个段中过程的远程调用。即使你通过写死的远程调用来阻止汇编器这样做,链接器很可能将这个远程调用翻译为PUSHCS与一个近程调用。在链接器中使用/NOFARCALLTRANSLATION选项来防止。建议使用一个小或平面内存模式,使得你无需远程调用,因为无论如何,远程调用与返回都是高代价的。

3.17.      静态预测

在第一次看到一条分支指令时,根据静态预测原则做出一次预测。

在P1与PMMX中的静态预测

在P1与PMMX上,之前未见过或不在分支目标缓存(BTB)的控制转移指令总是被预测落空。

一条分支指令如果总是落空,将不会得到一个BTB项。只有它被采用一次,它将进入BTB。在PMMX上,不管落空多少次,它都将待在BTB中。任何跳转到紧接着自己的控制转移指令将不会得到BTB项,因此将总是有误预测惩罚。

PPro,P2,P3,P4,P4E中的静态预测

在PPro,P2,P3,P4及P4E上,之前未见过或不在分支目标缓存的控制转移指令,如果向前,预测落空,如果后向(即循环),预测被采用。在这些处理器上,静态预测比动态预测更耗时。

在P4与P4E上,你可以通过添加预测暗示前缀改变静态预测。前缀3EH将使分支被预测为第一次即采用,前缀2EH将使分支被预测为第一次即不采用。这些前缀可以这个方式编码:

;Example 3.6. P4/P4E static branch prediction hint

DB3EH ; Prediction hint prefix

JBELL ; Predicted taken first time

预测暗示前缀事实上是段前缀,它们没有影响,在其他处理器上不会造成危害。

很少情形值得将静态预测考虑进来。几乎任何执行足够频繁、影响足够大的分支都很可能待在BTB中,使得仅动态预测起作用。仅当上下文或任务切换发生得非常频繁时,静态预测才有显著的影响。

通常,你无需关心静态误预测的惩罚。组织分支,使最经常的路径不被采用更为重要,因为这改进了代码预取,追踪缓存使用,以及回收。

静态预测确实对追踪缓存中追踪的组织有影响,但这不是一个持续的影响,因为在几次迭代后,追踪可能被重新组织。

PM与Core2中的静态预测

这些处理器不使用静态预测。在第一次看见一个分支时,预测器只是做出一个随机预测,依赖于要分配给这个新分支的BTB项有什么。只有50%的机会做出跳转或不跳转的周期预测,但被预测的目标是正确的。分支暗示前缀在PM与Core2处理器上没有作用。

AMD中的静态预测

第一次看到一个分支时,预测它不被采用。第一次被采用后,分支总是被预测采用。动态预测总是在分支被采用后使用,然后是不被采用后。分支暗示前缀没有作用。

3.18.      邻近的跳转

在PMMX上的邻近跳转

在PMMX上,存在两条控制转移指令共享相同BTB项的风险,如果它们彼此太靠近。显而易见的结果是它们将总是被误预测。用于一条控制转移指令的BTB项由该指令最后字节地址的2-31比特识别。如果两条控制转移指令太靠近,仅在地址的0-1比特不同,那么我们有共享BTB项的问题。对于这个问题,RET指令特别脆弱,因为它仅有一个字节。有各种方式避免这个问题:

1.      在内存中稍微上下移动一下代码序列,使得在两个地址间是一个DWORD边界。

2.      将短程跳转改变为近程跳转(带有4字节位移),使得指令末尾下移更多。你没有办法强迫汇编器使用一条指令最短形式以外的形式,因此如果选择它,你需要写死近程跳转。

3.      在两条控制转移指令间放置某些指令。这是最容易的方法,如果因为段不是DWORD对齐,你不知道DWORD边界在哪, 或者因为在之前的代码中的改变,代码不停地移上、移下,这是唯一的方法。

当紧接着一个调用目标标记的第一个指令对包含另一个调用指令,或者一个返回紧接着另一个返回时,有惩罚。

对串接调用的惩罚仅出现在从多处调用相同的子例程时。串接的返回总是有惩罚。有时在一次调用后有一个小暂停,但对调用后的返回;返回后的调用;跳转后的跳转、调用或返回;或者返回后的跳转,都没有惩罚。

PPro,P2与P3上的串接跳转

在PPro,P2及P3上,在前一个跳转、调用或返回后的第一个时钟周期里不能执行跳转、调用或返回。因此,对每个跳转,串接跳转将需要2个时钟周期,你可能希望确保处理器可以并行干点别的。出于同样原因,在这些处理器上,一个循环每次迭代至少需要2个时钟周期。

在P4,P4E及PM上的串接跳转

回收站每时钟周期仅能处理一个采用的跳转、调用或返回,且仅在三个回收工位的第一个里。因此,最好不要每三个μop超过一个跳转。

AMD上的串接跳转

采用的跳转有每两个时钟周期一个的吞吐率。如果在跳转目标后有一个16字节边界,会被延迟一个时钟周期。没采用跳转的吞吐率是三个时钟周期一个。避免在一条分支指令紧跟一字节的返回指令。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  x86 英特尔 amd cpu