为什么英特尔Haswell XEON CPU零星地计算FFT和ART?

在最后几天,我观察到我无法解释的新工作站的行为。 对这个问题做了一些研究, INTEL Haswell架构和当前Skylake Generation中可能存在一个bug。

在撰写关于可能的错误之前,让我给你一个使用的硬件,程序代码和问题本身的概述。

工作站硬件规范

  • 英特尔至强E5-2680 V3 2500MHz 30Mcaching12核
  • Supermicro SC745 BTQ -R1K28B-SQ
  • 4 x 32GB ECC Registered DDR4-2133 Ram
  • INTEL SSD 730系列480 GB
  • NVIDIA Tesla C2075
  • NVIDIA TITAN

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

我目前正在运行Ubuntu 15.04 64位桌面版本,最新的更新和内核的东西安装。 除了使用这台机器开发CUDA内核和东西,我最近testing了一个纯C程序。 该程序正在对相当大的input数据集进行一些修改后的ART 。 所以代码执行一些FFT并花费相当多的时间来完成计算。 我目前无法发布/链接到任何源代码,因为这是正在进行的研究,无法发布。 如果你不熟悉ART ,只是简单的解释一下。 ART是一种技术,用于重build从计算机断层摄影机接收到的数据,以获取可见的图像进行诊断。 所以我们的代码版本重build了像2048x2048x512这样的大小的数据集。 到目前为止,没有什么特别的,也没有涉及火箭科学。 经过几个小时的debugging和修复错误,代码在参考结果上进行了testing,我们可以确认代码的工作原理。 代码使用的唯一的库是标准的math.h 没有特殊的编译参数,没有额外的库的东西,可能会带来额外的问题

观察问题

该代码使用一种技术来实现ART,以最小化重构数据所需的投影。 那么我们假设我们可以重build一个包含25个投影的数据片。 代码在12个内核上以完全相同的input数据启动。 请注意,该实现不是基于multithreading,目前启动了12个程序实例。 我知道这不是最好的办法,涉及适当的线程pipe理是非常build议,这已经在改善列表:)

所以当我们至less运行两个程序实例(每个实例在一个单独的数据切片上运行)时,结果都是随机的,有些预测是错误的。 给你一个结果的想法,请看Table1。 请注意,input数据总是相同的。

只运行一个涉及CPU核心的代码实例,结果都是正确的。 即使执行一个涉及一个CPU内核的运行,结果仍然是正确的。 只有至less包含两个或两个以上的内核才能生成如表1所示的结果模式。

表1:Haswell XEON CPU的随机错误结果

确定问题

好吧,这花了好几个小时才能知道实际发生了什么问题。 所以我们通过了整个代码,其中大部分的问题都是从一个小错误开始的。 但是,没有(当然,我们不能certificate没有错误,也不能保证)。 要validation我们的代码,我们使用了两个不同的机器:

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

令人惊讶的是,Machine1和Machine2都能产生正确的结果。 即使使用所有的CPU核心,结果仍然是正确的。 在每台机器上都不会出现超过50次的错误结果。 代码被编译在每个目标机器上,没有优化选项或任何特定的编译器设置。 所以,阅读这个消息导致了以下的发现:

  • ArsTechnika – 在复杂的工作负载下,Skylake CPU冻结
  • PcWorld – 如何testing您的电脑skylake错误
  • 英特尔社区 – 冻结Skylake处理器的简单指令

所以在Prime95和Mersenne社区的人们似乎是第一个发现和识别这个讨厌的bug的人 。 引用的post和新闻支持怀疑,这个问题只存在于繁重的工作量下。 按照我的观察,我可以证实这种行为。

问题(S)

  • 您/社区是否在Haswell CPU和Skylake CPU上观察到这个问题?
  • 正如gcc默认AVX(2)优化(尽可能),closures这个优化会有帮助吗?
  • 我如何编译我的代码,并确保可能会受到此错误影响的任何优化都将被closures? 到目前为止,我只使用Haswell / Skylake体系结构中的AVX2命令集来读取有关问题。

解决scheme?

好的,我可以closures所有的AVX2优化。 但是这减慢了我的代码。 英特尔可能会向主板制造商发布BIOS更新,以修改英特尔CPU中的微代码。 由于它似乎是一个硬件错误,即使通过更新CPU微码,这也可能变得有趣。 我认为这可能是一个有效的select,因为Intel CPU使用一些RISC来控制由Microcode控制的CISC转换机制。

编辑: Techreport.com – 勘误提示英特尔在Haswell,早期Broadwell CPU中禁用TSX将检查我的CPU中的微码版本。

编辑2:截至目前(19.01.2016 15:39 CET)Memtest86 + v4.20正在运行和testing内存。 由于这似乎需要相当长的一段时间才能完成,因此我会在明天更新这个文章。

编辑3:截至目前(21.01.2016 09:35 CET)Memtest86 +完成了两个运行,并通过。 甚至没有一个内存错误。 将CPU的微代码从revision=0x2drevision=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) 

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

虽然HSE58不太可能在发挥作用(它只会减慢AVX单元),但Haswell 已经将勘误与AVX单元联系在一起。 但是,在AVX2计算之前,请尝试放置一些MFENCE指令。 如果这个修复了,立即报告,这意味着我们需要在内核中使用所有的IRET(HSE105)。

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

编辑:这不是一个真正的答案 ,所以我应该做一个评论,而不是。 我道歉。 由于微码更新不足以解决这个问题,它可能仍然是一个新的勘误,一个旧的,但没有工作的勘误,或完全(如代码错误或海湾合作委员会代码生成错误)的东西。

编辑:问题解决了。 我必须向社区大声疾呼,并且非常感谢你的提示。 很抱歉给匿名用户,谁似乎参与了内核开发。 发生了什么? 我们花了2天时间debugging程序代码。 没有发现执行问题。 但是:主代码涉及另一个帮助程序。 这个帮助程序根据需要计算ARTalgorithm的权重。 所以在debugging和testing之后,这个帮助程序在运行至less4个进程时就搞砸了。 所以这不是内核/硬件问题,而是软件(内存访问)问题。

得到教训:

  1. debugging涉及到计算过程的每个工具。
  2. 微码已经过时了。 SuperMicro被告知这一点。
  3. Ubuntu 15.04可能需要额外的工具,以使CPU的所有内核全速运行。 通过安装Ubuntu 14.04实现了这一点 – 所有内核运行在2.5GHz。
  4. 如果我们在会议上见面,我需要喝点啤酒。

所以经过三天的思考,testing和摆弄机器,我发现了今天的观察:

  1. Ubuntu 15.04以每个内核420-650 MHz运行CPU。 好吧,我认为这是一个节能的select,所以我遵循各种指南设置速度最高(2.50千兆赫)。 它没有工作。 检查与cpufreq-utils

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

  3. 我读过其他用户遇到的Ubuntu 15.04和CPU频率问题。 所以我决定插入一个SSD并安装Ubuntu 14.04。 再次检查CPU频率是什么..它显示了2.50 GHz,如我所料。

  4. 再次启动重buildalgorithm(现在比Ubuntu 15.04快4-5倍),并等待结果。 好的。 结果是正确的吧! 我再次检查,开始了9个过程,并比较了结果。 仍然正确。

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

对不起,怀疑这是一个CPU的错误

编辑:一些更多的testing后,这个问题只解决了一些情况,但还没有。 我会做更多的testing。