为什么 Intel Haswell XEON CPU 偶尔会错误计算 FFT 和 ART?

Why is Intel Haswell XEON CPU sporadically miscomputing FFTs and ART?

在过去的几天里,我观察到我无法解释的新工作站的行为。对这个问题做了一些研究,INTEL Haswell architecture 以及当前的 Skylake 一代中可能存在错误。

在写可能的BUG之前,先简单介绍一下所用的硬件、程序代码和问题本身。

工作站硬件规格

有问题的操作系统和程序代码

我目前正在 运行ning Ubuntu 15.04 64 位桌面版,安装了最新更新和内核内容。除了用这台机器开发 CUDA Kernels 之类的,我最近测试了一个纯 C 程序。 该程序正在对相当大的输入数据集进行某种修改 ART。所以代码执行了一些 FFT 并消耗了相当多的时间来完成计算。我目前无法 post / link 到任何来源 代码,因为这是正在进行的研究,无法发表。如果您不熟悉 ART,请简单解释一下它的作用。 ART 是一种用于重建从计算机断层扫描仪接收到的数据以获得 用于诊断的可见图像。所以我们的代码版本重建了大小为 2048x2048x512 的数据集。到目前为止,没有什么太特别的,也没有涉及火箭科学。经过几个小时的调试和修复错误后,代码通过了测试 根据参考结果,我们可以确认代码按预期工作。代码使用的唯一库是标准库 math.h 。没有特殊的编译参数,没有可能带来额外 问题 .

的额外库内容

观察问题

该代码使用一种技术来实现 ART,以最大限度地减少重建数据所需的投影。所以让我们假设我们可以重建一个包含 25 个投影的数据切片。代码以 12 个内核上完全相同的输入数据开始。请注意, 实现不是基于多线程,目前启动了 12 个程序实例。我知道这不是最好的方法,强烈建议涉及适当的线程管理,这已经在改进列表中:)

因此,当我们 运行 至少有两个程序实例(每个实例都在一个单独的数据片上工作)时,某些预测的结果以随机方式出现错误。为了让您了解结果,请参见表 1。请注意,输入数据始终相同。

运行只有一个实例代码涉及CPU一个核心,结果全部正确。即使执行一些涉及一个 CPU 核心的 运行s,结果仍然正确。仅涉及至少两个或更多核心会生成如表 1 所示的结果模式。

确定问题

好吧,这花了好几个小时才弄清楚到底出了什么问题。所以我们检查了整个代码,大多数问题都是从一个小的实现错误开始的。但是,嗯,不(当然我们不能证明没有错误,也不能保证)。为了验证我们的代码,我们使用了两台不同的机器:

令人惊讶的是,Machine1 和 Machine2 都总是 产生正确的结果。即使使用所有 CPU 核,结果仍然正确。在每台机器上超过 50 运行s 甚至没有一个错误结果。代码在每台目标机器上编译,没有优化选项或任何特定的编译器设置。 因此,阅读新闻得出以下发现:

Prime95 and the Mersenne Community seem to be the first ones to discover and identify this nasty bug 那边的人。引用的 postings 和新闻支持怀疑,即问题仅在繁重的工作量下存在。根据我的观察,我可以确认这种行为。

问题

解决方案?

好的,我可以关闭所有 AVX2 优化。但这会减慢我的代码速度。 Intel 可能会向主板制造商发布 BIOS 更新,这将修改 Intel CPUs 中的微代码。由于它似乎是一个硬件错误,因此即使更新 CPUs 微码也可能会变得有趣。我认为这可能是一个有效的选择,因为英特尔 CPUs 使用一些 RISC 到 CISC 的翻译机制,由微码控制。

编辑:Techreport.com - Errata prompts Intel to disable TSX in Haswell, early Broadwell CPUs 将检查我的 CPU 中的微码版本。

EDIT2:截至目前(19.01.2016 15:39 CET)Memtest86+ v4.20 运行正在测试内存。由于这似乎需要相当长的时间才能完成,我将在明天更新 post 结果。

EDIT3:截至目前(2016 年 1 月 21 日 09:35 CET)Memtest86+ 完成了两个 运行 并通过了。连一处记忆错误都没有。将 CPU 的微码从 revision=0x2d 更新为 revision=0x36。目前正在准备在这里发布的源代码。结果错误的问题在于。由于我不是相关代码的作者,因此我必须仔细检查是否 post 我不允许的代码。我也在使用工作站并维护它。

