c++ c performance assembly iaca

c++ - ¿Qué es IACA y cómo lo uso?



performance assembly (1)

Encontré esta herramienta poderosa e interesante llamada IACA (Intel Architecture Code Analyzer) , pero tengo problemas para entenderla. ¿Qué puedo hacer con él, cuáles son sus limitaciones y cómo puedo:

  • Úselo para analizar el código en C o C ++?
  • Úselo para analizar el código en el ensamblador x86?

2017-11 : Lanzamiento de la versión 3.0 (a partir de 2017-11-03)

2017-03 : lanzamiento de la versión 2.3

Lo que es:

IACA (Intel Architecture Code Analyzer) es una herramienta gratuita de análisis estático de código abierto creada por Intel para analizar estáticamente la programación de instrucciones cuando se ejecuta con procesadores Intel modernos. Esto le permite calcular, para un fragmento dado,

  • En el modo de rendimiento , el rendimiento máximo ( el fragmento se supone que es el cuerpo de un ciclo interno )
  • En modo Latencia , la latencia mínima desde la primera instrucción hasta la última.
  • En modo Trace , imprime el progreso de las instrucciones a través de sus etapas de pipeline.

cuando se asumen las condiciones de ejecución óptimas (todos los accesos de memoria golpean la memoria caché L1 y no hay fallas de página).

IACA es compatible con las programaciones informáticas para los procesadores Nehalem, Westmere, Sandy Bridge, Ivy Bridge, Haswell, Broadwell y Skylake a partir de la versión 2.3 y Haswell, Broadwell y Skylake a partir de la versión 3.0.

IACA es una herramienta de línea de comandos que produce informes de texto ASCII y diagramas de Graphviz. Las versiones 2.1 y siguientes admiten Linux de 32 y 64 bits, Mac OS X y Windows y análisis de código de 32 y 64 bits; La versión 2.2 y superior solo admiten sistemas operativos de 64 bits y análisis de código de 64 bits.

Cómo usarlo:

La entrada de IACA es un binario compilado de su código, en el cual se han inyectado dos marcadores : un marcador de inicio y un marcador final . Los marcadores hacen que el código no se pueda ejecutar, pero permiten que la herramienta encuentre rápidamente las piezas de código relevantes y las analice.

No necesita la capacidad de ejecutar el binario en su sistema; De hecho, el binario suministrado a IACA no se puede ejecutar de todos modos debido a la presencia de los marcadores inyectados en el código. IACA solo requiere la capacidad de leer el binario que se analizará. Por lo tanto, es posible, utilizando IACA, analizar un binario Haswell empleando instrucciones FMA en una máquina Pentium III.

C / C ++

En C y C ++, uno obtiene acceso a las macros de inyección de marcadores con #include "iacaMarks.h" , donde iacaMarks.h es un encabezado que se envía con la herramienta en el subdirectorio include/ .

Luego, uno inserta los marcadores alrededor del bucle de interés más interno , o el fragmento de interés de línea recta, de la siguiente manera:

/* C or C++ usage of IACA */ while(cond){ IACA_START /* Loop body */ /* ... */ } IACA_END

La aplicación luego se reconstruye de la forma en que lo haría con las optimizaciones habilitadas (en modo de lanzamiento para usuarios de IDE como Visual Studio). El resultado es un binario que es idéntico en todos los aspectos a la versión Release, excepto con la presencia de las marcas, que hacen que la aplicación no se pueda ejecutar.

IACA confía en que el compilador no reordena las marcas excesivamente; Como tal, para tales compilaciones de análisis ciertas optimizaciones poderosas pueden necesitar ser deshabilitadas si reordenan las marcas para incluir código extraño no dentro del ciclo más interno, o excluir código dentro de él.

Asamblea (x86)

Los marcadores de IACA son patrones de byte mágico inyectados en la ubicación correcta dentro del código. Al usar iacaMarks.h en C o C ++, el compilador maneja la inserción de los bytes mágicos especificados por el encabezado en la ubicación correcta. En el montaje, sin embargo, debe insertar manualmente estas marcas. Por lo tanto, uno debe hacer lo siguiente:

