4

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

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

CPUID 指令告诉 Family、Model 和 Stepping。

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

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

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

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

编辑:在第一个序列中添加“XOR PTR ereg,0”确实使时间与奔腾 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
4

4 回答 4

3

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

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

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

于 2009-07-08T16:57:08.063 回答
1

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

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

于 2009-07-10T14:35:47.547 回答
0

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

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

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

于 2009-07-13T19:41:28.003 回答
0

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

于 2009-08-06T06:19:54.700 回答