【问题标题】:Why do more Pentium assembly instructions take less time?为什么更多的 Pentium 汇编指令需要更少的时间?
【发布时间】:2010-11-09 02:40:55
【问题描述】:

以下是两个 Pentium 组装序列列表中的剪辑。我们有一个外部循环,它试图为我们的序列计时,并正在做一个调用表来访问这些例程。因此,每次都是从同一位置拨打外线电话。这两个序列的不同之处在于第一个序列比第二个序列少一条指令。

我们在两台 Intel 机器上得到的结果非常不同。

CPUID 指令告诉 Family、Model 和 Stepping。

机器 1:Family 6,Model 15 步进 11. CPUZ 报告“Intel Core 2 Duo E6750”
指令以统计上相同的速度执行。

机器 2:Family 15,Model 3,Stepping 3。CPUZ 报告“Intel Pentium 4”
第一个序列比第二个序列花费大约 8% 的时间。

我们根本无法解释时间的增加。不应该有任何不同的标志延迟、分支预测、寄存器使用问题等。至少我们无法判断。

有谁知道为什么在一台机器上执行第一个序列需要更长的时间?

编辑:在第一个序列中添加“XOR PTR ereg, 0”确实使时间与 Pentium 4 上的第二个匹配。好奇。

第一个序列:

00000040               ALUSHIFT_AND_C_V_E LABEL NEAR
00000040  0F B7 04 55       MOVZX   EAX, gwr[(SIZEOF WORD) * EDX]       ; EAX = 0000000000000000 LLLLLLLLLLLLLLLL
   00000000 E
00000048  0F B7 14 4D       MOVZX   EDX, gwr[(SIZEOF WORD) * ECX]       ; EDX = 0000000000000000 RRRRRRRRRRRRRRRR
   00000000 E
00000050  23 C2             AND     EAX, EDX                            ; AX = L&R      (result)
00000052  A3 00000000 E     MOV     dvalue, EAX                         ; Save the temporary ALU/Shifter result
00000057  C3                RET                                         ; Return

第二个序列:

00000060               ALUSHIFT_AND_C_V_NE LABEL NEAR
00000060  0F B7 04 55       MOVZX   EAX, gwr[(SIZEOF WORD) * EDX]       ; EAX = 0000000000000000 LLLLLLLLLLLLLLLL
   00000000 E
00000068  0F B7 14 4D       MOVZX   EDX, gwr[(SIZEOF WORD) * ECX]       ; EDX = 0000000000000000 RRRRRRRRRRRRRRRR
   00000000 E
00000070  23 C2             AND     EAX, EDX                            ; AX = L&R      (result)
00000072  80 35 00000000 E  XOR     BYTE PTR ereg, 1                    ; E = ~E
   01
00000079  A3 00000000 E     MOV     dvalue, EAX                         ; Save the temporary ALU/Shifter result
0000007E  C3                RET                                         ; Return

【问题讨论】:

  • 看起来类似于我问的一个问题:stackoverflow.com/questions/688325/…
  • 是 ALUSHIFT_AND_C_V_E LABEL NEAR 和 ALUSHIFT_AND_C_V_NE LABEL NEAR 两个序列吗?如果是这样,您可能应该将它们放在单独的块中以使代码更易于阅读。
  • 知道我们在谈论哪个 CPU 也很好(用人名,而不是 CPUID 字符串)
  • @Mark:谢谢。我已经根据您收到的一些答案开始调查。 @jalf:我编辑了你的优秀建议。

标签: assembly intel timing x86


【解决方案1】:

在 Pentium I 或 II 之后,编译器执行的大多数优化都不是 必要的。芯片会将这些指令分解成微操作,然后为你优化。 t 可能是芯片之间的分支预测差异,或者 XOR + RET 与普通 RET 一样昂贵的事实。我对您在上面看到的奔腾型号不太熟悉。另一种可能性是它也可能是缓存行问题或硬件差异。

英特尔文档中可能有某些内容,也可能没有。

无论如何。经验丰富的汇编编码人员知道,唯一的真理是通过测试实现的,这就是您正在做的事情。

【讨论】:

  • 奔腾和更高版本的编码和其他任何东西一样都是巫毒。有时添加更多指令会使事情变得更快,等等。实际测试和计时是唯一可行的方法!
【解决方案2】:

事实证明,与代码所在的位置存在一些奇怪的交互,导致增加。即使一切都是缓存对齐的,切换代码块会导致 Pentium-4 上的时间增加

感谢所有花时间调查或查看它的人。

【讨论】:

    【解决方案3】:

    您可以在此代码前面添加一个、两个等 nop(并且不更改任何其他内容)以移动它在缓存中的位置,以查看是否有缓存效果(或者只是关闭缓存)。警告虽然只要一个额外的 nop 就可以改变其他地方的指令,该指令不能再使用相对于 pc 寻址的东西,导致可能更多的指令字节导致被测代码移动超过预期以及可能的连锁反应其他相关的更改说明。

    即使您玩缓存游戏,这里野兽的本性也是芯片内部的魔法,它接收一条指令流并将其分配给执行单元。

    即使您不明白为什么,调整和测试最终才是真正获得性能的原因。尽管一旦您将该代码移至较旧的芯片或较新的芯片或不同的主板或相同的芯片系列,但不同的步进,您所有的性能调整都会让您兴奋。

    【讨论】:

      【解决方案4】:

      几个月前,我也遇到过类似的事情。我的项目有一个配置开关,用于启用__thread 用于线程局部变量。没有它,它将使用pthread_getspecific 等。后者的每一点都与__thread 版本一样多,加上一个函数调用以及一些用于设置参数、保存寄存器等的附加指令。有趣的是,更费力的版本始终更快。不过,仅在 Pentium 4 上。所有其他芯片都表现良好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-13
        • 2010-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多