; NASM usage of IACA mov ebx, 111 ; Start marker bytes db 0x64, 0x67, 0x90 ; Start marker bytes .innermostlooplabel: ; Loop body ; ... jne .innermostlooplabel ; Conditional branch backwards to top of loop mov ebx, 222 ; End marker bytes db 0x64, 0x67, 0x90 ; End marker bytes

Es crítico para los programadores de C / C ++ que el compilador logre este mismo patrón.

Lo que produce:

Como ejemplo, analicemos el siguiente ejemplo de ensamblador en la arquitectura Haswell :

.L2: vmovaps ymm1, [rdi+rax] ;L2 vfmadd231ps ymm1, ymm2, [rsi+rax] ;L2 vmovaps [rdx+rax], ymm1 ; S1 add rax, 32 ; ADD jne .L2 ; JMP

.L2 inmediatamente antes de la etiqueta .L2 el marcador de inicio e inmediatamente después del marcador final. A continuación, reconstruimos el software e invocamos IACA de esta forma (en Linux, supone que el directorio bin/ está en la ruta, y foo que es un objeto ELF64 que contiene las marcas IACA):

iaca.sh -64 -arch HSW -graph insndeps.dot foo

, produciendo así un informe de análisis del foo binario de 64 bits cuando se ejecuta en un procesador Haswell y un gráfico de las dependencias de instrucciones visibles con Graphviz.

El informe se imprime a la salida estándar (aunque se puede dirigir a un archivo con un -o ). El informe proporcionado para el fragmento de arriba es:

Intel(R) Architecture Code Analyzer Version - 2.1 Analyzed File - ../../../tests_fma Binary Format - 64Bit Architecture - HSW Analysis Type - Throughput Throughput Analysis Report -------------------------- Block Throughput: 1.55 Cycles Throughput Bottleneck: FrontEnd, PORT2_AGU, PORT3_AGU Port Binding In Cycles Per Iteration: --------------------------------------------------------------------------------------- | Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 | --------------------------------------------------------------------------------------- | Cycles | 0.5 0.0 | 0.5 | 1.5 1.0 | 1.5 1.0 | 1.0 | 0.0 | 1.0 | 0.0 | --------------------------------------------------------------------------------------- N - port number or number of cycles resource conflict caused delay, DV - Divider pipe (on port 0) D - Data fetch pipe (on ports 2 and 3), CP - on a critical path F - Macro Fusion with the previous instruction occurred * - instruction micro-ops not bound to a port ^ - Micro Fusion happened # - ESP Tracking sync uop was issued @ - SSE instruction followed an AVX256 instruction, dozens of cycles penalty is expected ! - instruction not supported, was not accounted in Analysis | Num Of | Ports pressure in cycles | | | Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 | | --------------------------------------------------------------------------------- | 1 | | | 1.0 1.0 | | | | | | CP | vmovaps ymm1, ymmword ptr [rdi+rax*1] | 2 | 0.5 | 0.5 | | 1.0 1.0 | | | | | CP | vfmadd231ps ymm1, ymm2, ymmword ptr [rsi+rax*1] | 2 | | | 0.5 | 0.5 | 1.0 | | | | CP | vmovaps ymmword ptr [rdx+rax*1], ymm1 | 1 | | | | | | | 1.0 | | | add rax, 0x20 | 0F | | | | | | | | | | jnz 0xffffffffffffffec Total Num Of Uops: 6

La herramienta señala útilmente que actualmente, el cuello de botella es la interfaz de Haswell y la AGU de los puertos 2 y 3. Este ejemplo nos permite diagnosticar el problema ya que la tienda no está siendo procesada por el Puerto 7, y tomar medidas correctivas.

Limitaciones

IACA no admite algunas instrucciones, que se ignoran en el análisis. No admite procesadores anteriores a Nehalem y no admite bucles no internos en el modo de rendimiento (no tiene capacidad para adivinar qué bifurcación se toma con qué frecuencia y en qué patrón).