Extensión SIMD a C ++ OpenMP en Visual Studio

En la era de las aplicaciones ubicuas de IA, existe una demanda emergente del compilador que acelera el código de aprendizaje automático intensivo en computación para el hardware existente. Tal código usualmente realiza cálculos matemáticos como la transformación y manipulación de matrices y generalmente está en forma de bucles. La extensión SIMD de OpenMP proporciona a los usuarios una forma fácil de acelerar los bucles al aprovechar explícitamente la unidad vectorial de los procesadores modernos. Estamos orgullosos de comenzar a ofrecer la vectorización SIMD C / C ++ OpenMP en Visual Studio 2019.


La interfaz del programa de aplicación OpenMP C / C ++ se diseñó originalmente para mejorar el rendimiento de la aplicación al permitir que el código se ejecute efectivamente en paralelo en múltiples procesadores en la década de 1990. Con los años, el estándar OpenMP se ha ampliado para admitir conceptos adicionales como la paralelización basada en tareas, la vectorización SIMD y la descarga del procesador. Desde 2005, Visual Studio ha admitido el estándar OpenMP 2.0 que se centra en la paralelización multiproceso. A medida que el mundo avanza hacia una era de IA, vemos una oportunidad cada vez mayor para mejorar la calidad del código al expandir el soporte del estándar OpenMP en Visual Studio. Continuamos nuestro viaje en Visual Studio 2019 agregando soporte para OpenMP SIMD.




OpenMP SIMD, introducido por primera vez en el estándar OpenMP 4.0, se dirige principalmente a la vectorización de bucles. Según nuestra investigación, hasta ahora es la función OpenMP más utilizada en el aprendizaje automático. Al anotar un bucle con una directiva SIMD de OpenMP, el compilador puede ignorar las dependencias vectoriales y vectorizar el bucle tanto como sea posible. El compilador respeta la intención de los usuarios de tener múltiples iteraciones de bucle ejecutadas simultáneamente.


#pragma omp simd for (i = 0; i < count; i++) { a[i] = b[i] + 1; } 

Como ya sabrá, C ++ en Visual Studio ya proporciona pragmas de bucle no OpenMP similares, como #pragma vector y #pragma ivdep . Sin embargo, el compilador puede hacer más con OpenMP SIMD. Por ejemplo:


  1. El compilador siempre puede ignorar las dependencias de vectores que están presentes.
  2. / fp: rápido está habilitado dentro del bucle.
  3. Los bucles con llamadas a funciones son vectorizables.
  4. Los bucles externos son vectorizables.
  5. Los bucles anidados se pueden unir en un bucle y vectorizar.
  6. La aceleración híbrida se puede lograr con #pragma omp para simd para permitir la multiprocesamiento de grano grueso y la vectorización de grano fino.

Además, la directiva OpenMP SIMD puede tomar las siguientes cláusulas para mejorar aún más la vectorización:


  • simdlen ( longitud ): especifique el número de carriles vectoriales
  • safelen ( longitud ): especifique la distancia de dependencia del vector
  • linear ( list [ : linear-step] ): la asignación lineal de la variable de inducción de bucle a la suscripción de matriz
  • alineado ( lista [ : alineación] ): la alineación de datos
  • privado ( lista ): especifique la privatización de datos
  • lastprivate ( lista ): especifique la privatización de datos con el valor final de la última iteración
  • reducción ( identificador de reducción : lista ): especifique operaciones de reducción personalizadas
  • colapso ( n ): nido de bucle de fusión

Nuevo -penpen: interruptor experimental


Un programa anotado con OpenMP-SIMD puede compilarse con un nuevo interruptor CL -openmp: experimental. Este nuevo conmutador habilita funciones adicionales de OpenMP que no están disponibles en -openmp . Si bien el nombre de este conmutador es "experimental", el conmutador en sí y la funcionalidad que permite son totalmente compatibles y están listos para la producción. El nombre refleja que no habilita ningún subconjunto o versión completa de un estándar OpenMP. Las iteraciones futuras del compilador pueden usar este modificador para habilitar funciones adicionales de OpenMP y se pueden agregar nuevos modificadores relacionados con OpenMP. El -openmp: interruptor experimental subsume el interruptor -openmp, lo que significa que es compatible con todas las funciones de OpenMP 2.0. Tenga en cuenta que la directiva SIMD y sus cláusulas no se pueden compilar con el modificador -openmp .


Para los bucles que no están vectorizados, el compilador emitirá un mensaje para cada uno de ellos, como se muestra a continuación. Por ejemplo,


cl -O2 -openmp: experimental mycode.cpp


mycode.cpp (84): información C5002: bucle simd Omp no vectorizado debido a la razón '1200'


mycode.cpp (90): información C5002: bucle simd Omp no vectorizado debido a la razón '1200'


Para los bucles vectorizados, el compilador permanece en silencio a menos que se proporcione un interruptor de registro de vectorización:


cl -O2 -openmp: experimental -Qvec-report: 2 mycode.cpp


mycode.cpp (84): información C5002: bucle simd Omp no vectorizado debido a la razón '1200'


