Anomalía significativa en el rendimiento de FMA experimentada en el procesador Intel Broadwell
Código1:
vzeroall
mov rcx, 1000000
startLabel1:
vfmadd231ps ymm0, ymm0, ymm0
vfmadd231ps ymm1, ymm1, ymm1
vfmadd231ps ymm2, ymm2, ymm2
vfmadd231ps ymm3, ymm3, ymm3
vfmadd231ps ymm4, ymm4, ymm4
vfmadd231ps ymm5, ymm5, ymm5
vfmadd231ps ymm6, ymm6, ymm6
vfmadd231ps ymm7, ymm7, ymm7
vfmadd231ps ymm8, ymm8, ymm8
vfmadd231ps ymm9, ymm9, ymm9
vpaddd ymm10, ymm10, ymm10
vpaddd ymm11, ymm11, ymm11
vpaddd ymm12, ymm12, ymm12
vpaddd ymm13, ymm13, ymm13
vpaddd ymm14, ymm14, ymm14
dec rcx
jnz startLabel1
Código2:
vzeroall
mov rcx, 1000000
startLabel2:
vmulps ymm0, ymm0, ymm0
vmulps ymm1, ymm1, ymm1
vmulps ymm2, ymm2, ymm2
vmulps ymm3, ymm3, ymm3
vmulps ymm4, ymm4, ymm4
vmulps ymm5, ymm5, ymm5
vmulps ymm6, ymm6, ymm6
vmulps ymm7, ymm7, ymm7
vmulps ymm8, ymm8, ymm8
vmulps ymm9, ymm9, ymm9
vpaddd ymm10, ymm10, ymm10
vpaddd ymm11, ymm11, ymm11
vpaddd ymm12, ymm12, ymm12
vpaddd ymm13, ymm13, ymm13
vpaddd ymm14, ymm14, ymm14
dec rcx
jnz startLabel2
Código3 (igual que Código2 pero con prefijo VEX largo):
vzeroall
mov rcx, 1000000
startLabel3:
byte 0c4h, 0c1h, 07ch, 059h, 0c0h ;long VEX form vmulps ymm0, ymm0, ymm0
byte 0c4h, 0c1h, 074h, 059h, 0c9h ;long VEX form vmulps ymm1, ymm1, ymm1
byte 0c4h, 0c1h, 06ch, 059h, 0d2h ;long VEX form vmulps ymm2, ymm2, ymm2
byte 0c4h, 0c1h, 06ch, 059h, 0dbh ;long VEX form vmulps ymm3, ymm3, ymm3
byte 0c4h, 0c1h, 05ch, 059h, 0e4h ;long VEX form vmulps ymm4, ymm4, ymm4
byte 0c4h, 0c1h, 054h, 059h, 0edh ;long VEX form vmulps ymm5, ymm5, ymm5
byte 0c4h, 0c1h, 04ch, 059h, 0f6h ;long VEX form vmulps ymm6, ymm6, ymm6
byte 0c4h, 0c1h, 044h, 059h, 0ffh ;long VEX form vmulps ymm7, ymm7, ymm7
vmulps ymm8, ymm8, ymm8
vmulps ymm9, ymm9, ymm9
vpaddd ymm10, ymm10, ymm10
vpaddd ymm11, ymm11, ymm11
vpaddd ymm12, ymm12, ymm12
vpaddd ymm13, ymm13, ymm13
vpaddd ymm14, ymm14, ymm14
dec rcx
jnz startLabel3
Código4 (igual que Código1 pero con registros xmm):
vzeroall
mov rcx, 1000000
startLabel4:
vfmadd231ps xmm0, xmm0, xmm0
vfmadd231ps xmm1, xmm1, xmm1
vfmadd231ps xmm2, xmm2, xmm2
vfmadd231ps xmm3, xmm3, xmm3
vfmadd231ps xmm4, xmm4, xmm4
vfmadd231ps xmm5, xmm5, xmm5
vfmadd231ps xmm6, xmm6, xmm6
vfmadd231ps xmm7, xmm7, xmm7
vfmadd231ps xmm8, xmm8, xmm8
vfmadd231ps xmm9, xmm9, xmm9
vpaddd xmm10, xmm10, xmm10
vpaddd xmm11, xmm11, xmm11
vpaddd xmm12, xmm12, xmm12
vpaddd xmm13, xmm13, xmm13
vpaddd xmm14, xmm14, xmm14
dec rcx
jnz startLabel4
Code5 (igual que Code1 pero con vpsubd`s que no es cero):
vzeroall
mov rcx, 1000000
startLabel5:
vfmadd231ps ymm0, ymm0, ymm0
vfmadd231ps ymm1, ymm1, ymm1
vfmadd231ps ymm2, ymm2, ymm2
vfmadd231ps ymm3, ymm3, ymm3
vfmadd231ps ymm4, ymm4, ymm4
vfmadd231ps ymm5, ymm5, ymm5
vfmadd231ps ymm6, ymm6, ymm6
vfmadd231ps ymm7, ymm7, ymm7
vfmadd231ps ymm8, ymm8, ymm8
vfmadd231ps ymm9, ymm9, ymm9
vpsubd ymm10, ymm10, ymm11
vpsubd ymm11, ymm11, ymm12
vpsubd ymm12, ymm12, ymm13
vpsubd ymm13, ymm13, ymm14
vpsubd ymm14, ymm14, ymm10
dec rcx
jnz startLabel5
Código6b: (revisado, operandos de memoria solo para vpaddds)
vzeroall
mov rcx, 1000000
startLabel6:
vfmadd231ps ymm0, ymm0, ymm0
vfmadd231ps ymm1, ymm1, ymm1
vfmadd231ps ymm2, ymm2, ymm2
vfmadd231ps ymm3, ymm3, ymm3
vfmadd231ps ymm4, ymm4, ymm4
vfmadd231ps ymm5, ymm5, ymm5
vfmadd231ps ymm6, ymm6, ymm6
vfmadd231ps ymm7, ymm7, ymm7
vfmadd231ps ymm8, ymm8, ymm8
vfmadd231ps ymm9, ymm9, ymm9
vpaddd ymm10, ymm10, [mem]
vpaddd ymm11, ymm11, [mem]
vpaddd ymm12, ymm12, [mem]
vpaddd ymm13, ymm13, [mem]
vpaddd ymm14, ymm14, [mem]
dec rcx
jnz startLabel6
Code7: (igual que Code1 pero vpaddds usa ymm15)
vzeroall
mov rcx, 1000000
startLabel7:
vfmadd231ps ymm0, ymm0, ymm0
vfmadd231ps ymm1, ymm1, ymm1
vfmadd231ps ymm2, ymm2, ymm2
vfmadd231ps ymm3, ymm3, ymm3
vfmadd231ps ymm4, ymm4, ymm4
vfmadd231ps ymm5, ymm5, ymm5
vfmadd231ps ymm6, ymm6, ymm6
vfmadd231ps ymm7, ymm7, ymm7
vfmadd231ps ymm8, ymm8, ymm8
vfmadd231ps ymm9, ymm9, ymm9
vpaddd ymm10, ymm15, ymm15
vpaddd ymm11, ymm15, ymm15
vpaddd ymm12, ymm15, ymm15
vpaddd ymm13, ymm15, ymm15
vpaddd ymm14, ymm15, ymm15
dec rcx
jnz startLabel7
Código8: (igual que Code7 pero usa xmm en lugar de ymm)
vzeroall
mov rcx, 1000000
startLabel8:
vfmadd231ps xmm0, ymm0, ymm0
vfmadd231ps xmm1, xmm1, xmm1
vfmadd231ps xmm2, xmm2, xmm2
vfmadd231ps xmm3, xmm3, xmm3
vfmadd231ps xmm4, xmm4, xmm4
vfmadd231ps xmm5, xmm5, xmm5
vfmadd231ps xmm6, xmm6, xmm6
vfmadd231ps xmm7, xmm7, xmm7
vfmadd231ps xmm8, xmm8, xmm8
vfmadd231ps xmm9, xmm9, xmm9
vpaddd xmm10, xmm15, xmm15
vpaddd xmm11, xmm15, xmm15
vpaddd xmm12, xmm15, xmm15
vpaddd xmm13, xmm15, xmm15
vpaddd xmm14, xmm15, xmm15
dec rcx
jnz startLabel8
Relojes TSC medidos con Turbo y C1E desactivados:
Haswell Broadwell Skylake
CPUID 306C3, 40661 306D4, 40671 506E3
Code1 ~5000000 ~7730000 ->~54% slower ~5500000 ->~10% slower
Code2 ~5000000 ~5000000 ~5000000
Code3 ~6000000 ~5000000 ~5000000
Code4 ~5000000 ~7730000 ~5500000
Code5 ~5000000 ~7730000 ~5500000
Code6b ~5000000 ~8380000 ~5500000
Code7 ~5000000 ~5000000 ~5000000
Code8 ~5000000 ~5000000 ~5000000
¿Alguien puede explicar qué sucede con Code1 en Broadwell?Supongo que Broadwell de alguna manera contamina el Puerto 1 con vpaddds en el caso del Código 1, sin embargo, Haswell puede usar el Puerto 5 solo si el Puerto 0 y el Puerto 1 están llenos;
¿Tienes alguna idea para lograr el ~ 5000000 clk en Broadwell con instrucciones de FMA?
Traté de reordenar. Comportamiento similar experimentado con double y qword;
Usé Windows 8.1 y Win 10;
Actualizar:Se agregó Code3 como la idea de Marat Dukhan con VEX largo;
Extendió la tabla de resultados con las experiencias de Skylake;
Subió un código de muestra de comunidad + MASM VS2015aquí
Actualización2:Intenté con registros xmm en lugar de ymm (Código 4). Mismo resultado en Broadwell.
Actualización3:Agregué Code5 como idea de Peter Cordes (sustituya vpaddd`s con otras instrucciones (vpxor, vpor, vpand, vpandn, vpsubd)). Si la nueva instrucción no es una expresión de puesta a cero (vpxor, vpsubd con el mismo registro), el resultado es el mismo en BDW. Proyecto de muestra actualizado con Code4 y Code5.
Actualización4:Agregué Code6 como idea de Stephen Canon (operandos de memoria). El resultado es ~ 8200000 clks. Proyecto de muestra actualizado con Code6;
Verifiqué la frecuencia de la CPU y la posible aceleración con la Prueba de estabilidad del sistema de AIDA64. La frecuencia es estable y no hay signos de estrangulamiento;
Análisis de rendimiento de Intel IACA 2.1 Haswell:
Intel(R) Architecture Code Analyzer Version - 2.1
Analyzed File - Assembly.obj
Binary Format - 64Bit
Architecture - HSW
Analysis Type - Throughput
Throughput Analysis Report
--------------------------
Block Throughput: 5.10 Cycles Throughput Bottleneck: Port0, Port1, Port5
Port Binding In Cycles Per Iteration:
---------------------------------------------------------------------------------------
| Port | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 |
---------------------------------------------------------------------------------------
| Cycles | 5.0 0.0 | 5.0 | 0.0 0.0 | 0.0 0.0 | 0.0 | 5.0 | 1.0 | 0.0 |
---------------------------------------------------------------------------------------
| Num Of | Ports pressure in cycles | |
| Uops | 0 - DV | 1 | 2 - D | 3 - D | 4 | 5 | 6 | 7 | |
---------------------------------------------------------------------------------
| 1 | 1.0 | | | | | | | | CP | vfmadd231ps ymm0, ymm0, ymm0
| 1 | | 1.0 | | | | | | | CP | vfmadd231ps ymm1, ymm1, ymm1
| 1 | 1.0 | | | | | | | | CP | vfmadd231ps ymm2, ymm2, ymm2
| 1 | | 1.0 | | | | | | | CP | vfmadd231ps ymm3, ymm3, ymm3
| 1 | 1.0 | | | | | | | | CP | vfmadd231ps ymm4, ymm4, ymm4
| 1 | | 1.0 | | | | | | | CP | vfmadd231ps ymm5, ymm5, ymm5
| 1 | 1.0 | | | | | | | | CP | vfmadd231ps ymm6, ymm6, ymm6
| 1 | | 1.0 | | | | | | | CP | vfmadd231ps ymm7, ymm7, ymm7
| 1 | 1.0 | | | | | | | | CP | vfmadd231ps ymm8, ymm8, ymm8
| 1 | | 1.0 | | | | | | | CP | vfmadd231ps ymm9, ymm9, ymm9
| 1 | | | | | | 1.0 | | | CP | vpaddd ymm10, ymm10, ymm10
| 1 | | | | | | 1.0 | | | CP | vpaddd ymm11, ymm11, ymm11
| 1 | | | | | | 1.0 | | | CP | vpaddd ymm12, ymm12, ymm12
| 1 | | | | | | 1.0 | | | CP | vpaddd ymm13, ymm13, ymm13
| 1 | | | | | | 1.0 | | | CP | vpaddd ymm14, ymm14, ymm14
| 1 | | | | | | | 1.0 | | | dec rcx
| 0F | | | | | | | | | | jnz 0xffffffffffffffaa
Total Num Of Uops: 16
Seguí la idea de jcomeau_ictx y modifiqué el testp.zip de Agner Fog (publicado el 22/12/2015) El uso del puerto en el BDW 306D4:
Clock Core cyc Instruct uop p0 uop p1 uop p5 uop p6
Code1: 7734720 7734727 17000001 4983410 5016592 5000001 1000001
Code2: 5000072 5000072 17000001 5000010 5000014 4999978 1000002
La distribución del puerto casi perfecta como en Haswell. Luego verifiqué los contadores de pérdida de recursos (evento 0xa2)
Clock Core cyc Instruct res.stl. RS stl. SB stl. ROB stl.
Code1: 7736212 7736213 17000001 3736191 3736143 0 0
Code2: 5000068 5000072 17000001 1000050 999957 0 0
Me parece que la diferencia Code1 y Code2 proviene del puesto RS. Comentario de Intel SDM: "Ciclos estancados debido a que no hay una entrada RS elegible disponible".
¿Cómo puedo evitar este puesto con FMA?
Actualización5:Code6 cambió, cuando Peter Cordes me llamó la atención, solo los vpaddds usan operandos de memoria. Sin efecto sobre HSW y SKL, BDW empeora.
Tal como lo midió Marat Dukhan, no solo vpadd / vpsub / vpand / vpandn / vpxor se vieron afectados, sino también otras instrucciones limitadas de Port5 como vmovaps, vblendps, vpermps, vshufps, vbroadcastss;
Como IwillnotexistIdonotexist sugirió, probé con otros operandos. Una modificación exitosa es Code7, donde todos los vpaddds usan ymm15. Esta versión puede producir en BDW ~ 5000000 clks, pero solo por un tiempo. Después de ~ 6 millones de pares de FMA, alcanza los ~ 7730000 clks habituales:
Clock Core cyc Instruct res.stl. RS stl. SB stl. ROB stl.
5133724 5110723 17000001 1107998 946376 0 0
6545476 6545482 17000001 2545453 1 0 0
6545468 6545471 17000001 2545437 90910 0 0
5000016 5000019 17000001 999992 999992 0 0
7671620 7617127 17000003 3614464 3363363 0 0
7737340 7737345 17000001 3737321 3737259 0 0
7802916 7747108 17000003 3737478 3735919 0 0
7928784 7796057 17000007 3767962 3676744 0 0
7941072 7847463 17000003 3781103 3651595 0 0
7787812 7779151 17000005 3765109 3685600 0 0
7792524 7738029 17000002 3736858 3736764 0 0
7736000 7736007 17000001 3735983 3735945 0 0
Probé la versión xmm de Code7 como Code8. El efecto es similar, pero el tiempo de ejecución más rápido se mantiene por más tiempo. No he encontrado diferencias significativas entre un i5-5250U de 1.6GHz y un i7-5775C de 3.7GHz.
16 y 17 se hicieron con HyperThreading deshabilitado. Con HTT habilitado, el efecto es menor.