EDIT4: (22.01.2016) (12:15 CET) 这是用于编译源代码的 Makefile:

# VARIABLES ==================================================================
CC = gcc
CFLAGS = --std=c99 -Wall
#LDFLAGS = -lm -lgomp   -fast -s -m64 
LDFLAGS = -lm 

OBJ = ArtReconstruction2Min.o


# RULES AND DEPENDENCIES ====================================================

# linking all object files
all: $(OBJ)
  
    $(CC) -o ART2Min $(OBJ) $(LDFLAGS)         

    
# every o-file depends on the corresonding c-file, -g Option bedeutet Debugging Informationene setzen
%.o: %.c
    $(CC)  -c -g $<  $(CFLAGS)
  
    
# MAKE CLEAN =================================================================
clean: 
    rm -f *.o
    rm -f main

gcc -v 输出:

gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.9.2-10ubuntu13' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Ubuntu 4.9.2-10ubuntu13) 

Skylake-S/U prime95 错误在 AVX(不是 AVX2)单元中。它固定在微码 0x56(可能)和 0x6a(肯定)上。 Haswell 中的此类错误不太可能,但有可能(特别是在 post-2014 Intel 上,其中 "validation" 成为不受欢迎的成本,而不是质量的承租人)。

Haswell 链接到 AVX 单元的勘误表,尽管 HSE58 不太可能起作用(它只会减慢 AVX 单元的速度)。但是,请尝试在 AVX2 计算之前放置一些 MFENCE 指令。如果这解决了问题,请立即报告,这意味着我们需要 MFENCE 内核中的所有 IRET (HSE105)。

您的处理器具有签名 0x306f2。确保您的微码版本为 0x36 或更高版本,此微码在 2015-11-06 的 Intel "Linux microcode update pack" 中。

编辑:这并不是真正的回答,所以我应该将其作为评论。我道歉。由于微代码更新不足以解决问题,它仍然可能是一个新的勘误表,一个旧的,但 unworked-around 勘误表,或者完全是其他东西(例如代码错误或 gcc 代码生成错误)。

编辑:问题已解决。我必须向社区大声说声抱歉,并非常感谢您的提示。抱歉匿名用户,他似乎参与了内核开发。发生了什么?我们又花了 2 天时间调试和摆弄程序代码。没有发现实施问题。但是:主要代码涉及另一个帮助程序。该帮助程序按需计算 ART 算法的权重。所以经过调试和测试,这个辅助程序搞砸了,当运行宁至少4个进程。所以这不是内核/硬件问题,而是软件(内存访问)问题。

经验教训:

  1. 调试计算过程中涉及的每个工具。
  2. 微码已过时。 SuperMicro 已获悉此事。
  3. Ubuntu 15.04 可能需要额外的工具,以便 CPU 运行 的所有内核全速运行。通过安装 Ubuntu 14.04 - 所有内核 运行ning 在 2.5GHz 下实现此目的。
  4. 如果我们在会议上见面,我需要喝点啤酒。

经过三天的思考、测试和摆弄机器,我今天发现了以下观察结果:

  1. Ubuntu 15.04 运行s CPU 每核心 420 - 650 MHz。好的,我认为这是一个 Energy-saving 选项,所以我按照各种指南将速度设置为最大值 (2.50 GHz)。它没有用。用 cpufreq-utils.

  2. 检查
  3. 在本机上测试了几次,结果还是不对。其他(i5、i7、XEON)机器产生了正确的结果。

  4. 我读到其他用户遇到了 Ubuntu 15.04 和 CPU 频率的问题。所以我决定插入SSD并安装Ubuntu 14.04。再次检查现在 CPU 的频率是多少……它显示了 2.50 GHz,正如我所期望的那样。

  5. 再次启动重建算法(现在比 Ubuntu 15.04 快 4-5 倍)并等待结果。好的。现在结果正确!我仔细检查,启动了 9 个进程并比较了结果。还是正确的。

所以我只能假设 Ubuntu 15.04 / 内核在这个 CPU 中使用 Speedstep 可能有问题。 CPU 15.04 运行 一直在 420 - 650 MHz 之间,而最小 CPU 速度预计为 1,20 GHz,最大 CPU 速度为 3, 30 GHz。如果有人想要检查,我可以提供导致这个问题的源代码和示例数据。

抱歉怀疑这是一个 CPU bug

编辑:经过更多测试后,问题仅在某些情况下得到解决,但尚未解决所有情况。我会做更多的测试。