Eu estava lendo esta pergunta muito interessante no Stack Overflow:
Um dos comentários dizia:
"Não vale nada que, em Haswell, a taxa de transferência de multiplicação de FP seja o dobro da adição de FP. Isso ocorre porque ambas as portas 0 e 1 podem ser usadas para multiplicação, mas apenas a porta 1 pode ser usada para adição. Dito isso, você pode trapacear com -multiplica adiciona uma vez que ambas as portas podem fazê-lo. "
Por que eles permitiriam o dobro de multiplicações simultâneas em comparação à adição?
cpu
computer-architecture
alu
floating-point
intel
user1271772
fonte
fonte
Respostas:
Isso possivelmente responde ao título da pergunta, se não o corpo:
A adição de ponto flutuante requer o alinhamento das duas mantas antes de adicioná-las (dependendo da diferença entre os dois expoentes), exigindo potencialmente uma grande quantidade variável de turno antes do somador. Em seguida, pode ser necessário renormalizar o resultado da adição de mantissa, potencialmente exigindo outra grande quantidade variável de turnos para formatar adequadamente o resultado do ponto flutuante. Os dois mancais de manivela de manivela, portanto, potencialmente exigem mais atrasos de porta, maiores atrasos de cabos ou ciclos extras que excedem o atraso de um front end bem compactado do multiplicador de transporte-salvar-somador de árvores.
Adicionado para o OP: observe que adicionar comprimentos de 2 milímetros e 2 quilômetros não é 4 de nenhuma das unidades. Isso ocorre devido à necessidade de converter uma ou outra medida na mesma escala ou representação de unidade antes da adição. Essa conversão requer essencialmente uma multiplicação por alguma potência de 10. O mesmo normalmente ocorre durante a adição de ponto flutuante, porque os números de ponto flutuante são uma forma de números inteiros de escala variável (por exemplo, existe uma unidade ou fator de escala, um expoente, associado a cada número). Portanto, pode ser necessário dimensionar um dos números com uma potência de 2 antes de adicionar bits de mantissa brutos para que ambos representem as mesmas unidades ou escala. Essa escala é essencialmente uma forma simples de multiplicação por uma potência de 2. Portanto, a adição de ponto flutuante requer multiplicação(que, sendo uma potência de 2, pode ser feita com um deslocamento de bit variável ou deslocador de barril, que pode exigir fios relativamente longos em relação aos tamanhos de transistor, que podem ser relativamente lentos em circuitos sub-micron-litográficos profundos). Se os dois números forem cancelados principalmente (porque um é quase negativo do outro), pode haver uma necessidade de redimensionar novamente o resultado da adição e formatar adequadamente o resultado. Portanto, a adição pode ser lenta se, além disso, exigir 2 etapas de multiplicação (pré e pós) em torno da adição binária de um número fixo (finito) bruto de mantissa bits que representam unidades ou escalas equivalentes, devido à natureza do formato numérico (ponto flutuante IEEE )
Adicionado nº 2: Além disso, muitos parâmetros de referência ponderam o FMACS (multiplica-acumula) mais do que simples adições. Em um MAC fundido, o alinhamento (deslocamento) do adendo geralmente pode ser feito principalmente em paralelo com a multiplicação, e o mantissa add geralmente pode ser incluído na árvore do CSA antes da propagação final de transporte.
fonte
Na multiplicação FP, o processamento do expoente acaba sendo uma adição simples (exatamente pelo mesmo motivo que a multiplicação no domínio do log é apenas uma adição). Você encontrou logaritmos, espero.
Agora considere como é difícil adicionar dois números na forma logarítmica ...
O ponto flutuante habita uma área cinza entre os domínios linear e log, com aspectos de ambos. Cada número de FP compreende um mantissa (que é linear) e um expoente (logarítmico). Para determinar o significado de cada bit na mantissa, primeiro você precisa observar o expoente (que é apenas um fator de escala).
Além disso, o processamento de expoentes no caso geral exige a troca de barril da mantissa duas vezes, onde cada troca de barril é efetivamente um caso especial de multiplicação levemente simplificada.
(O primeiro turno alinha as duas entradas com a mesma potência de 2, para que um bit de mantissa tenha o mesmo peso binário em cada operando.
Um exemplo decimal será suficiente (embora o binário seja obviamente usado) ...
O segundo redimensiona a saída ...
Tão paradoxalmente, uma adição de FP envolve algo muito parecido com duas multiplicações que devem ser executadas seqüencialmente, com a adição de mantissa entre elas. Nessa perspectiva, o desempenho relatado não é tão surpreendente.
fonte
TL: DR : como a Intel achou que a latência de adição de SSE / AVX FP era mais importante que a taxa de transferência, eles optaram por não executá-la nas unidades FMA em Haswell / Broadwell.
O Haswell executa (SIMD) FP multiplica-se nas mesmas unidades de execução que o FMA ( Fused Multiply-Add ), dos quais possui dois, porque alguns códigos intensivos em FP podem usar principalmente FMAs para realizar 2 FLOPs por instrução. A mesma latência de 5 ciclos da FMA e
mulps
das CPUs anteriores (Sandybridge / IvyBridge). Haswell queria duas unidades de FMA, e não há desvantagem em permitir a multiplicação, porque elas têm a mesma latência que a unidade de multiplicação dedicada em CPUs anteriores.Mas mantém a unidade de adição SIMD FP dedicada das CPUs anteriores ainda em execução
addps
/addpd
com latência de 3 ciclos. Eu li que o possível raciocínio pode ser que o código que muitos FP adicionam tende a afunilar sua latência, não a taxa de transferência. Certamente isso é verdade para uma soma ingênua de uma matriz com apenas um acumulador (vetor), como você normalmente obtém da vetorização automática do GCC. Mas não sei se a Intel confirmou publicamente que esse era o raciocínio deles.Broadwell é o mesmo ( mas acelerou
mulps
/mulpd
até 3c de latência enquanto as FMA permaneceram em 5c). Talvez eles tenham sido capazes de atalho para a unidade FMA e obter o resultado da multiplicação antes de fazer uma adição fictícia0.0
, ou talvez algo completamente diferente e isso seja simplista demais. O BDW é principalmente um encolhimento do HSW, com a maioria das alterações sendo pequenas.No Skylake, tudo FP (incluindo adição) é executado na unidade FMA com latência de 4 ciclos e taxa de transferência de 0,5 c, exceto, é claro, div / sqrt e booleanos bit a bit (por exemplo, valor absoluto ou negação). A Intel aparentemente decidiu que não valia a pena extra de silício para adicionar FP de baixa latência ou que o
addps
rendimento desequilibrado era problemático. Além disso, a padronização das latências torna mais fácil evitar conflitos de write-back (quando 2 resultados estão prontos no mesmo ciclo) no agendamento de uop. isto é, simplifica o agendamento e / ou as portas de conclusão.Então, sim, a Intel mudou isso na próxima grande revisão de microarquitetura (Skylake). A redução da latência de FMA em 1 ciclo tornou o benefício de uma unidade de adição SIMD FP dedicada muito menor, para casos vinculados à latência.
Skylake também mostra sinais da Intel se preparando para o AVX512, onde estender um somador SIMD-FP separado para 512 bits de largura teria ocupado ainda mais a área da matriz. O Skylake-X (com AVX512) supostamente tem um núcleo quase idêntico ao cliente Skylake comum, exceto pelo cache L2 maior e (em alguns modelos) uma unidade FMA extra de 512 bits "conectada" à porta 5.
O SKX desliga as ALUs SIMD da porta 1 quando uops de 512 bits estão em andamento, mas precisa ser executada
vaddps xmm/ymm/zmm
a qualquer momento. Isso fez com que uma unidade FP ADD dedicada na porta 1 fosse um problema e é uma motivação separada para mudar do desempenho do código existente.Curiosidade: tudo, desde Skylake, KabyLake, Coffee Lake e até Cascade Lake, é microarquiteturalmente idêntico ao Skylake, exceto o Cascade Lake, que adiciona algumas novas instruções AVX512. O IPC não mudou de outra maneira. Porém, as CPUs mais novas têm melhores iGPUs. Ice Lake (microarquitetura Sunny Cove) é a primeira vez em vários anos que vimos uma nova microarquitetura real (exceto o nunca lançado amplamente Cannon Lake).
Argumentos baseados na complexidade de uma unidade FMUL versus uma unidade FADD são interessantes, mas não relevantes neste caso . Uma unidade FMA inclui todo o hardware de troca necessário para fazer a adição de FP como parte de uma FMA 1 .
Nota: Eu não quero dizer o x87
fmul
instrução, quero dizer um / FP escalar SSE / AVX SIMD multiplicam ALU que suporta 32-bit de precisão simples /float
e 64-bitdouble
de precisão (53-bit significand aka mantissa). por exemplo, instruções comomulps
oumulsd
. O x87 de 80 bits realfmul
ainda é apenas uma taxa de transferência de 1 / relógio em Haswell, na porta 0.As CPUs modernas têm transistores mais do que suficientes para resolver problemas quando vale a pena e quando não causam problemas de atraso na propagação da distância física. Especialmente para unidades de execução que estão ativas apenas algumas vezes. Veja https://en.wikipedia.org/wiki/Dark_silicon e este documento da conferência de 2011: Dark Silicon and the End of Multicore Scaling. É isso que torna possível que as CPUs tenham taxa de transferência massiva de FPU e taxa de transferência inteira massiva, mas não as duas ao mesmo tempo (porque essas diferentes unidades de execução estão nas mesmas portas de expedição para competir entre si). Em muitos códigos cuidadosamente ajustados que não afetam a largura de banda do mem, não são as unidades de execução de back-end que são o fator limitante, mas a taxa de transferência de instruções de front-end. ( núcleos largos são muito caros ). Consulte também http://www.lighterra.com/papers/modernmicroprocessors/ .
Antes de Haswell
Antes do HSW , as CPUs da Intel, como Nehalem e Sandybridge, tinham o SIMD FP multiplicado na porta 0 e o SIMD FP adicionado na porta 1. Portanto, havia unidades de execução separadas e o rendimento era equilibrado. ( https://stackoverflow.com/questions/8389648/how-do-i-achieve-the-theoretical-maximum-of-4-flops-per-cycle
Haswell introduziu o suporte FMA nos processadores Intel (alguns anos depois que a AMD introduziu o FMA4 no Bulldozer, depois que a Intel os enganou, esperando o mais tarde possível para tornar público que implementariam FMA de 3 operandos, não de 4 operandos não FMA4 de destino destrutivo). Curiosidade: o AMD Piledriver ainda era o primeiro CPU x86 com FMA3, cerca de um ano antes de Haswell em junho de 2013
Isso exigiu uma grande invasão dos internos para suportar até um único uop com 3 entradas. De qualquer forma, a Intel foi all-in e aproveitou os transistores cada vez menores para instalar duas unidades SIMD FMA de 256 bits, tornando Haswell (e seus sucessores) bestas na matemática de FP.
Um objetivo de desempenho que a Intel poderia ter em mente era o BLAS denso matmul e o produto de pontos vetoriais. Ambos podem usar principalmente FMA e não precisam apenas adicionar.
Como mencionei anteriormente, algumas cargas de trabalho que realizam principalmente ou apenas a adição de FP são gargalos na adição de latência, (principalmente), não na taxa de transferência.
Nota de rodapé 1 : E com um multiplicador de
1.0
, as FMA literalmente podem ser usadas para adição, mas com pior latência do que umaaddps
instrução. Isso é potencialmente útil para cargas de trabalho, como a soma de uma matriz quente no cache L1d, onde a taxa de transferência de adição de FP é mais importante que a latência. Isso só ajuda se você usar vários acumuladores de vetores para ocultar a latência, é claro, e manter 10 operações de FMA em andamento nas unidades de execução de FP (latência 5c / taxa de transferência de 0,5c = latência de 10 operações * produto de largura de banda). Você precisa fazer isso ao usar o FMA também para um produto vetorial com pontos .Veja a descrição de David Kanter da microarquitetura Sandybridge, que possui um diagrama de blocos de quais UEs estão em qual porta da família NHM, SnB e AMD Bulldozer. (Consulte também as tabelas de instruções e o guia de microarquitetura de otimização de asm da Agner Fog , e também https://uops.info/, que também possui testes experimentais de uops, portas e latência / taxa de transferência de quase todas as instruções em muitas gerações de microarquiteturas da Intel.)
Também relacionado: https://stackoverflow.com/questions/8389648/how-do-i-achieve-the-theoretical-maximum-of-4-flops-per-cycle
fonte
[cpu-architecture]
,[performance]
,[x86-64]
,[assembly]
, e[sse]
. Eu escrevi uma resposta no código C ++ para testar a conjectura Collatz mais rapidamente do que o conjunto escrito à mão - por quê? que muitas pessoas pensam que é bom. Também esta sobre OoO pipeline execução.Vou olhar para esta parte:
"Por que eles permitiriam " ...
TL; DR - porque eles projetaram dessa maneira. É uma decisão de gerenciamento. Claro que existem respostas de mantissa e shifters de bits, mas essas são as coisas que entram na decisão da gerência.
Por que eles projetaram dessa maneira? A resposta é que as especificações são feitas para atender a certos objetivos. Esses objetivos incluem desempenho e custo. O desempenho é voltado não para as operações, mas para uma referência como FLOPS ou FPS no Crysis.
Esses benchmarks terão uma mistura de funções, algumas delas podem ser processadas ao mesmo tempo.
Se os designers descobrirem que ter duas funções do widget A o torna muito mais rápido, em vez de duas funções do widget B, eles seguirão com o widget A. A implementação de dois de A e dois de B custará mais.
Olhando para trás, quando pipelines superescalares e super (antes de múltiplos núcleos) se tornaram comuns em chips comerciais, eles estavam lá para aumentar o desempenho. O Pentium possui dois tubos e nenhum vetor se une. A Haswell possui mais canais, unidades vetoriais, um canal mais profundo, funções dedicadas e muito mais. Por que não existem dois de tudo? Porque eles projetaram dessa maneira.
fonte
Este diagrama da Intel pode ajudar:
Parece que eles deram a cada unidade um FMA (multiply-add fundido), bem como um multiplicador e um único somador. Eles podem ou não compartilhar hardware por baixo.
A questão do porquê é muito mais difícil de responder sem as justificativas internas do design, mas o texto na caixa roxa nos dá uma dica com "dobra FLOPs de pico": o processador terá como alvo um conjunto de benchmarks, derivados de casos de uso reais. A FMA é muito popular nelas, pois é a unidade básica de multiplicação de matrizes. A adição nua é menos popular.
Você pode, como foi indicado, usar as duas portas para fazer acréscimos com uma instrução FMA em que o parâmetro de multiplicação é 1, computando (A x 1) + B. Isso será um pouco mais lento que uma adição simples.
fonte
Vamos dar uma olhada nas etapas demoradas:
Adição: Alinhe os expoentes (pode ser uma operação de turno massiva). Um somador de 53 bits. Normalização (em até 53 bits).
Multiplicação: uma rede massiva de somadores para reduzir produtos de 53 bits de 53 x 53 à soma de dois números de 106 bits. Um somador de 106 bits. Normalização. Eu diria que reduzir os produtos bit para dois números pode ser feito tão rápido quanto o somador final.
Se você pode fazer o tempo de multiplicação variável, você tem a vantagem de que a normalização mudará apenas um bit na maioria das vezes, e você pode detectar os outros casos muito rapidamente (entradas desnormalizadas ou a quantidade de expoentes é muito pequena).
Além disso, a necessidade de etapas de normalização é muito comum (adicionar números que não são do mesmo tamanho, subtrair números próximos). Portanto, para a multiplicação, você pode ter um caminho rápido e sofrer um grande golpe pelo caminho lento; Além disso, você não pode.
PS. Lendo os comentários: faz sentido que adicionar números desnormalizados não cause uma penalidade: significa apenas que, entre os bits que são deslocados para alinhar os expoentes, muitos são zeros. E o resultado desnormalizado significa que você para de mudar para remover os zeros à esquerda, se isso reduzir o tamanho do expoente.
fonte
-ffast-math
conjuntos FTZ / DAZ (liberar denormals para zero) para fazer isso, em vez de receber uma assistência FP.