Micro fusion y modos de direccionamiento


He encontrado algo inesperado (para mí) usando el Intel® Architecture Code Analyzer (IACA).

La siguiente instrucción usando [base+index] direccionamiento

addps xmm1, xmmword ptr [rsi+rax*1]

No micro-fusible según IACA. Sin embargo, si utilizo [base+offset] así

addps xmm1, xmmword ptr [rsi]

IACA informa que se fusiona.

La sección 2-11 del Intel optimization reference manual da el siguiente ejemplo "de micro-operaciones micro-fusionadas que pueden ser manejadas por todos decodificadores "

FADD DOUBLE PTR [RDI + RSI*8]

Y El manual de ensamblaje de optimización de Agner Fog también da ejemplos de fusión de micro-op usando [base+index] direccionamiento. Véase, por ejemplo, la sección 12.2 "El mismo ejemplo en Core2". Entonces, ¿cuál es la respuesta correcta?

Author: Tom Zych, 2014-09-25

4 answers

En los decodificadores y uop-cache, el modo de direccionamiento no afecta a la micro-fusión (excepto que una instrucción con un operando inmediato no puede micro-fusionar un modo de direccionamiento relativo a RIP).

Pero algunas combinaciones de uop y modo de direccionamiento no pueden permanecer micro-fusionadas en el ROB (en el núcleo fuera de orden), por lo que las CPU de la familia SNB de Intel "no laminan" cuando es necesario, en algún momento antes de la etapa de edición/cambio de nombre. Para el rendimiento de problemas y el tamaño de ventana fuera de orden (ROB-size), cuenta de uop de dominio fusionado después de un-laminación es lo que importa.

El manual de optimización de Intel describe la des-laminación para Sandybridge en Sección 2.3.2.4: Cola de micro-op y el Detector de Flujo de Bucle (LSD), pero no describe los cambios para ninguna microarquitectura posterior.


Las reglas , lo mejor que puedo decir de los experimentos en SnB, HSW, y SKL:

  • SnB (y asumo también IvB): los modos de direccionamiento indexados siempre están sin laminado, otros permanecen micro-fusionado. IACA es (en su mayoría?) correcto.
  • HSW, SKL: Estos solo mantienen una instrucción ALU indexada micro-fusionada si tiene 2 operandos y trata el registro dst como lectura-modificación-escritura. Aquí "operandos" incluye banderas, lo que significa que adc y cmov no micro-fusible. La mayoría de las instrucciones codificadas por VEX tampoco se fusionan ya que generalmente tienen tres operandos (así que paddb xmm0, [rdi+rbx] se fusiona pero vpaddb xmm0, xmm0, [rdi+rbx] no). Finalmente, la instrucción ocasional de 2 operandos donde el primer operando es write only, como pabsb xmm0, [rax + rbx] también no se fusionen. IACA se equivoca al aplicar las reglas del SnB.

Relacionado: los modos de direccionamiento simples (no indexados) son los únicos que la unidad de dirección de tienda dedicada en el puerto 7 (Haswell y posteriores) puede manejar, por lo que todavía es potencialmente útil evitar los modos de direccionamiento indexados para las tiendas. (Un buen truco para esto es dirigirse a su dst con un solo registro, pero src con dst+(initial_src-initial_dst). Entonces solo tienes que incrementar el registro dst dentro de un bucle.)

Tenga en cuenta que algunas instrucciones nunca micro-fusible en absoluto (incluso en los decodificadores/uop-cache). por ejemplo, shufps xmm, [mem], imm8, o vinsertf128 ymm, ymm, [mem], imm8, son siempre 2 uops en SnB a través de Skylake, a pesar de que sus versiones register-source son solo 1 uop. Esto es típico para instrucciones con un operando de control imm8 más los operandos usuales dest/src1, src2 registro/memoria, pero hay algunos otros casos. por ejemplo, PSRLW/D/Q xmm,[mem] (cuenta de desplazamiento vectorial de un operando de memoria) no micro-fusible, y tampoco PMULLD.

