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

如何找到英特尔x86 CPUs上的指令解码到的微操作?

东方弘壮
2023-03-14

第3.5.1节下的英特尔优化参考建议:

“支持单个微操作指令。”

"避免使用具有超过4个微操作并且需要多个周期来解码的复杂指令(例如,回车、离开或循环)。改用简单指令序列。"

虽然英特尔自己告诉编译器编写者使用解码为几个微操作的指令,但我在他们的任何手册中都找不到任何解释每个ASM指令解码为多少微操作的说明!这些信息在任何地方都可以找到吗?(当然,我预计不同代CPU的答案会有所不同。)

共有3个答案

张溪叠
2023-03-14

已经有人指出,Agner Fog的优化手册是一个很好的资源,特别是他的说明表,对于所有感兴趣的x86微架构来说,这些说明表几乎是全面的。

但您还有另一种选择:英特尔的架构代码分析器 (IACA)。在Stack Overflow上有一篇关于如何使用它的文章,但它非常简单(尽管对于一次性分析来说有点乏味)。您只需下载可执行文件,围绕要分析的指令块发出一些序幕和尾声代码(它包括一个用于此目的的C标头(iacaMarks.h),可与各种编译器配合使用,或者您可以指示汇编程序发出适当的字节),然后通过iaca运行二进制文件.exe.当前版本(v2.2)仅支持64位二进制文件,但这不是主要限制,因为32位和64位模式的指令级分析不会有很大不同。当前版本还支持专业软件开发人员可能感兴趣的所有现代英特尔微架构,从 Nehalem 到 Broadwell。

从此工具获得的输出将告诉您特定指令可以在哪些端口上执行,以及该指令将在指定的微体系结构上分解为多少μops。

这与您将直接回答您的问题一样接近,因为正如Hans Passant在评论中指出的那样,每条指令分解的确切μops是英特尔故意保密的。它们不仅是专有的商业秘密,而且英特尔希望能够自由地将其工作方式从一个微架构更改为另一个微架构。但实际上,一条指令分解多少μops是您在优化代码时想知道的全部内容。指令分解为哪个μops并不重要。

但我想重申彼得·科德斯回答的一部分:“尽管在某些情况下很容易猜测”。如果你必须为你正在考虑的每一条指令查找这种类型的详细信息,你将会浪费很多时间。你也会把自己逼疯,因为正如你已经知道的,它随微体系结构的不同而不同。这里真正的技巧是直观地感受x86 ISA中哪些指令是“简单”的,哪些是“复杂”的。通过阅读文档,这一点应该是显而易见的,这种直观的感觉正是英特尔优化建议的全部目标。避免“复杂的”(老CISC风格)指令,如< code>LOOP、< code>ENTER、< code>LEAVE等等。例如,优先选择< code>DEC JNZ而不是< code>LOOP。相对而言,只有一小部分“经典”x86指令能够解码一个或两个以上的操作。< sup>*研究一个优秀的优化编译器的输出也会引导您走向正确的方向,因为您永远不会看到编译器使用这些“复杂”的指令。

