【问题标题】:Why is Intel Haswell XEON CPU sporadically miscomputing FFTs and ART?为什么 Intel Haswell XEON CPU 偶尔会错误计算 FFT 和 ART?
【发布时间】:2016-04-24 17:02:15
【问题描述】:

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

在写可能的错误之前,让我先概述一下使用的硬件、程序代码和问题本身。

工作站硬件规格

  • INTEL Xeon E5-2680 V3 2500MHz 30M Cache 12Core
  • 美超微 SC745 BTQ -R1K28B-SQ
  • 4 x 32GB ECC 已注册 DDR4-2133 内存
  • 英特尔 SSD 730 系列 480 GB
  • NVIDIA Tesla C2075
  • NVIDIA 泰坦

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

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

观察问题

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

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

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

识别问题

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

  • (机器 1)英特尔酷睿 i5 四核(2009 年末型号)
  • (Machine2) 在 Intel XEON 6core SandyBridge CPU 上运行的虚拟机

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

所以Prime95Mersenne Community 的人们似乎是第一个发现和识别这个nasty bug 的人。引用的贴子和新闻支持了这种怀疑,即问题只存在于工作量大的情况下。根据我的观察,我可以确认这种行为。

问题

  • 您/社区是否在 Haswell CPU 和 Skylake CPU 上观察到此问题?
  • gcc 会按照默认的 AVX(2) 优化(只要可能),关闭此优化会有所帮助吗?
  • 如何编译我的代码并确保关闭可能受此错误影响的任何优化?到目前为止,我只阅读了有关在 Haswell / Skylake 架构中使用 AVX2 命令集的问题。

解决方案?

好的,我可以关闭所有 AVX2 优化。但这会减慢我的代码速度。英特尔可能会向主板制造商发布 BIOS 更新,以修改英特尔 CPU 中的微码。由于这似乎是一个硬件错误,即使通过更新 CPU 微码,这也可能会变得有趣。我认为这可能是一个有效的选择,因为 Intel CPU 使用一些由 Microcode 控制的 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 正在运行并测试内存。由于这似乎需要相当长的时间才能完成,我将在明天更新帖子并提供结果。

EDIT3:截至目前(21.01.2016 09:35 CET)Memtest86+ 完成了两次运行并通过了。甚至没有一个内存错误。将 CPU 的微码从 revision=0x2d 更新为 revision=0x36。目前正在准备这里发布的源代码。错误结果的问题在于。由于我不是相关代码的作者,因此我必须仔细检查不要发布我不允许发布的代码。我也在使用工作站并对其进行维护。

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) 

【问题讨论】:

  • 为什么投反对票?这是一个很好的、有效的问题!我将尝试在等效设置中重现。
  • @specializt 很好,因为他的测试表明,12 个相同的内核中有 11 个没有做同样的事情,尽管他们应该做的事情给了这个设置一些真正的意义。在计算时出现零星的失败是一项艰巨的任务,要提出这样一个“愚蠢”的事情要做,以揭示一些基本的假设(代码在任何内核上的任何负载下对于相同输入的行为都是相同的)是错误的.
  • 他可能会或可能不会通过无意义的冗余操作发现硬件错误(非常不可能)或硬件缺陷(非常可能)这一事实并没有使该方法变得更聪明。他目前所经历的被称为“运气”——他也会在运行数天的 IBT 或 prime95 等 CPU 密集型测试工具上发现相同的问题。 @semm0 :下载并运行 IBT - 如果您的机器锁定,您就知道问题与散热有关,甚至是硬件缺陷 - 在这两种情况下,零星的计算错误都很常见。
  • “无特殊编译参数”。你怎么知道?你有什么编译选项?你说“正如 gcc 所做的默认 AVX(2) 优化”。不,不是的。它仅在 64 位模式下默认使用 SSE2。您一定添加了一些选项。您问“关闭此优化会有所帮助吗?”你为什么不测试一下?再次说明您的编译选项以及您的编译器和版本。
  • 您的代码是否使用任何全局状态变量?如果是这样,那么即使多个线程运行相同的函数并且如果它们写入全局状态变量,这也可能会给出错误的结果。

标签: intel cpu-architecture processor avx2


【解决方案1】:

Skylake-S/U prime95 勘误表位于 AVX(不是 AVX2)单元中。它固定在微码 0x56(可能)和 0x6a(肯定)上。 Haswell 中的这种错误不太可能,但可能发生(尤其是在 2014 年后的英特尔,“验证”成为不受欢迎的成本,而不是质量的租户)。

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

您的处理器具有签名 0x306f2。确保您的微码修订版为 0x36 或更高版本,此微码在 2015 年 11 月 6 日的英特尔“Linux 微码更新包”中。

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

【讨论】:

  • 感谢您的回答。目前正在从上面收集 cmets 所需的所有信息。关于微码的信息(此信息稍后将作为附加“编辑”添加到原始问题中):微码:CPU0 sig=0x306f2, pf=0x1, revision=0x2d
  • 请更新该微码并重新测试...您可以直接在 Debian 或 Ubuntu Xenial Xerus 中使用更新的“intel-microcode”包:只需下载“.deb”来自 Debian 或 Ubuntu,然后“dpkg -i”。确保 initramfs 已更新,然后重新启动。并且向 Supermicro 投诉,让他们更新他们的 BIOS。
  • 好的,已安装微码更新:微码:CPU0 sig=0x306f2, pf=0x1, revision=0x36 抱歉,学期的最后一周有一些学生报告正在进行。现在将重新开始计算以查看结果。我会尽量在 4 到 5 小时内让你更新。
  • 微码更新后问题依然存在。需要睡觉... 9 小时后回来。
  • @semm0,你还没有说明你的编译选项。
【解决方案2】:

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

经验教训:

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

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

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

  2. 在这台机器上进行多次测试后,结果仍然错误。其他(i5、i7、XEON)机器产生了正确的结果。

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

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

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

很抱歉怀疑这是一个 CPU 错误

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

【讨论】:

  • 您是否尝试过使用可用的编译器选项进行编译?喜欢-O3 -march=native?这应该会产生另一个 2 到 10 倍的加速,具体取决于内存带宽是否是瓶颈,以及您的代码使用 AVX/AVX2 自动矢量化的程度。用-O0 处理数字是愚蠢的,除非这是您能够重现问题的唯一方法。另请注意,Ubuntu 15.10 自 2015/10 年(当然)就已经发布。我会尝试升级到那个。 (特别是因为较新的编译器,如 gcc 5.2,比旧编译器更好)。
  • 感谢您的评论彼得。通常我使用 CUDA 7.5 进行开发,目前仅在 14.04 或 15.04 上运行 - 我没有在 15.10 上进行测试...谢谢指出编译器优化。以大约 30-40% 的加速开始。
  • 启用优化后是否得到正确的结果?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-16
  • 2021-12-18
  • 2013-09-20
  • 1970-01-01
  • 2015-11-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多