Ver también este post en Agner Fog blog para la discusión sobre los límites de rendimiento de problemas en HSW/SKL cuando se leen muchos registros: Mucha micro-fusión con modos de direccionamiento indexados puede conducir a ralentizaciones frente a las mismas instrucciones con menos operandos de registro: modos de direccionamiento de un registro e inmediates. Todavía no conocemos la causa, pero sospecho que hay algún tipo de límite de lectura de registros, tal vez relacionado con la lectura de muchos registros fríos del PRF.


Casos de prueba, números de real medidas : Todos estos micro-fusibles en los decodificadores, AFAIK, incluso si luego son sin-laminado.

# store
mov        [rax], edi  SnB/HSW/SKL: 1 fused-domain, 2 unfused.  The store-address uop can run on port7.
mov    [rax+rsi], edi  SnB: unlaminated.  HSW/SKL: stays micro-fused.  (The store-address can't use port7, though).
mov [buf +rax*4], edi  SnB: unlaminated.  HSW/SKL: stays micro-fused.

# normal ALU stuff
add    edx, [rsp+rsi]  SnB: unlaminated.  HSW/SKL: stays micro-fused.  
# I assume the majority of traditional/normal ALU insns are like add

Instrucciones de tres entradas que HSW / SKL puede tener que des-laminar

vfmadd213ps xmm0,xmm0,[rel buf] HSW/SKL: stays micro-fused: 1 fused, 2 unfused.
vfmadd213ps xmm0,xmm0,[rdi]     HSW/SKL: stays micro-fused
vfmadd213ps xmm0,xmm0,[0+rdi*4] HSW/SKL: un-laminated: 2 uops in fused & unfused-domains.
     (So indexed addressing mode is still the condition for HSW/SKL, same as documented by Intel for SnB)

# no idea why this one-source BMI2 instruction is unlaminated
# It's different from ADD in that its destination is write-only (and it uses a VEX encoding)
blsi   edi, [rdi]       HSW/SKL: 1 fused-domain, 2 unfused.
blsi   edi, [rdi+rsi]   HSW/SKL: 2 fused & unfused-domain.


adc         eax, [rdi] same as cmov r, [rdi]
cmove       ebx, [rdi]   Stays micro-fused.  (SnB?)/HSW: 2 fused-domain, 3 unfused domain.  
                         SKL: 1 fused-domain, 2 unfused.

# I haven't confirmed that this micro-fuses in the decoders, but I'm assuming it does since a one-register addressing mode does.

adc   eax, [rdi+rsi] same as cmov r, [rdi+rsi]
cmove ebx, [rdi+rax]  SnB: untested, probably 3 fused&unfused-domain.
                      HSW: un-laminated to 3 fused&unfused-domain.  
                      SKL: un-laminated to 2 fused&unfused-domain.

Asumo que Broadwell se comporta como Skylake para adc/cmov.

Es extraño que HSW des-lamine la fuente de memoria ADC y CMOV. Tal vez Intel no llegó a cambiar eso de SnB antes de que llegaran a la fecha límite para el envío de Haswell.

La tabla de Agner insn dice cmovcc r,m y adc r,m no micro-fusible en absoluto en HSW/SKL, pero eso no coincide con mis experimentos. Los recuentos de ciclo que estoy midiendo coinciden con el recuento de problemas de uop de dominio fusionado, para un cuello de botella de 4 uops / reloj. Espero que vuelva a comprobarlo y corrija las tablas.

Memoria-dest entero ALU :

add        [rdi], eax  SnB: untested (Agner says 2 fused-domain, 4 unfused-domain (load + ALU  + store-address + store-data)
                       HSW/SKL: 2 fused-domain, 4 unfused.
add    [rdi+rsi], eax  SnB: untested, probably 4 fused & unfused-domain
                       HSW/SKL: 3 fused-domain, 4 unfused.  (I don't know which uop stays fused).
                  HSW: About 0.95 cycles extra store-forwarding latency vs. [rdi] for the same address used repeatedly.  (6.98c per iter, up from 6.04c for [rdi])
                  SKL: 0.02c extra latency (5.45c per iter, up from 5.43c for [rdi]), again in a tiny loop with dec ecx/jnz


adc     [rdi], eax      SnB: untested
                        HSW: 4 fused-domain, 6 unfused-domain.  (same-address throughput 7.23c with dec, 7.19c with sub ecx,1)
                        SKL: 4 fused-domain, 6 unfused-domain.  (same-address throughput ~5.25c with dec, 5.28c with sub)
adc     [rdi+rsi], eax  SnB: untested
                        HSW: 5 fused-domain, 6 unfused-domain.  (same-address throughput = 7.03c)
                        SKL: 5 fused-domain, 6 unfused-domain.  (same-address throughput = ~5.4c with sub ecx,1 for the loop branch, or 5.23c with dec ecx for the loop branch.)

Sí, así es, adc [rdi],eax / dec ecx / jnz ejecuta más rápido que el mismo bucle con add en lugar de adc en SKL. No intenté usar diferentes direcciones, ya que claramente a SKL no le gustan las reescrituras repetidas de la misma dirección (latencia de reenvío de tienda mayor de lo esperado. Ver también este post sobre la repetición de almacenar/recargar a la misma dirección siendo más lento de lo esperado en SKL.

Memory-destination adc es tantos uops porque la familia Intel P6 (y aparentemente la familia SNB) no puede mantener las mismas entradas TLB para todos los uops de una instrucción multi-uop, por lo que necesita un uop adicional para solucionar el problema-caso donde la carga y agregar completa, y luego los errores de almacenamiento, pero el insn no se puede reiniciar simplemente porque CF ya se ha actualizado. Interesante serie de comentarios de Andy Glew (@krazyglew).

Presumiblemente la fusión en los decodificadores y la des-laminación más tarde nos salva de de necesitar microcódigo ROM para producir más de 4 uops de dominio fusionado a partir de una sola instrucción para adc [base+idx], reg.


Por qué los un-laminados de la familia SnB :

Sandybridge simplificó el formato uop interno para ahorrar energía y transistores (junto con hacer el cambio principal al uso de un archivo de registro físico, en lugar de mantener los datos de entrada / salida en el ROB). Las CPU de la familia SnB solo permiten un número limitado de registros de entrada para un uop de dominio fusionado en el núcleo fuera de orden. Para SnB / IvB, ese límite es de 2 entradas (incluidas las banderas). Para HSW y posteriores, el límite es de 3 entradas para un uop. No estoy seguro de si el destino de memoria add y adc están aprovechando al máximo eso, o si Intel para sacar a Haswell de la puerta con algunas instrucciones

Nehalem y anteriores tienen un límite de 2 entradas para un uop de dominio sin fusionar, pero el ROB aparentemente puede rastrear uops micro-fusionados con 3 registros de entrada (el operando de registro sin memoria, base e índice).


Así que los almacenes indexados y las instrucciones de carga de ALU+todavía pueden decodificarse de manera eficiente (sin tener que ser el primer uop en un grupo), y no ocupan espacio adicional en la caché de uop, pero por lo demás las ventajas de la micro-fusión son esencialmente ido para afinar bucles apretados. la"des-laminación" ocurre antes del núcleo fuera de orden de 4 dominios fusionados uops por ciclo de emisión/retirada de ancho. Los contadores de rendimiento de dominio fusionado (uops_issued / uops_retired.retire_slots) contar uops de dominio fundido después de des-laminación.

La descripción de Intel del renamer (Sección 2.3.3.1: Renamer) implica que es la etapa de emisión/cambio de nombre la que realmente realiza la des-laminación, por lo que los uops destinados a la des-laminación aún pueden ser micro-fusionado en el 28/56/64 fusionado-dominio uop issue queue / loop-buffer (también conocido como el IDQ).

TODO: prueba esto. Hacer un bucle que apenas debería caber en el búfer de bucle. Cambie algo para que uno de los uops no esté laminado antes de emitirlo, y vea si todavía se ejecuta desde el búfer de bucle (LSD), o si todos los uops ahora se vuelven a recuperar desde la caché de uop (DSB). Hay contadores de perf para rastrear de dónde vienen los uops, por lo que esto debería ser fácil.

Harder TODO: si ocurre un-laminación entre la lectura de la caché de uop y la adición al IDQ, pruebe si alguna vez puede reducir el ancho de banda de la caché de uop. O si la no laminación ocurre justo en la etapa del problema, ¿puede dañar el rendimiento del problema? (es decir, cómo maneja los uops sobrantes después de emitir los primeros 4.)


(Vea la versión anterior de esta respuesta para algunas conjeturas basadas en afinar algún código LUT, con algunas notas en vpgatherdd siendo aproximadamente 1.7 veces más ciclos que un bucle pinsrw.)

Pruebas Experimentales en SnB

Los números HSW/SKL se midieron en un i5-4210U y un i7-6700k. Ambos tenían HT habilitado (pero el sistema inactivo por lo que el hilo tenía todo el núcleo para sí mismo). Corrí los mismos binarios estáticos en ambos sistemas, Linux 4.10 en SKL y Linux 4.8 en HSW, usando ocperf.py. (El ordenador portátil HSW NFS-montado mi SKL desktop /home.)

Los números SnB se midieron como se describe a continuación, en un i5-2500k que ya no funciona.

Confirmado mediante pruebas con contadores de rendimiento para uops y ciclos.

Encontré una tabla de eventos PMU para Intel Sandybridge, para usar con el comando perf de Linux. (Standard perf desafortunadamente no tiene nombres simbólicos para la mayoría de eventos PMU específicos de hardware, como uops.) Lo utilicé para una respuesta reciente.

ocperf.py proporciona nombres simbólicos para estos eventos PMU específicos de uarch, para que no tenga que buscar tablas. Además, el mismo nombre simbólico funciona en varios uarches. No lo estaba. consciente de ello cuando escribí esta respuesta por primera vez.

Para probar la micro-fusión uop, construí un programa de prueba que está atascado en el límite de dominio fusionado de 4 uops por ciclo de las CPU Intel. Para evitar cualquier contención de puerto de ejecución, muchos de estos uops son nops, que todavía se encuentran en la caché de uop y pasan por la canalización igual que cualquier otro uop, excepto que no se envían a un puerto de ejecución. (Un xor x, same, o un movimiento eliminado, sería lo mismo.)

Programa de pruebas: yasm -f elf64 uop-test.s && ld uop-test.o -o uop-test

GLOBAL _start
_start:
    xor eax, eax
    xor ebx, ebx
    xor edx, edx
    xor edi, edi
    lea rsi, [rel mydata]   ; load pointer
    mov ecx, 10000000
    cmp dword [rsp], 2      ; argc >= 2
    jge .loop_2reg

ALIGN 32
.loop_1reg:
    or eax, [rsi + 0]
    or ebx, [rsi + 4]
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_1reg
;   xchg r8, r9     ; no effect on flags; decided to use NOPs instead

    jmp .out

ALIGN 32
.loop_2reg:
    or eax, [rsi + 0 + rdi]
    or ebx, [rsi + 4 + rdi]
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_2reg

.out:
    xor edi, edi
    mov eax, 231    ;  exit(0)
    syscall

SECTION .rodata
mydata:
db 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff

También encontré que el ancho de banda uop fuera del búfer de bucle no es una constante de 4 por ciclo, si el bucle no es un múltiplo de 4 uops. (es decir, es abc, abc, ...; no abca, bcab, ...). Desafortunadamente, el documento microarch de Agner Fog no estaba claro en esta limitación del búfer de bucle. Ver ¿Se reduce el rendimiento cuando se ejecutan bucles cuyo recuento de uop no es un múltiplo del ancho del procesador? para más investigación sobre HSW/SKL. SnB puede ser peor que HSW en este caso, pero no estoy seguro y todavía no tienen trabajo de hardware SnB.

Quería mantener la macro-fusión (comparar-y-rama) fuera de la imagen, así que usé nop s entre el dec y la rama. Usé 4 nops, por lo que con la micro-fusión, el bucle sería 8 uops, y llenar la tubería con 2 ciclos por 1 iteración.

En la otra versión del bucle, usando modos de direccionamiento de 2 operandos que no micro-fusionan, el bucle será de 10 uops de dominio fusionado, y se ejecutará en 3 ciclo.

Resultados de mi 3.3 GHz Intel Sandybridge (i5 2500k). No hice nada para que el gobernador cpufreq aumentara la velocidad del reloj antes de probar, porque los ciclos son ciclos cuando no interactúas con la memoria. He añadido anotaciones para los eventos de contador de rendimiento que tuve que introducir en hexadecimal.

Probando el modo de direccionamiento 1-reg: no cmdline arg

$ perf stat -e task-clock,cycles,instructions,r1b1,r10e,r2c2,r1c2,stalled-cycles-frontend,stalled-cycles-backend ./uop-test

Performance counter stats for './uop-test':

     11.489620      task-clock (msec)         #    0.961 CPUs utilized
    20,288,530      cycles                    #    1.766 GHz
    80,082,993      instructions              #    3.95  insns per cycle
                                              #    0.00  stalled cycles per insn
    60,190,182      r1b1  ; UOPS_DISPATCHED: (unfused-domain.  1->umask 02 -> uops sent to execution ports from this thread)
    80,203,853      r10e  ; UOPS_ISSUED: fused-domain
    80,118,315      r2c2  ; UOPS_RETIRED: retirement slots used (fused-domain)
   100,136,097      r1c2  ; UOPS_RETIRED: ALL (unfused-domain)
       220,440      stalled-cycles-frontend   #    1.09% frontend cycles idle
       193,887      stalled-cycles-backend    #    0.96% backend  cycles idle

   0.011949917 seconds time elapsed

Probando el modo de direccionamiento 2-reg: con una cmdline arg

$ perf stat -e task-clock,cycles,instructions,r1b1,r10e,r2c2,r1c2,stalled-cycles-frontend,stalled-cycles-backend ./uop-test x

 Performance counter stats for './uop-test x':

         18.756134      task-clock (msec)         #    0.981 CPUs utilized
        30,377,306      cycles                    #    1.620 GHz
        80,105,553      instructions              #    2.64  insns per cycle
                                                  #    0.01  stalled cycles per insn
        60,218,693      r1b1  ; UOPS_DISPATCHED: (unfused-domain.  1->umask 02 -> uops sent to execution ports from this thread)
       100,224,654      r10e  ; UOPS_ISSUED: fused-domain
       100,148,591      r2c2  ; UOPS_RETIRED: retirement slots used (fused-domain)
       100,172,151      r1c2  ; UOPS_RETIRED: ALL (unfused-domain)
           307,712      stalled-cycles-frontend   #    1.01% frontend cycles idle
         1,100,168      stalled-cycles-backend    #    3.62% backend  cycles idle

       0.019114911 seconds time elapsed

Entonces, ambas versiones ejecutaron instrucciones de 80M, y enviaron uops de 60M a los puertos de ejecución. (or con una fuente de memoria envía a una ALU para el or, y un puerto de carga para la carga, independientemente de si estaba micro-fusionada o no en el resto de la tubería. nop no envía a un puerto de ejecución en absoluto.) Del mismo modo, ambas versiones retiran 100M uops de dominio sin fusionar, porque los 40M nops cuentan aquí.

La diferencia está en los contadores para el dominio fusionado.

  1. La versión de dirección de 1 registro solo emite y retira uops de dominio fusionado de 80M. Este es el mismo que el número de instrucciones. Cada insn se convierte en un uop de dominio fusionado.
  2. La versión de 2 direcciones de registro emite 100M uops de dominio fusionado. Este es el mismo que el número de uops de dominio sin fusionar, lo que indica que no se produjo una micro-fusión.

Sospecho que solo verá una diferencia entre UOPS_ISSUED y UOPS_RETIRED(ranuras de retiro utilizado) si los errores de la rama llevaron a uops ser cancelado después de la emisión, pero antes de la jubilación.

Y finalmente, el impacto en el rendimiento es real. La versión no fusionada tomó 1,5 veces más ciclos de reloj. Esto exagera la diferencia de rendimiento en comparación con la mayoría de los casos reales. El bucle tiene que ejecutarse en un número entero de ciclos, y los 2 uops adicionales lo empujan de 2 a 3. A menudo, un uops de dominio fusionado adicional de 2 hará menos diferencia. Y potencialmente no hay diferencia, si el código es embotellado por algo que no sea 4-fusionado-dominio-uops-por-ciclo.

Aún así, el código que hace muchas referencias de memoria en un bucle podría ser más rápido si se implementa con una cantidad moderada de desenrollamiento e incremento de múltiples punteros que se utilizan con un direccionamiento simple [base + immediate offset], en lugar de usar los modos de direccionamiento [base + index].

Cosas posteriores

RIP-relative with an immediate can't micro-fuse . Las pruebas de Agner Fog muestran que este es el caso incluso en el decodificadores / uop-caché, por lo que nunca se fusionan en el primer lugar (en lugar de ser un-laminado).

IACA se equivoca, y afirma que ambos micro-fusibles: {[62]]}

cmp dword  [abs mydata], 0x1b   ; fused counters != unfused counters (micro-fusion happened, and wasn't un-laminated).  Uses 2 entries in the uop-cache, according to Agner Fog's testing
cmp dword  [rel mydata], 0x1b   ; fused counters ~= unfused counters (micro-fusion didn't happen)

RIP-rel hace micro-fusible (y permanecer fusible) cuando no hay inmediato, por ejemplo:

or  eax, dword  [rel mydata]    ; fused counters != unfused counters, i.e. micro-fusion happens

La micro-fusión no aumenta la latencia de una instrucción. La carga puede emitirse antes de que la otra entrada esté lista.

ALIGN 32
.dep_fuse:
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    dec ecx
    jg .dep_fuse

Este bucle se ejecuta a 5 ciclos por iteración, debido a la eax cadena dep. No más rápido que una secuencia de or eax, [rsi + 0 + rdi], o mov ebx, [rsi + 0 + rdi] / or eax, ebx. (Las versiones no fusionadas y mov ejecutan el mismo número de uops.) Scheduling / dep checking sucede en el dominio unfused. Los uops recién emitidos entran en el planificador (también conocido como Reservation Station (RS)), así como en el ROB. Dejan el planificador después de enviar (también conocido como ser enviado a una unidad de ejecución), pero permanecen en el ROBO hasta la jubilación. Por lo tanto, la ventana fuera de orden para ocultar la latencia de carga es al menos el tamaño del planificador (54 uops de dominio sin fusionar en Sandybridge, 60 en Haswell, 97 en Skylake).

Micro-fusion no tiene un atajo para la base y el desplazamiento siendo el mismo registro. Un bucle con or eax, [mydata + rdi+4*rdi] (donde rdi se pone a cero) ejecuta tantos uops y ciclos como el bucle con or eax, [rsi+rdi]. Este modo de direccionamiento podría usarse para iterar sobre una matriz de estructuras de tamaño impar que comienzan en una dirección fija. Esto probablemente nunca se usa en la mayoría de los programas, por lo que no es sorprendente que Intel no gastara transistores al permitir que este caso especial de modos de 2 registros se microfusione. (E Intel lo documenta como" modos de direccionamiento indexados " de todos modos, donde se necesita un factor de registro y escala.)


Macro-fusión de un cmp/jcc o dec/jcc crea un uop que permanece como un solo uop incluso en el ciclo-dominio. dec / nop / jge todavía se puede ejecutar en un solo ciclo, pero es de tres uops en lugar de uno.

 28
Author: Peter Cordes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-18 18:55:54

Nota: Desde que escribí esta respuesta, Peter probó Haswell y Skylake también e integró los resultados en la respuesta aceptada anteriormente (en particular, la mayoría de las mejoras que atribuyo a Skylake a continuación parecen haber aparecido en Haswell). Deberías ver esa respuesta para el resumen del comportamiento en las CPU y esta respuesta (aunque no es incorrecta) es principalmente de interés histórico.

Mi prueba indica que en Skylake al menos 1 , el procesador fusiona completamente incluso modos de direccionamiento complejos, a diferencia de Sandybridge.

Es decir, las versiones 1-arg y 2-arg del código publicado anteriormente por Peter se ejecutan en el mismo número de ciclos, con el mismo número de uops enviados y retirados.

Mis resultados:

Estadísticas de contador de rendimiento para ./uop-test:

     23.718772      task-clock (msec)         #    0.973 CPUs utilized          
    20,642,233      cycles                    #    0.870 GHz                    
    80,111,957      instructions              #    3.88  insns per cycle        
    60,253,831      uops_executed_thread      # 2540.344 M/sec                  
    80,295,685      uops_issued_any           # 3385.322 M/sec                  
    80,176,940      uops_retired_retire_slots # 3380.316 M/sec                  

   0.024376698 seconds time elapsed

Estadísticas de contador de rendimiento para ./uop-test x:

     13.532440      task-clock (msec)         #    0.967 CPUs utilized          
    21,592,044      cycles                    #    1.596 GHz                    
    80,073,676      instructions              #    3.71  insns per cycle        
    60,144,749      uops_executed_thread      # 4444.487 M/sec                  
    80,162,360      uops_issued_any           # 5923.718 M/sec                  
    80,104,978      uops_retired_retire_slots # 5919.478 M/sec                  

   0.013997088 seconds time elapsed

Estadísticas de contador de rendimiento para ./uop-test x x:

     16.672198      task-clock (msec)         #    0.981 CPUs utilized          
    27,056,453      cycles                    #    1.623 GHz                    
    80,083,140      instructions              #    2.96  insns per cycle        
    60,164,049      uops_executed_thread      # 3608.645 M/sec                  
   100,187,390      uops_issued_any           # 6009.249 M/sec                  
   100,118,409      uops_retired_retire_slots # 6005.112 M/sec                  

   0.016997874 seconds time elapsed

No encontré ninguna UOPS_RETIRED_ANY instrucción en Skylake, solo el tipo" ranuras retirados " que es aparentemente fusionada-dominio.

La prueba final (uop-test x x) es una variante que Peter sugiere que usa un RIP-relative cmp con immediate, que no se sabe que microfuse:

.loop_riprel
    cmp dword [rel mydata], 1
    cmp dword [rel mydata], 2
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_riprel

Los resultados muestran que los 2 uops adicionales por ciclo son recogidos por los contadores uops emitidos y retirados (por lo tanto, la prueba puede diferenciar entre fusión que ocurre y no).

Más pruebas en otras arquitecturas son ¡bienvenido! Puedes encontrar el código (copiado de Peter arriba) en github .


[1] ... y quizás algunas otras arquitecturas entre Skylake y Sandybridge, ya que Peter solo probó SB y yo solo probé SKL.

 8
Author: BeeOnRope,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-18 02:42:39

Los procesadores Intel más antiguos sin caché uop pueden hacer la fusión, así que tal vez esto sea un inconveniente de la caché uop. No tengo tiempo para probar esto ahora, pero agregaré una prueba para uop fusion la próxima vez que actualice mis scripts de prueba . ¿Has intentado con las instrucciones de FMA? Son las únicas instrucciones que permiten 3 dependencias de entrada en una uop no fusionada.

 5
Author: A Fog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-12 05:49:16

Ahora he revisado los resultados de las pruebas de Intel Sandy Bridge, Ivy Bridge, Haswell y Broadwell. No he tenido acceso a la prueba en un Skylake todavía. Los resultados son:

  • Las instrucciones con direccionamiento de dos registros y tres dependencias de entrada se están fusionando perfectamente. Solo toman una entrada en la caché de micro-operación siempre y cuando no contengan más de 32 bits de datos (o 2 * 16 bits).
  • Es posible hacer instrucciones con cuatro dependencias de entrada, usando fusionado instrucciones de multiplicar y agregar en Haswell y Broadwell. Estas instrucciones aún se fusionan en un solo micro-op y solo toman una entrada en el caché de micro-op.
  • Las instrucciones con más de 32 bits de datos, por ejemplo, la dirección de 32 bits y los datos inmediatos de 8 bits aún pueden fusionarse, pero usan dos entradas en la caché de microoperaciones (a menos que los 32 bits se puedan comprimir en un entero con signo de 16 bits)
  • Las instrucciones con direccionamiento relativo rip y una constante inmediata no se fusionan, incluso si tanto el desplazamiento como la constante inmediata son muy pequeños.
  • Todos los resultados son idénticos en las cuatro máquinas analizadas.
  • Las pruebas se realizaron con mis propios programas de prueba utilizando los contadores de monitoreo de rendimiento en bucles que eran lo suficientemente pequeños como para caber en la caché de micro-op.

Sus resultados pueden deberse a otros factores. No he intentado usar la IACA.

 5
Author: A Fog,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-01 14:54:01