不过,与 Peter 的回答有些相反,我很确定英特尔优化手册中引用的部分并不是指 SIMD 指令。他们正在谈论以微码实现的老式CISC指令,如果他们不必支持它们以实现向后兼容性,他们已经放弃了。如果你需要SSE3的HADDPS的行为,那么你最好使用HADDPS,而不是试图把它分解成“更简单”的组件。(当然,除非您可以通过在不相关的代码中交错来更好地安排这些操作。但这在实践中很难做到。

*为了完全准确,有某些看似简单的指令实际上是使用微码实现的,并分解为多个µops。64位除法(DIV)就是一个例子。如果我没记错的话,这是使用类似30-40µops(变量)的东西进行微编码的。然而,这不是您应该避免的指令,这表明Intel的手册在这里分配建议时非常笼统。如果您需要进行除法,请使用DIV。显然,在优化速度时更喜欢不进行除法,但也不要试图编写自己的除法算法来避免微编码的DIV

这里的另一个大例外是字符串指令。不过,这些指令的性能计算比“避免,因为它们解码为多个µops”要复杂一点。

< sub >幸运的是,有一点很简单:不要使用没有< code>REP前缀的字符串指令。这是没有意义的,通过将指令“分解”成更简单的“组件”指令,您将获得更好的性能,例如,< code > MOVSB →< code > MOV·阿尔,[ESI] < code > MOV·埃斯:[EDI],阿尔 < code > INC/DEC ESI < code > INC/DEC EDI 。

决定有点棘手的地方是何时开始利用REP前缀。虽然这确实会导致指令解码为许多μops,但有时使用重复的字符串指令仍然比自己手动编写循环代码更有效。但并非总是如此。关于这个问题已经在Stack Overflow和其他地方进行了很多讨论。例如,请参阅此问题。

详细的分析确实超出了本答案的范围,但我的快速经验法则是,您可以完全忘记< code >代表负载 、< code >代表SCAS和< code >代表CMPS。另一方面,当您需要重复相当多的次数时,< code >代表MOVS和< code >代表STOS非常有用。总是使用尽可能大的字长:32位的DWORD,64位的QWORD(但是请注意,在现代处理器上,使用< code > MOVSB /< code > STOSB 可能更好,因为它们可以在内部移动更大的数量)。即使所有这些条件都满足了,如果你的目标有可用的向量指令,你可能想验证用向量移动实现移动/存储不会更快。

另见Agner Fog在第150页的一般建议。

万修为
2023-03-14

除了在其他答案中已经提到的资源(阿格内尔·福格的表格和IACA),您还可以在我们的网站uops.info上找到有关最新英特尔CPU(从Nehalem到Cannon Lake)上大多数x86指令的μops的详细信息。该网站还包含有关每条指令的延迟和吞吐量的信息。这些数据是通过在实际硬件(使用硬件性能计数器)和不同版本的IACA上运行自动生成的微基准测试获得的。

与Agner Fog的指令表相比,uops.info上的数据在某些情况下更加准确和精确。作为一个例子,考虑Nehalem上的PBLENDVB指令。根据Agner Fog的表,该指令有一个只能使用端口0的μop和一个只能使用端口5的μop。这可能是基于观察到,当重复执行该指令时,平均而言,端口0上有一个μop,端口5上有一个μop。uops.info上的微基准测试表明,实际上两个μops都可以使用端口0和端口5。这是通过将该指令与只能使用端口0或端口5的指令一起执行来确定的。

uops.info上的数据还揭示了英特尔IACA中的几个不准确之处。例如,在CVTPI2PS XMM的Skylake两个μop上,MM指令只能使用IACA的端口0(http://uops . info/html-ports/SKL/CVT pi 2 PS _ XMM _ MM-iaca 3.0 . html)。在实际硬件上,有一个μop只能使用端口0,还有一个μop可以同时使用端口0和端口1。Agner Fog还观察到,这条指令的一个μop可以使用端口1;但是,他声称这个μop只能使用端口1,这是不正确的。

仇建茗
2023-03-14

Agner Fog关于x86指令的PDF文档(从Hans引用的主页链接)是我发现的关于指令计时和微操作的唯一参考。我从未见过英特尔关于微操作故障的文档。

 类似资料:
  • 问题内容: 从我读到的内容来看,它用于修复CPU中的错误,而无需修改BIOS。根据我对汇编的基本知识,我知道汇编指令在内部由CPU分解为微代码,并相应地执行。但是intel以某种方式可以在系统启动和运行时进行一些更新。 有人有更多信息吗?是否有关于微码可以做什么以及如何使用的文档? 编辑:我读过维基百科的文章:没弄清楚我怎么能自己写一些,以及它有什么用。 问题答案: 在较早的时期,微代码在CPU中

  • 我正在对代码中性能关键的部分进行微优化,并遇到了指令序列(在 我想我终于有了一个xchg的用例,它可以让我删除指令并编写: 然而,令我惊讶的是,我从Agner Fog的指令表中发现,是一个3微操作指令,在Sandy Bridge、Ivy Bridge、Broadwell、Haswell甚至Skylake上具有2个周期延迟。3个完整的微操作和2个周期的延迟!3个微操作丢弃了我的4-1-1-1节奏,2

  • 问题只是关于的含义。 我认为指令本身要么实现,要么不实现,但是操作码没有不同的含义,所以对于指令本身,我想一个引用就足够了。关于性能期望,确定确切的CPU系列是重要的,而不仅仅是供应商。

  • 我正在使用Cassandra-Driver-Core-3.0.0-1。

  • 这是如此令人沮丧...我试图安装顺序node.js.我成功地在本地安装了它,但我不能全局安装它(我得到权限拒绝错误: 实际上,我并不希望它是全局安装的,但当它在本地安装时,应该配置并初始化sequelize模块(通过键入sequelize init:models 所以我做了功课,发现命令未找到错误可以解决与全局安装(-bash:续集:命令未找到)和修复错误在启用全局安装我改变了我的用户访问(错误: