¿Por qué Intel Haswell XEON CPU esporádicamente no funciona correctamente con FFT y ART?
intel xeon e5-2660 v2 (2)
Durante los últimos días observé un comportamiento de mi nueva estación de trabajo que no pude explicar. Investigando un poco sobre este problema, podría haber un posible error en la arquitectura INTEL Haswell , así como en la generación actual de Skylake.
Antes de escribir sobre el posible error, permítame darle una visión general del hardware utilizado, el código del programa y el problema en sí.
Especificación de hardware de estación de trabajo
- INTEL Xeon E5-2680 V3 2500MHz 30M Caché 12Core
- Supermicro SC745 BTQ -R1K28B-SQ
- 4 x 32GB ECC registrado DDR4-2133 Ram
- INTEL SSD 730 Series 480 GB
- NVIDIA Tesla C2075
- NVIDIA TITAN
Código del sistema operativo y del programa en cuestión
Actualmente estoy ejecutando Ubuntu 15.04 versión de escritorio de 64 bits, las últimas actualizaciones y cosas del kernel instaladas. Además de usar esta máquina para desarrollar núcleos CUDA y cosas así, recientemente probé un programa C puro. El programa está haciendo una especie de ART modificado en conjuntos de datos de entrada bastante grandes. Entonces, el código ejecuta algunas FFT y consume bastante tiempo para finalizar el cálculo. Actualmente no puedo publicar / vincular a ningún código fuente ya que esta es una investigación en curso que no se puede publicar. Si no está familiarizado con ART , solo tiene una explicación simple de lo que hace. El TAR es una técnica utilizada para reconstruir los datos recibidos de una máquina de tomógrafo de computadora para obtener imágenes visibles para el diagnóstico. Entonces, nuestra versión del código reconstruye conjuntos de datos de tamaños como 2048x2048x512. Hasta ahora, nada demasiado especial ni ciencia espacial involucrada. Después de algunas horas de errores de corrección y corrección, el código fue probado en los resultados de referencia y podemos confirmar que el código funciona como debe. La única biblioteca que el código está usando es math.h
estándar. Sin parámetros de compilación especiales, sin elementos adicionales de la biblioteca que puedan generar problemas adicionales.
Observando el problema
El código implementa ART utilizando una técnica para minimizar las proyecciones necesarias para reconstruir los datos. Así que supongamos que podemos reconstruir una porción de datos que incluya 25 proyecciones. El código se inicia con exactamente los mismos datos de entrada en 12 núcleos. Tenga en cuenta que la implementación no se basa en subprocesos múltiples, actualmente se lanzan 12 instancias del programa. Sé que esta no es la mejor manera de hacerlo, ya que se recomienda mucho la administración adecuada de subprocesos y esto ya está en la lista de mejoras :)
Por lo tanto, cuando ejecutamos al menos dos instancias del programa (cada instancia trabaja en un segmento de datos separado), los resultados de algunas proyecciones son incorrectos de forma aleatoria. Para darle una idea de los resultados, consulte la Tabla1. Tenga en cuenta que los datos de entrada son siempre los mismos.
Al ejecutar solo una instancia del código que involucra un núcleo de la CPU, los resultados son todos correctos. Incluso realizando algunas ejecuciones que involucran un núcleo de CPU, los resultados siguen siendo correctos. Solo la participación de al menos dos o más núcleos genera un patrón de resultados como se ve en la Tabla1.
Identificando el problema
Bueno, esto tomó algunas horas para tener una idea de lo que realmente está yendo mal. Entonces revisamos todo el código, la mayoría de esos problemas comienzan con un pequeño error de implementación. Pero, bueno, no (por supuesto no podemos probar la ausencia de errores ni garantizarlo). Para verificar nuestro código, usamos dos máquinas diferentes:
- (Máquina1) Intel Core i5 Quad-Core (Modelo de finales de 2009)
- (Machine2) Máquina virtual que se ejecuta en la CPU Intel XEON 6core SandyBridge
sorprendentemente, tanto Machine1 como Machine2 producen siempre resultados correctos. Incluso utilizando todos los núcleos de CPU, los resultados siguen siendo correctos. Ni siquiera un resultado erróneo en más de 50 carreras en cada máquina. El código se compiló en todas las máquinas de destino sin opciones de optimización ni configuraciones de compilación específicas. Entonces, leer las noticias llevó a los siguientes hallazgos:
- ArsTechnika: CPU de Skylake se congela durante una carga de trabajo compleja
- PcWorld: cómo probar tu PC para ver el error de skylake
- Comunidad Intel: instrucciones simples para congelar un procesador Skylake
Así que la gente de Prime95 y la Comunidad Mersenne parecen ser los primeros en descubrir e identificar este desagradable error . Las publicaciones y las noticias mencionadas apoyan la sospecha de que el problema solo existe bajo una gran carga de trabajo. Siguiendo mi observación, puedo confirmar este comportamiento.
Las preguntas)
- ¿Ha observado usted / la comunidad este problema en las CPU Haswell y en las CPU Skylake?
- Como gcc lo hace por optimización AVX (2) por defecto (siempre que sea posible), ¿sería útil desactivar esta optimización?
- ¿Cómo puedo compilar mi código y asegurar que cualquier optimización que pueda verse afectada por este error esté desactivada? Hasta ahora, solo leo sobre un problema usando el conjunto de comandos AVX2 en las arquitecturas Haswell / Skylake.
Soluciones?
De acuerdo, puedo desactivar todas las optimizaciones de AVX2. Pero esto ralentiza mi código. Intel podría lanzar una actualización de la BIOS a los fabricantes de la placa base que modificaría el microcódigo en las CPU de Intel. Como parece ser un error de hardware, esto podría ser interesante incluso al actualizar el microcódigo de la CPU. Creo que podría ser una opción válida, ya que las CPU Intel usan algunos mecanismos de traducción de RISC a CISC controlados por Microcode.
EDITAR: Techreport.com - Errata le pide a Intel que deshabilite TSX en Haswell, las primeras CPU de Broadwell verificarán la versión de microcódigo en mi CPU.
EDIT2: A partir de ahora (19.01.2016 15:39 CET) Memtest86 + v4.20 se está ejecutando y probando la memoria. Como esto parece tomar bastante tiempo para terminar, actualizaré la publicación mañana con los resultados.
EDIT3: A partir de ahora (21.01.2016 09:35 CET) Memtest86 + finalizó dos carreras y pasó. Ni siquiera un error de memoria. Se actualizó el microcódigo de la CPU de revision=0x2d
a revision=0x36
. Actualmente estamos preparando el código fuente para publicar aquí. El problema con los resultados incorrectos consiste. Como yo no soy el autor del código en cuestión, tengo que verificar dos veces para no publicar el código que no tengo permitido. También estoy usando la estación de trabajo y manteniéndola.
EDIT4: (22.01.2016) (12:15 CET) Aquí está el Makefile utilizado para compilar el código fuente:
# 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
y la salida 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)
EDITAR: Problema resuelto. Tengo que gritar una gran disculpa a la comunidad y un gran agradecimiento por tus consejos. Perdón por el usuario anónimo, que parece estar involucrado en el desarrollo del kernel. ¿Que pasó? Pasamos otros 2 días depurando y jugueteando con el código del programa. No se encontraron problemas de implementación. PERO: el código principal implica otro programa auxiliar. Este programa de ayuda calcula ponderaciones para el algoritmo ART bajo demanda. Entonces, después de la depuración y las pruebas, este programa de ayuda se equivocó al ejecutar al menos 4 procesos. Entonces esto NO era un problema Kernel / hardware, sino un problema de software (acceso a la memoria).
Lecciones aprendidas:
- Depure cada herramienta que está involucrada en el proceso de cálculo.
- Microcode estaba desactualizado. SuperMicro está informado sobre esto.
- Ubuntu 15.04 posiblemente necesite herramientas adicionales, para que todos los núcleos de la CPU funcionen a toda velocidad. Logramos esto al instalar Ubuntu 14.04, todos los núcleos funcionando a 2,5 GHz.
- Necesito gastar un poco de cerveza si alguna vez nos encontramos en una conferencia.
Entonces, después de tres días de pensar, probar y juguetear con la máquina, hoy descubrí las siguientes observaciones:
Ubuntu 15.04 ejecuta la CPU con 420 - 650 MHz por Core. De acuerdo, pensé que esta es una opción de ahorro de energía, así que seguí varias guías para establecer la velocidad al máximo (2.50 GHz). No funcionó. Comprobado con
cpufreq-utils
.Los resultados seguían siendo incorrectos después de varias pruebas en esta máquina. Otras máquinas (i5, i7, XEON) produjeron resultados correctos.
Leí que otros usuarios experimentaron problemas con Ubuntu 15.04 y la frecuencia de la CPU. Así que decidí conectar un SSD e instalar Ubuntu 14.04. Comprobé nuevamente qué frecuencia de CPU es ahora ... y mostró 2.50 GHz como esperaba.
De nuevo comenzó el algoritmo de reconstrucción (que ahora era como 4-5 veces más rápido que en Ubuntu 15.04) y esperó los resultados. Bueno. ¡Los resultados son correctos ahora! Comprobé dos veces, comencé 9 procesos y comparé los resultados. Aún correcto
Así que solo puedo suponer que podría haber un problema en Ubuntu 15.04 / Kernel usando Speedstep en esta CPU. La CPU en 15.04 funcionó todo el tiempo entre 420 - 650 MHz, mientras que la velocidad mínima de la CPU es de 1,20 GHz y la velocidad máxima de la CPU es de 3,30 GHz. Si alguien quiere el cheque, puedo ofrecer el código fuente y los datos de ejemplo que conducen a este problema.
Perdón por sospechar que esto sea un error de la CPU.
EDITAR: después de algunas pruebas más, el problema solo se resuelve para algunos escenarios pero aún no para todos. Haré más pruebas.
La errata Skylake-S / U prime95 está en la unidad AVX (no AVX2). Se fija en los microcódigos 0x56 (probablemente) y 0x6a (seguro). Tal errata en Haswell es poco probable, pero posible (especialmente en Intel después de 2014, donde la "validación" se convirtió en un costo no deseado en lugar de un inquilino para la calidad).
Haswell tiene una errata vinculada a la unidad AVX, aunque es poco probable que HSE58 esté en juego (solo ralentiza la unidad AVX). Sin embargo, intente colocar algunas instrucciones MFENCE antes de los cálculos AVX2. Si esto lo soluciona, repórtelo de inmediato, significa que necesitamos MENTAR todo IRET en el kernel (HSE105).
Su procesador tiene firma 0x306f2. Asegúrese de tener la revisión de microcódigo 0x36 o posterior, este microcódigo se encuentra en el "paquete de actualización de microcódigo de Linux" de Intel del 2015-11-06.
EDITAR: esta no era realmente una respuesta , por lo que debería haber hecho un comentario. Pido disculpas. Como la actualización del microcódigo no fue suficiente para solucionar el problema, aún podría tratarse de una nueva errata, una errata antigua pero no procesada, o algo completamente distinto (como error de código o error de generación de código de gcc).