Intel修复了JCC的错误,但是问题来了。。。

Intel修复了JCC的错误,但是问题来了。。。

作者:BlogUpdater |  时间:2020-02-18 |  浏览:99 |  评论已关闭 条评论

楔子
近日Intel工程师透露在某些CPU上会出现JCC(Jump Conditional Code)错误。Intel公司已经提出可通过微码更新(MCU)解决此问题,但是带来的坏处是可能会导致性能降级。为此,MSVC团队和Intel通力协作,在编译器中提供了一种软件修复措施来降低Intel MCU的性能影响。

介绍
对于此次JCC错误,有如下三个地方需要注意的:
1. JCC错误到底是什么,它造成的影响是什么?
2. 微码更新可以避免这一错误,它有什么副作用吗?
3. MSVC编译器提供了一些方法来减轻这种副作用。

JCC错误简介
在Intel发布的白皮书中,列出了一些CPU型号,这些CPU在某些情况下可能会发生JCC错误。从技术角度来说,就是某些跳转指令会Overlay到缓存的边界上。这个错误会导致运行在这些CPU上的软件的一些不确定的行为。

微码更新
通过Intel提供的微码更新(MCU)可以避免JCC错误。它的原理如下:
通过微码更新,可以避免跳转指令Overlay到32字节边界上,如下图所示。

微码更新将会影响如下的指令:
> conditional jumps
> macro-fused conditional jumps
> direct unconditional jump
> indirect jump
> direct/indirect call
> return

此次微码更新将通过Windows Update来进行分发,同时,此次微码更新不仅影响Windows操作系统上,也同样影响其他操作系统。
就如同上面所提到的,在安装了这个微码更新的机器上,应用程序的运行时性能会出现降级的现象。基于我们的测试结果,我们看到此次降级的幅度为0%~3%。这一降级幅度在某些测试中还会更高。

MSVC编译器中提供的软件修复
为了降低此次性能降级的影响,我们在MSVC编译器中提供了软件修复方案,软件开发者可以使用[/QIntel-jcc-erratum]编译开关来编译他们的代码。通过测试,我们发现,在启用了这个编译开关进行编译后,我们几乎看不到性能降级了。另外,这个开关会增加3%的二进制代码大小。

如何启用MSVC软件修复方案
从Visual Studio 2019 v16.5 Preview 2开始,开发者就可以使用上面所提到的软件修复方案。具体方法为,在工程属性设置页面的[代码生成]设置里,将下图中的属性设置为[Yes]。

还有一些未文档化的编译器选项可以限制软件修复的影响范围。可以在一些实验中尝试使用这些选项,但是我们可能在将来的发布版本中不再提供它们。
1. /d2QIntel-jcc-erratum-partial: 这个选项表示,仅在函数中循环部分应用软件修复。
2. /d2QIntel-jcc-erratum:: 这个选项表示,仅在文件[file.txt]中指定的函数应用软件修复。
3. /d2QIntel-jcc-erratum-partial:: 这个选项表示,仅在文件[file.txt]中指定的函数中的循环部分应用软件修复。

在文件[file.txt]中指定的函数名称为经过名称修饰后的函数名,以便编译器进行识别。

为了使用这些编译选项,可以在[Additional Options]设置中进行设定,如下图所示:

所有这些编译器开关仅在软件的发布版本中可用,并且和/clr开关不兼容。在多个开关/d2QIntel-jcc-erratum*被使用的情况下,全部处理(所有分支)将会优先于部分处理(循环分支)。如果开关应用在某一个函数上,则处理也会仅应用在该函数上。

这个软件修复方案到底做了什么?
软件修复实现在编译器中,它会尝试检测代码中所有的被影响的跳转指令(这些跳转指令将会覆盖在32字节边界上),然后将它们对切到边界上。具体来说,就是在执行跳转之前,在指令上添加一些段覆盖前缀。被修改后的指令的大小增加了但是增量还是小于15个字节。在某些情况下,前缀指令无法添加的时候,将使用NOP指令。下面的表格展示了编译期在软件修复开启或者未开启的时候生成的代码对比。

在上面的例子中,所有的CMP和JL指令都是[macro-fused]并覆盖在32字节边界上的。软件修复方案通过在块中的第一个指令打上Padding,然后对于MOV指令,添加了0x3E前缀使得CMP指令可以对齐到32字节的边界的起始位置。

关于性能,再说两句
我们分别测试了经过微码更新后和应用了软件修复方案后的性能影响。在我们的测试中使用到如下的测试机器配置:
处理器:Intel Core i9 9900K @ 3.60GHz
操作系统:Windows操作系统的一份私有构建版本
测试套件:SPEC CPU® 2017

基于我们的测试结果,我们看到,应用了微码更新后,我们看到了0%~3%的性能降级。在其他的测试基准平台中,我们甚至看到了高达10%的性能降级。

通过应用我们在编译器中提供的软件修复方案(/QIntel-jcc-erratum),我们看到这种方案显著的消除了这种影响。这个编译器开关应用到了一个应用程序的所有模块上,带来的副作用是二进制代码的大小增加了大概3%。

我们还发现,通过将软件修复方案应用到循环代码部分(/d2QIntel-jcc-erratum-partial开关),性能降级的也同样显著的被消除了,同时我们看到了二进制代码增加的幅度也减小了。从测试结果来看,大概减少了大约1.5%。如果你希望减少修复方案对二进制代码大小的影响并且尽可能的消除性能降级,可以使用[/d2QIntel-jcc-erratum:]和[/d2QIntel-jcc-erratum-partial:]这两个编译开关。

同时,我们也测试了编译开关[/QIntel-jcc-erratum]的性能影响,结果是,因为各个测试工程的代码规模都不一样,我们建议开发者评估[/QIntel-jcc-erratum]开关的影响并选择最合适的开关。

总结
如果你的代码运行在有JCC缺陷的机器上,我们鼓励你测试你的代码性能并采取对应的措施。你还可以使用[Windows Performance Toolkit]或者[Intel VTune Profiler]来对你的代码进行性能测试。同时可以根据Intel发布的白皮书来检测MCU带来的性能降级。如果你的程序代码确实受到影响了,则可以采用[/QIntel-jcc-erratum]编译开关或者上面提到的其他开关重新编译你的代码。

标签:

评论已关闭。