问题描述
英特尔recommends使用指令前缀缓解JCC错误的性能后果。
如果使用/QIntel-jcc-erratum
编译MSVC,则遵循建议,并插入前缀指令,如下所示:
3E 3E 3E 3E 3E 3E 3E 3E 3E 48 8B C8 mov rcx,rax ; with redundant 3E prefixes
They sayMSVC在前缀不可用时求助于NOPS。
Clang有-mbranches-within-32B-boundaries
选项,如果需要,它更喜欢nop
,多字节(https://godbolt.org/z/399nc5Msq通知xchg ax, ax
)
3E前缀的后果是什么,具体是:
- 为什么英特尔推荐这种方式,而不是多字节NOPS?
- 未受影响的CPU会有什么后果?
- 据报道,AMD上的
/QIntel-jcc-erratum
程序运行得更快,可能的解释是什么?
NOP
推荐答案是单独的指令,必须分别解码并通过流水线。始终最好使用前缀填充指令以实现所需的对齐,而不是像What methods can be used to efficiently extend instruction length on modern x86?中所讨论的那样插入NOP(但只能以不会在某些无法处理大量前缀的CPU上造成重大停顿的方式进行)。
也许Intel认为工具链在这种情况下这样做是值得的,因为它实际上将位于内部循环内,而不仅仅是内部循环外部的NOP。(将前缀添加到前一条指令相对简单。)
我现在有了一些数据点。AMD FX 8300上/QIntel-jcc-erratum
的基准测试结果差。
特定基准测试的速度下降了十进制数量级,其中英特尔Skylake在同一基准测试中的收益约为20%。这与Peter的评论一致:
尽管推土机家族确实过时了,但我认为我承受不起如此大的影响。我还担心其他CPU可能会以同样的方式被额外的前缀卡住。因此,我的结论是而不是将/QIntel-jcc-erratum
用于一般目标软件。除非在特定的翻译单位中启用它并动态调度到那里,这在大多数情况下都是一件非常麻烦的事情。
在MSVC上可能安全的一件事是停止使用/Os
标志。发现/Os
标志至少:
- 避免跳转表而支持条件跳转
- 避免循环开始填充
尝试以下示例(https://godbolt.org/z/jvezPd9jM):
void loop(int i, char a[], char b[])
{
char* stop = a + i;
while (a != stop){
*b++ = *a++;
}
}
void jump_table(int i, char a[], char b[])
{
switch (i)
{
case 7:
a[6] = b[6]; case 6:
a[5] = b[5]; case 5:
a[4] = b[4]; case 4:
a[3] = b[3]; case 3:
a[2] = b[2]; case 2:
a[1] = b[1]; case 1:
a[0] = b[1]; case 0: break;
default: __assume(false);
}
}
这会导致更频繁地遇到JCC性能问题(避免跳表会产生一系列JCC,避免对齐会导致小于16b的小循环有时还会触及边界)
这篇关于英特尔JCC错误-用于缓解的前缀有何影响?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!