Anomalia significativa no desempenho de FMA experimentada no processador 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
Code3 (o mesmo que Code2, mas com prefixo VEX longo):
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
Code4 (o mesmo que Code1, mas com 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
Código5 (o mesmo que o Código1, mas com vpsubd`s sem zeros):
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
Code6b: (revisado, operandos de memória apenas 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
Código7: (igual ao Código1, mas o 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 ao Código7, mas usa xmm em vez 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
Relógios TSC medidos com Turbo e C1E desativados:
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
Alguém pode explicar o que acontece com o Code1 em Broadwell?Meu palpite é que Broadwell de alguma forma contamina a Porta1 com vpaddds no caso do Código1, no entanto, o Haswell pode usar a Porta5 apenas se a Porta0 e a Porta1 estiverem cheias.;
Você tem alguma ideia de realizar o ~ 5000000 clk em Broadwell com instruções FMA?
Eu tentei reordenar. Comportamento semelhante experimentado com double e qword;
Eu usei o Windows 8.1 e o Win 10;
Atualizar:Adicionado Code3 como a idéia de Marat Dukhan com VEX longo;
Ampliou a tabela de resultados com as experiências Skylake;
Carregou um código de amostra Comunidade VS2015 + MASMaqui
Update2:Eu tentei com registros xmm em vez de ymm (código 4). Mesmo resultado em Broadwell.
Update3:Adicionei o Code5 como ideia de Peter Cordes (substitua o vpaddd por outras instruções (vpxor, vpor, vpand, vpandn, vpsubd)). Se a nova instrução não for um idioma de zeragem (vpxor, vpsubd com o mesmo registro), o resultado será o mesmo no BDW. Projeto de amostra atualizado com o Code4 e o Code5.
Update4:Adicionei Code6 como ideia de Stephen Canon (operandos de memória). O resultado é ~ 8200000 clks. Projeto de amostra atualizado com o Code6;
Eu verifiquei o freq da CPU e a possível limitação com o Teste de Estabilidade do Sistema da AIDA64. A frequência é estável e nenhum sinal de estrangulamento;
Análise de rendimento 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
Segui a idéia do jcomeau_ictx e modifiquei o testp.zip do Agner Fog (publicado em 2015-12-22) O uso da porta no 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
A distribuição portuária quase perfeita como no Haswell. Depois verifiquei os contadores de paralisação 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
Parece-me a diferença de Code1 e Code2 que vem da parada do RS. Observação do Intel SDM: "Ciclos interrompidos devido a nenhuma entrada RS qualificada disponível".
Como evitar essa parada com as FMA?
Update5:O Code6 mudou, como Peter Cordes chamou minha atenção, apenas os vpaddds usam operandos de memória. Nenhum efeito no HSW e SKL, o BDW piora.
Como Marat Dukhan mediu, não apenas o vpadd / vpsub / vpand / vpandn / vpxor afetou, mas outras instruções limitadas do Port5 como vmovaps, vblendps, vpermps, vshufps, vbroadcastss;
Como não existirei sugerir, tentei com outros operandos. Uma modificação bem-sucedida é o Code7, onde todos os vpaddds usam ymm15. Esta versão pode produzir em BDWs ~ 5000000 clks, mas apenas por um tempo. Após ~ 6 milhões de pares de FMA, atinge os ~ 7730000 clks usuais:
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
Eu tentei a versão xmm do Code7 como Code8. O efeito é semelhante, mas o tempo de execução mais rápido dura mais tempo. Não encontrei diferença significativa entre o i5-5250U de 1.6GHz e o i7-5775C de 3.7GHz.
16 e 17 foram feitas com o HyperThreading desativado. Com HTT ativado, o efeito é menor.