Los intrínsecos SIMD no dan tanto miedo, pero ¿deberíamos usarlos?

¿Es la programación de bajo nivel un pecado o una virtud? Depende.

Al programar para usar el procesamiento de vectores en un procesador moderno, lo ideal sería escribir un código en mi idioma favorito y se ejecutaría lo más rápido posible "automáticamente por arte de magia".

A menos que hayas empezado a programar la semana pasada, sospecho que sabes que no es así como funciona el mundo. El máximo rendimiento solo viene con esfuerzo. De ahí mi pregunta: ¿qué tan bajo deberíamos ir?

Operaciones vectoriales definidas

Una operación "vectorial" es una operación matemática que hace más de una operación. Una suma vectorial puede sumar ocho pares de números en lugar de la suma normal, que solo suma un par de números. Considere pedirle a la computadora que sume dos números. Podemos hacer eso con una instrucción de adición regular. Considere pedirle a la computadora que sume ocho pares de números (calcular C1 = A1 + B1, C2 = A2 + B2,… C8 = A8 + B8). Podemos hacer eso con una instrucción de suma vectorial .

Las instrucciones vectoriales incluyen sumas, restas, multiplicaciones y otras operaciones.

 SIMD: paralelismo para vectores

Los informáticos tienen un nombre elegante para las instrucciones vectoriales: SIMD o "Datos múltiples de instrucción única". Si pensamos en una instrucción de suma regular como un SISD (Instrucción única de datos únicos) donde simple significa un solo par de entradas de datos, entonces una suma vectorial es un SIMD donde múltiple podría significar ocho pares de entradas de datos.

Me gusta llamar a SIMD "el otro paralelismo de hardware", ya que a menudo se piensa que el "paralelismo" en las computadoras proviene de tener múltiples núcleos. Los recuentos de núcleos han aumentado constantemente. Los recuentos de cuatro núcleos son comunes, 20 o más son comunes en los procesadores para servidores, y el recuento de núcleos superior de Intel en la actualidad es de 72 núcleos en un solo procesador Intel® Xeon Phi ™.

Los tamaños de las instrucciones vectoriales también han aumentado. Las primeras instrucciones vectoriales, como SSE, realizaban hasta cuatro operaciones a la vez. El ancho de vector superior de Intel en la actualidad, en AVX-512, realiza hasta 16 operaciones a la vez.

 ¿Qué tan bajo deberíamos ir?

Con tanto desempeño en juego, ¿cuánto trabajo deberíamos hacer para explotar este desempeño?

 La respuesta es mucha, y esta es la razón: cuatro núcleos pueden hacer que tengamos una velocidad 4X como máximo. AVX (la mitad del tamaño de AVX-512, pero mucho más común) puede llevarnos hasta 8X de velocidad como máximo. Combinados, pueden llegar hasta 32X. Hacer ambas cosas tiene mucho sentido.

Aquí está mi simple lista de cómo intentar explotar las instrucciones vectoriales (en el orden en que deberíamos intentar aplicarlas):

 1.     Primero, llame a una biblioteca que haga el trabajo (lo último en vectorización implícita). Un ejemplo de dicha biblioteca es Intel® Math Kernel Library (Intel® MKL). Todo el trabajo para usar instrucciones vectoriales fue realizado por otra persona. Las limitaciones son obvias: tenemos que encontrar una biblioteca que haga lo que necesitamos.

2. En     segundo lugar, utilice la vectorización implícita. Manténgase abstracto y escríbalo usted mismo utilizando plantillas o compiladores como ayuda. Muchos compiladores tienen opciones y conmutadores de vectorización. Es probable que los compiladores sean la forma más portátil y estable de hacerlo. Ha habido muchas plantillas para la vectorización, pero ninguna ha tenido un uso suficiente a lo largo del tiempo para ser un claro ganador (una entrada reciente es Intel® SIMD Data Layout Templates [Intel® SDLT]).

3. En     tercer lugar, utilice la vectorización explícita. Esto se ha vuelto muy popular en los últimos años e intenta resolver el problema de permanecer abstracto pero obligando al compilador a usar instrucciones vectoriales cuando de otra manera no las usaría. El soporte para SIMD en OpenMP es el ejemplo clave aquí, donde las solicitudes de vectorización para el compilador se dan de manera muy explícita. Existen extensiones no estándar en muchos compiladores, a menudo en forma de opciones o "pragmas". Si toma esta ruta, OpenMP es el camino a seguir si está en C, C ++ o Fortran.

4.     Finalmente, baje y ensucie. Utilice intrínsecos SIMD. Es como lenguaje ensamblador, pero escrito dentro de su programa C / C ++. Los intrínsecos SIMD en realidad se ven como una llamada de función, pero generalmente producen una sola instrucción (una instrucción de operación vectorial, también conocida como instrucción SIMD).

Los elementos intrínsecos de SIMD no son malos; sin embargo, son un último recurso. Las primeras tres opciones son siempre más fáciles de mantener para el futuro cuando funcionan. Sin embargo, cuando los tres primeros no satisfacen nuestras necesidades, definitivamente deberíamos intentar usar los intrínsecos SIMD.

 Si desea comenzar a usar los intrínsecos SIMD, tendrá una gran ventaja si está acostumbrado a la programación en lenguaje ensamblador. Principalmente, esto se debe a que le resultará más fácil leer la documentación que explica las operaciones, incluida la excelente "Guía de intrínsecos" en línea de Intel. Si eres completamente nuevo en esto, me encontré con un blog reciente ("SSE: ¡cuidado con la brecha!") Que tiene una mano suave en la introducción de intrínsecos. También me gusta "Crunching Numbers with AVX and AVX2".

 Si una biblioteca o un compilador puede hacer lo que necesita, los intrínsecos SIMD no son la mejor opción. Sin embargo, tienen su lugar y no son difíciles de usar una vez que te acostumbras. Pruébalos. Los beneficios de rendimiento pueden ser asombrosos. He visto intrínsecos SIMD utilizados por programadores inteligentes para código que es probable que ningún compilador produzca.

Incluso si probamos los elementos intrínsecos de SIMD y eventualmente dejamos que una biblioteca o compilador haga el trabajo, lo que aprendamos puede ser invaluable para comprender el mejor uso de una biblioteca o compilador para la vectorización. Y esa puede ser la mejor razón para probar los intrínsecos SIMD la próxima vez que necesitemos algo para usar instrucciones vectoriales.

Haga clic aquí para descargar su prueba gratuita de 30 días de Intel Parallel Studio XE