mycode.cpp (90): información C5002: bucle simd Omp no vectorizado debido a la razón '1200'


mycode.cpp (96): información C5001: Omp simd loop vectorized


Como primer paso para soportar OpenMP SIMD, básicamente hemos conectado el pragma SIMD con el vectorizador de backend bajo el nuevo interruptor. Nos centramos en vectorizar los bucles más internos mejorando el vectorizador y el análisis de alias. Ninguna de las cláusulas SIMD son efectivas en Visual Studio 2019 en el momento de escribir este artículo. Serán analizados pero ignorados por el compilador con una advertencia emitida para la conciencia del usuario. Por ejemplo, el compilador emitirá


advertencia C4849: se ignora la cláusula 'simdlen' de OpenMP en la directiva 'simd'


para el siguiente código:


 #pragma omp simd simdlen(8) for (i = 1; i < count; i++) { a[i] = a[i-1] + 1; b[i] = *c + 1; bar(i); } 

Más acerca de la semántica de la directiva OpenMP SIMD


La directiva OpenMP SIMD proporciona a los usuarios una forma de dictar el compilador para vectorizar un bucle. El compilador puede ignorar la aparente legalidad de dicha vectorización al aceptar la promesa de corrección de los usuarios. Es responsabilidad de los usuarios cuando ocurre un comportamiento inesperado con la vectorización. Al anotar un bucle con la directiva OpenMP SIMD, los usuarios tienen la intención de ejecutar múltiples iteraciones de bucle simultáneamente. Esto le da al compilador mucha libertad para generar código de máquina que aproveche los recursos SIMD o vectoriales en el procesador de destino. Si bien el compilador no es responsable de explorar la corrección y el beneficio de dicho paralelismo especificado por el usuario, aún debe garantizar el comportamiento secuencial de una iteración de bucle único.


Por ejemplo, el siguiente bucle está anotado con la directiva OpenMP SIMD. No existe un paralelismo perfecto entre las iteraciones de bucle ya que existe una dependencia hacia atrás de un [i] a un [i-1]. Pero debido a la directiva SIMD, el compilador todavía puede empaquetar iteraciones consecutivas de la primera instrucción en una instrucción vectorial y ejecutarlas en paralelo.


 #pragma omp simd for (i = 1; i < count; i++) { a[i] = a[i-1] + 1; b[i] = *c + 1; bar(i); } 

Por lo tanto, la siguiente forma de vector transformada del bucle es legal porque el compilador mantiene el comportamiento secuencial de cada iteración del bucle original. En otras palabras, un [i] se ejecuta después de un [-1], b [i] es después de un [i] y la llamada a la barra ocurre por fin.


 #pragma omp simd for (i = 1; i < count; i+=4) { a[i:i+3] = a[i-1:i+2] + 1; b[i:i+3] = *c + 1; bar(i); bar(i+1); bar(i+2); bar(i+3); } 

Es ilegal mover la referencia de memoria * c fuera del bucle si puede alias con a [i] o b [i] . También es ilegal reordenar las declaraciones dentro de una iteración original si se rompe la dependencia secuencial. Como ejemplo, el siguiente ciclo transformado no es legal.


 c = b; t = *c; #pragma omp simd for (i = 1; i < count; i+=4) { a[i:i+3] = a[i-1:i+2] + 1; bar(i); // illegal to reorder if bar[i] depends on b[i] b[i:i+3] = t + 1; // illegal to move *c out of the loop bar(i+1); bar(i+2); bar(i+3); } 

Planes futuros y comentarios


Le recomendamos que pruebe esta nueva función. Como siempre, agradecemos sus comentarios. Si ve un bucle SIMD de OpenMP que espera que esté vectorizado, pero no lo es o el código generado no es óptimo, infórmenos. Nos puede contactar a través de los comentarios a continuación, por correo electrónico ( visualcpp@microsoft.com ), twitter (@visualc) o por la Comunidad de desarrolladores .


En el futuro, nos encantaría escuchar su necesidad de funcionalidades OpenMP que faltan en Visual Studio. Como ha habido varias evoluciones importantes en OpenMP desde el estándar 2.0, OpenMP ahora tiene características tremendas para facilitar su esfuerzo para crear programas de alto rendimiento. Por ejemplo, la programación de concurrencia basada en tareas está disponible a partir de OpenMP 3.0. La computación heterogénea (CPU + aceleradores) es compatible con OpenMP 4.0. La compatibilidad con la vectorización SIMD avanzada y la paralelización en bucle DOACROSS también están disponibles en el último estándar OpenMP ahora. Consulte las revisiones estándar completas y los conjuntos de características del sitio web oficial de OpenMP: https://www.openmp.org . Le pedimos sinceramente su opinión sobre las características específicas de OpenMP que le gustaría ver. También nos interesa saber cómo está utilizando OpenMP para acelerar su código. Sus comentarios son fundamentales para ayudar a dirigir la dirección del soporte de OpenMP en Visual Studio.


Avatar
Hongtao Yu

Source: https://habr.com/ru/post/446688/


All Articles