下面是两个Pentium汇编序列列表中的剪辑。我们有一个外部循环,它试图计算我们的序列,并且正在进行一个call-through-table来获取这些例程。因此,每次都在同一位置进行外线呼叫。这两个序列的不同之处在于,第一个序列的指令少于第二个序列。
我们在两台英特尔机器上获得的结果非常不同。
CPUID指令告诉Family,Model和Stepping。
机器1:系列6,型号15步进11.CPUZ报告“Intel Core 2 Duo E6750”
指令在统计上以相同的速度执行。
机器2:系列15,型号3,步进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
答案 0 :(得分:3)
在Pentium I或II之后,编译器执行的大多数优化都不是 必需的。芯片会将这些指令分解为微操作,然后为您优化。 t可能是芯片之间的分支预测差异,或者XOR + RET与普通RET一样昂贵的事实。我不太熟悉你在上面看到的Pentiums模型。另一种可能性是它也可能是缓存行问题或硬件差异。
英特尔文档中可能存在某些内容,或者可能没有。
不管。经验丰富的汇编程序员知道唯一的事实是通过测试来实现的,这就是你正在做的事情。
答案 1 :(得分:1)
事实证明,代码所在的位置存在一些奇怪的交互,导致增加。即使所有内容都是高速缓存对齐的,切换代码块也会导致Pentium-4的时间增加
感谢所有花时间调查或查看它的人。
答案 2 :(得分:0)
您可以在此代码前添加一个,两个等nops(并且不进行任何其他操作)以移动到缓存中的位置以查看是否存在缓存效果(或只是关闭缓存)。警告虽然只要一个额外的nop可以改变其他地方的指令,使用相对于pc寻址不再达到某些东西,可能导致更多的指令字节导致被测代码移动超过预期以及可能的连锁反应其他相对要求改变的指示。
即使您玩缓存游戏,这里的野兽的本质也是芯片内部的神奇之处,它采用一条指令流并在执行单元之间进行划分。
调整和测试是最终真正获得性能,即使你不明白为什么。虽然只要将代码移动到较旧的芯片或较新的芯片或不同的主板或相同的芯片系列但不同的步进,所有的性能调整都可以打开你。
答案 3 :(得分:0)
几个月前,我发生了类似的事情。我的项目有一个configure-switch,可以将__thread
用于线程局部变量。没有它,它将使用pthread_getspecific
等。后者与__thread
版本加上函数调用以及一些用于设置参数,保存寄存器等的附加指令一样多。有趣的是,更费力的版本一直更快。但是,仅限奔腾4。所有其他芯片都表现得很好。