当前位置: 首页 > 知识库问答 >
问题:

64位跳转的成本,第一次总是10-22个周期?

胡玉书
2023-03-14

在x86_64 64位地址没有直接跳转。只有一个32位。通过间接跳转,我了解在分支预测发挥作用之前,管道必须解决一次。我的问题是:在第一次执行时,64位没有办法做1-3个周期的跳跃?

共有1个答案

柏夕
2023-03-14

“第一次”直接跳转并不总是那么便宜,即使没有I-cache未命中。他们仍然需要分支预测。

在长模式下,< code>jcc rel32和< code>jmp rel32(以及rel8紧凑型版本)使用来自RIP的符号扩展相对位移。您可以跳转到任何64位地址,只要您来自2GB以内的地址。因此,请将您的代码与其他代码保持在2GB以内,这样您就可以使用rel32位移。

在长模式中没有绝对直接跳转。32位模式的farJMP ptr16:32(操作码0xEA)和farCALL ptr16-32根本没有64位版本。(为了性能和方便起见,您不需要远jmp。)像SYSCALL和INT这样的指令是间接跳转(具有隐式目标),无论如何都没有用处。

也没有指令预取/预解码指令来获得L1 I-cache或uop cache中的目标hot,或者任何方式来提示流水线不久将需要来自给定地址的解码指令。

请参阅 Darek Mihocka 关于仿真器中间接跳转的文章中的 PREDECODE 愿望清单部分,其中将一个来宾指令的处理程序直接跳转到下一个来宾指令的处理程序非常有用,而不是有一个几乎总是会误判的间接调用调度指令。(或者至少当Mihocka写道,在IT-TAGE分支预测器或多或少地解决了这个问题之前(在英特尔哈斯韦尔和后来的AMD禅宗或Zen2中):分支预测和解释器的性能 - 不要相信罗霍,斯瓦米和塞兹内克的2015年民间传说。

即使是直接跳转也需要分支目标缓冲区来预测下一个读取块应该来自其他地方。这些信息比解码阶段早得多,因此必须对其进行预测,以避免严重的前端气泡。最近有一个有趣的问题提出了这个问题:慢jmp-指令。Realworldtech论坛线程上的回复清楚地表明,分支预测需要处理读取块,而不仅仅是指令,即使在易于解码的固定宽度ISA(与x86不同)上,您也需要在解码结果可用之前进行预测。

对于新看到的直接 (rel32) 跳转的代码提取气泡的大小,1-3 个周期是不现实的。不过,该气泡的一部分可能会被解码的uop队列隐藏。

要解码的代码提取可能至少需要5或6个周期,甚至更多。假设L1-I命中时间为4个周期,与Haswell的L1D负载使用延迟相同。然后Intel CPU预解码以标记指令边界,然后解码阶段最多解码4 uops。大卫·坎特(David Kanter)的哈斯韦尔(Haswell)写作有一个前端的图表。

来自慢速 jmp 指令问题的 OP 数据表明,在英特尔 Broadwell 上,除了 JMP 指令之外,一大块只有 JMP 指令,每 12 个时钟运行一个 JMP(分支目标 = next insn),所以这是你最糟糕的情况,即获取/解码气泡根本无法隐藏,因为你没有做任何其他事情,让前端有时间赶上。

我假设我们正在谈论从传统解码器中逃跑。从 uop 缓存运行时的 BTB 未命中可能会稍短一些,因为解码后的 uop 可用速度更快。如果分支目标也在 uop 缓存中命中,则在解码的 uop 可以开始进入解码的 uop 队列(用作循环缓冲区的同一缓冲区)之前,周期也会更少。

如果解码的uop队列在代码提取气泡期间不为空,那么在发出阶段可能没有任何气泡(将uop发送到CPU的无序部分)。

或者,如果OOO部分有很多未执行的uops需要处理(即CPU正在执行一些具有瓶颈的代码,这些瓶颈将IPC限制在远小于前端带宽),则前端气泡可能不会对它产生太大影响。

不过,间接分支的情况更糟。直到几个周期后,当jmp uop在后端执行以检查预测时,才能检测到正确的目标。从错误预测中恢复涉及从执行的错误路径回滚任何独立工作,这与在任何错误路径指令/ uops发出之前重新引导前端不同。

你的基本前提是正确的:间接分支并不便宜,应该尽可能避免。(虽然一个间接分支可能比一个条件分支的短链更便宜,例如在本例中。)

相关:

  • 当skylake CPU错误预测分支时到底会发生什么?
  • 为什么这些年英特尔改变了静态分支预测机制?
  • 分支目标预测结合分支预测?
  • CPU架构演进如何影响虚函数调用性能?

 类似资料:
  • 问题内容: 我想知道x86和x64中的64位长吗? 问题答案: 是。Java 在任何JVM上都是64位,无一例外。所有Java原语类型都是完全可移植的,并且在所有实现中都具有固定的大小。

  • [VB.net]大家好, 我的代码有一个小问题。我的家里有一台现有的服务器,我正在尝试创建与服务器的连接,它可以正常工作。我现在的问题是,第一次调用,如果是登录或其他方法,它总是需要大约10秒:在第一次调用之后 然后,当我调用第一个调用时,会发生以下情况:在此处输入图像描述 这是我的AppConfig:

  • 问题内容: 我目前正在使用vbscript函数以2/12/2009格式获取本周和上周的第一天值。我想知道是否可以使用SQL查询。 问题答案: 这些语句应该在TSQL中完成您想要的操作。请注意,这些报表基于当前日期。您可以将getdate()替换为所需的任何日期:

  • 我正在检测电子邮件是否通过标题上显示的指令与fire base进行验证,并且它可以工作,但有一个奇怪的错误。 第一次尝试验证邮件时,即使已验证,也会显示未验证。当方法再次被执行时,它返回它已被验证。 我已经检查过了,这不是时间问题,即使我从验证邮件的那一刻到我告诉应用程序检查它是否被验证的那一刻离开了很长时间,它总是在第一次尝试时失败。 我该怎么办,如果电子邮件被验证,它返回说,它是从第一次尝试验

  • 本文向大家介绍查看Linux系统是32位还是64位的方法总结,包括了查看Linux系统是32位还是64位的方法总结的使用技巧和注意事项,需要的朋友参考一下 方法1:getconf LONG_BIT 查看 如下例子所示: 32位Linux系统显示32, 64位Linux系统显示64。最简单、快捷的方法。 32 64  方法2:uname命令查看 如下例子所示,x86_64表示64位系统, i686

  • fileInput包含一个大约30行的csv文件,我只想访问第二行。 我需要访问第二行而不是第一行(第一行包含列名称)<代码>行[1]给出了