- Aprender
- Computação e TI
- Ciência da computação
- Organização e arquitetura de computadores
- Processadores paralelos
Processadores paralelos e de múltiplos núcleos
IntermediárioAula 6 de 6 do curso Curso de Organização e arquitetura de computadores
O que você vai aprender
- Explicar por que os processadores passaram a usar paralelismo, distinguir o paralelismo em nível de instrução, dados, thread e requisição, classificar máquinas pela taxonomia de Flynn e descrever como o multithreading em hardware mantém um núcleo ocupado.
- Explicar por que os computadores passaram a usar paralelismo e identificar seus tiposRelacionar a barreira de potência à transição para chips de múltiplos núcleos e reconhecer o paralelismo em nível de instrução, dados, thread e requisição em programas reais.
- Classificar hardware paralelo com a taxonomia de FlynnUsar o número de fluxos de instruções e de dados para classificar uma máquina como SISD, SIMD, MISD ou MIMD e explicar o estilo de programação SPMD.
- Manter um núcleo ocupado com multithreading em hardwareExplicar como o multithreading de granularidade fina, de granularidade grossa e simultâneo oculta paradas e como threads de hardware diferem de núcleos adicionais.
- Explicar por que os computadores passaram a usar paralelismo e identificar seus tipos
- Calcular aceleração e eficiência, aplicar as leis de Amdahl e Gustafson, considerar desequilíbrio de carga e sobrecarga e usar o modelo Roofline para verificar se a capacidade de cálculo ou a largura de banda da memória limita um programa.
- Calcular a aceleração e a eficiência com a lei de AmdahlDefinir aceleração e eficiência, aplicar a lei de Amdahl nos dois sentidos e explicar por que a fração sequencial limita a aceleração de um problema de tamanho fixo.
- Distinguir escalabilidade forte e fraca e considerar as sobrecargasComparar a aceleração com tamanho fixo e com tamanho escalonado, aplicar a lei de Gustafson e estimar o efeito do desequilíbrio de carga, da comunicação e da sincronização.
- Determinar limites de desempenho com o modelo RooflineCalcular a intensidade aritmética, ler um gráfico Roofline para decidir se um kernel é limitado pela largura de banda da memória ou pela capacidade de cálculo de pico e escolher otimizações adequadas.
- Calcular a aceleração e a eficiência com a lei de Amdahl
- Usar instruções SIMD e arquiteturas vetoriais para processar vetores, explicar como uma GPU é organizada para obter alta vazão e escrever e analisar um kernel simples de GPU.
- Processar vários elementos de dados ao mesmo tempo com instruções SIMDCalcular quantas vias um registrador SIMD tem, vetorizar laços simples e reconhecer as organizações de dados, os desvios e as dependências que limitam a aceleração SIMD.
- Explicar como arquiteturas vetoriais executam laçosDescrever registradores vetoriais, comprimento do vetor, particionamento do laço em blocos, vias e acesso com passo constante, usando a extensão vetorial RISC-V como exemplo.
- Descrever como uma GPU é organizada para obter alta vazãoExplicar multiprocessadores de streaming, warps e execução SIMT, como GPUs ocultam a latência da memória, divergência de desvios, coalescência de acessos à memória e custo da transferência de dados, e comparar GPUs com CPUs e aceleradores de domínio específico.
- Escrever e analisar um kernel simples de GPUUsar a hierarquia de grade, bloco e thread para mapear dados às threads, organizar o trabalho do hospedeiro e do dispositivo e sincronizar dentro de um bloco.
- Processar vários elementos de dados ao mesmo tempo com instruções SIMD
- Descrever multiprocessadores de memória compartilhada e como as threads dividem o trabalho, explicar as garantias da coerência de cache, acompanhar protocolos de monitoração e de diretório e evitar falso compartilhamento.
- Descrever multiprocessadores de memória compartilhada e dividir o trabalho entre núcleosExplicar um espaço de endereçamento compartilhado único, o acesso uniforme e não uniforme à memória, a organização das caches de um chip de múltiplos núcleos e como as threads dividem e combinam o trabalho.
- Explicar o problema da coerência de cache e as garantias da coerênciaMostrar como caches privadas podem retornar dados desatualizados, apresentar as condições de um sistema de memória coerente e distinguir coerência de consistência e de código livre de condições de corrida.
- Acompanhar um protocolo de monitoração de coerência com estados MSI e MESIAcompanhar estados de blocos de cache e transações no barramento em uma sequência de leituras e escritas e explicar o que o estado exclusivo economiza.
- Explicar protocolos baseados em diretório e evitar falso compartilhamentoDescrever como um diretório rastreia os detentores de cópias, estimar seu custo de armazenamento e reconhecer, medir e corrigir o falso compartilhamento.
- Descrever multiprocessadores de memória compartilhada e dividir o trabalho entre núcleos
- Descrever aglomerados de computadores com passagem de mensagens e comparar redes de interconexão por largura de banda e custo; depois, explicar como computadores em escala de centro de dados fornecem serviços de internet, considerando custo, energia e falhas.
- Descrever aglomerados de computadores com passagem de mensagens e comparar redes de interconexãoExplicar como nós com memórias privadas cooperam por mensagens e comparar topologias de rede por largura de banda total, largura de banda de bisseção e custo.
- Explicar como computadores em escala de centro de dados fornecem serviços em grande escalaDescrever a organização de um computador em escala de centro de dados e analisar sua rede, seu uso de energia e suas falhas com cálculos simples.
- Descrever aglomerados de computadores com passagem de mensagens e comparar redes de interconexão
Guia de estudo de Processadores paralelos
1Identifique e classifique o trabalho paralelo
O hardware paralelo pode trabalhar com instruções, elementos de vetores, threads ou requisições independentes. A escolha útil depende de onde um programa tem trabalho que pode ser executado em conjunto. Relacione esse trabalho aos limites de potência que levaram os chips a ter múltiplos núcleos e depois classifique o hardware por seus fluxos de instruções. O multithreading em hardware oferece outra forma de manter um núcleo ocupado ao encontrar instruções úteis durante as paradas.
1.1 Por que os chips agora dividem o trabalho
Computadores paralelos realizam operações ao mesmo tempo. Eles podem reduzir a latência, o tempo que uma tarefa leva, ou aumentar a vazão, o número de tarefas concluídas por segundo. Esses objetivos levam a formas diferentes de dividir o trabalho.
A barreira de potência
Aumentar a frequência de clock antes tornava cada geração de processadores mais rápida. A potência dinâmica segue aproximadamente : capacitância vezes tensão ao quadrado vezes frequência de chaveamento. A tensão aparece duas vezes nesse produto. Reduzir tanto a tensão quanto a frequência em 15% resulta em da potência dinâmica original, cerca de 61%.
A tensão não podia continuar caindo o suficiente para compensar frequências de clock mais altas. A corrente de fuga e o calor tornaram custoso demais continuar aumentando a frequência. Essa barreira de potência levou a indústria aos chips de múltiplos núcleos em meados dos anos 2000. Um chip de múltiplos núcleos coloca vários núcleos de processador em um chip; um sistema multiprocessador tem pelo menos dois processadores. Núcleos mais modestos podem realizar mais trabalho total por joule, desde que haja trabalho suficiente para dividir.
Quatro fontes de trabalho paralelo
| Tipo | O que é executado em conjunto? | Exemplo |
|---|---|---|
| Paralelismo em nível de instrução (ILP) | Instruções de um fluxo de instruções | Um pipeline sobrepõe estágios de instruções sucessivas. |
| Paralelismo em nível de dados (DLP) | A mesma operação em muitos elementos | Somar elementos correspondentes de dois vetores. |
| Paralelismo em nível de thread (TLP) | Várias sequências de instruções | Várias threads processam regiões diferentes de uma imagem. |
| Paralelismo em nível de requisição | Tarefas independentes | Servidores respondem às consultas de muitos usuários ao mesmo tempo. |
O ILP é identificado principalmente pelo hardware e pelos compiladores. A segmentação em pipeline, a emissão múltipla e a execução fora de ordem sobrepõem instruções enquanto preservam os resultados exigidos pelo programa. Dependências e desvios limitam a sobreposição disponível.
O DLP aparece quando muitos elementos precisam do mesmo cálculo. Instruções SIMD, processadores vetoriais e GPUs exploram essa regularidade. O TLP exige que o trabalho seja dividido em threads pelo código, por uma biblioteca ou por um compilador. Uma thread tem seu próprio contador de programa, registradores e pilha; threads de um mesmo processo compartilham seu espaço de endereçamento. Processos distintos têm espaços de endereçamento distintos.
O trabalho em nível de requisição precisa de pouca cooperação entre tarefas. Adicionar servidores pode, portanto, aumentar a capacidade quase proporcionalmente aos recursos acrescentados. Executar vários programas independentes em um notebook também usa núcleos que estariam ociosos, aumentando a vazão geral mesmo quando nenhum desses programas é paralelizado internamente.
Tarefas concorrentes e execução simultânea
Concorrência significa que tarefas progridem durante períodos sobrepostos. Um núcleo pode fazer isso alternando entre elas. Paralelismo significa que operações são executadas no mesmo instante em unidades de hardware distintas. Um sistema de núcleo único pode manter vários programas em andamento sem executar suas instruções simultaneamente.
Um programa com uma thread sequencial não se divide entre oito núcleos simplesmente porque eles existem. Os núcleos extras podem executar outro trabalho, mas reduzir o tempo desse programa exige trabalho paralelo dentro dele. Mesmo depois que o trabalho é dividido, qualquer parte sequencial restante ainda limita o ganho.
Principais conclusões
- O hardware paralelo pode reduzir a latência de uma tarefa ou aumentar a vazão total.
- A potência dinâmica depende da tensão ao quadrado e da frequência.
- ILP, DLP, TLP e paralelismo em nível de requisição revelam tipos diferentes de trabalho.
- A concorrência pode usar compartilhamento de tempo; o paralelismo usa execução simultânea.
1.2 Conte os fluxos de instruções e de dados
Um processador pode conter muitas unidades aritméticas sem seguir muitos fluxos de instruções independentes. A taxonomia de Flynn classifica o hardware por seus fluxos de instruções e de dados, portanto o primeiro passo é escolher o nível da máquina que está sendo descrito.
As quatro classes de hardware
| Classe | Fluxos de instruções | Fluxos de dados | Significado |
|---|---|---|---|
| SISD | Único | Único | Um processador segue um fluxo de instruções comum. |
| SIMD | Único | Múltiplos | Uma instrução aplica uma operação a vários elementos de dados. |
| MISD | Múltiplos | Único | Fluxos de instruções diferentes operam sobre um fluxo de dados. |
| MIMD | Múltiplos | Múltiplos | Processadores buscam instruções e trabalham com dados de forma independente. |
Um processador convencional de núcleo único é SISD mesmo quando seu pipeline sobrepõe várias instruções. A emissão superescalar, por si só, não cria contadores de programa independentes nem transforma o núcleo em hardware MIMD.
Uma instrução SIMD pode somar oito pares de números de ponto flutuante de 32 bits em um registrador de 256 bits. Ela tem oito vias aritméticas, mas elas seguem uma instrução. Extensões SIMD de largura fixa incluem x86 SSE e AVX e Arm Neon; arquiteturas vetoriais também se enquadram na classe SIMD. Cálculos regulares em vetores são adequados porque muitos elementos precisam da mesma operação.
Processadores MIMD escolhem suas instruções independentemente. Chips de múltiplos núcleos, multiprocessadores de memória compartilhada e aglomerados de computadores se enquadram nessa classe. Os núcleos podem executar programas diferentes ou cópias do mesmo programa que chegam a desvios diferentes em momentos diferentes.
MISD completa a classificação dois por dois. Há poucos exemplos práticos claros. Alguns sistemas tolerantes a falhas e pipelines de processamento são descritos dessa forma, mas sua classificação depende de como seus fluxos são definidos.
Um programa ainda pode ter muitos fluxos de instruções
SPMD, programa único e múltiplos dados, é um estilo de programação. Cada unidade de trabalho executa uma cópia do mesmo programa e usa seu identificador para selecionar sua parcela dos dados. As unidades têm estados de execução independentes, portanto SPMD normalmente é executado em hardware MIMD.
Para quatro núcleos somando 4.000 valores, o núcleo de identificador trata os índices de a . O núcleo 0 trata de 0 a 999; o núcleo 3 trata de 3000 a 3999. Cada um produz uma soma parcial, e essas quatro somas são combinadas. O texto compartilhado do programa não exige que os quatro núcleos emitam a mesma instrução no mesmo ciclo.
Classifique cada nível separadamente
Considere uma CPU de oito núcleos cujas threads usam instruções AVX. Entre os núcleos, ela é MIMD: os núcleos avançam independentemente. Dentro de uma operação AVX, ela é SIMD: uma instrução controla várias vias. Contar todas as unidades aritméticas juntas ocultaria essa estrutura.
Um aglomerado que executa cópias de um programa científico também é hardware MIMD usando software SPMD. Seus nós se comunicam por mensagens. Uma GPU combina muitos grupos de threads escalonados independentemente com execução semelhante a SIMD dentro de cada grupo; a NVIDIA chama seu estilo de execução baseado em threads de SIMT.
Para classificar uma descrição, pergunte quem escolhe a próxima instrução. Depois, pergunte se essa instrução processa um elemento de dados ou vários. O número de arquivos-fonte, programas instalados ou unidades aritméticas, por si só, não responde a essas duas perguntas.
Principais conclusões
- A taxonomia de Flynn conta os fluxos de instruções e os fluxos de dados.
- A segmentação em pipeline dentro de um fluxo de instruções continua sendo SISD.
- SIMD compartilha o controle de instruções entre vias; MIMD tem fluxos de instruções independentes.
- SPMD é um estilo de programação normalmente executado em hardware MIMD.
- Uma máquina pode ser MIMD entre núcleos e SIMD dentro de cada núcleo.
1.3 Preencha ciclos ociosos com outra thread
Uma falta na cache pode deixar um núcleo esperando centenas de ciclos. O multithreading em hardware mantém os estados de execução de várias threads dentro de um núcleo para que instruções úteis de outra thread possam ser executadas durante essa espera.
O que é duplicado e o que é compartilhado
Cada thread de hardware tem seu próprio contador de programa e estado de registradores. As threads compartilham as unidades de execução, as caches e o acesso à largura de banda da memória do núcleo. Manter o estado no hardware torna a troca muito mais rápida do que salvar e restaurar um processo do sistema operacional, o que pode custar milhares de ciclos. O hardware pode fazer a troca em um ciclo ou menos.
O sistema operacional vê cada thread de hardware como um processador lógico. Oito núcleos físicos com duas threads de hardware por núcleo apresentam 16 processadores lógicos. Essa contagem descreve os contextos de thread disponíveis, não 16 núcleos físicos completos.
Três formas de escalonamento
| Abordagem | Quando o núcleo escolhe outra thread? | Principal compromisso |
|---|---|---|
| Granularidade fina | A cada ciclo, pulando threads paradas | Oculta paradas curtas e longas, mas cada thread espera entre suas vezes. |
| Granularidade grossa | Em uma parada longa, como uma falta na cache de último nível | Dá longos períodos de execução a uma thread, mas a troca e o preenchimento do pipeline custam tempo. |
| Multithreading simultâneo (SMT) | Várias threads podem emitir instruções no mesmo ciclo | Preenche posições de emissão não usadas enquanto compartilha os recursos do núcleo. |
O escalonamento de granularidade fina pode alternar entre threads prontas mesmo quando a thread anterior poderia continuar. O escalonamento de granularidade grossa continua executando essa thread até que uma parada custosa justifique a troca. O SMT usa um núcleo com emissão múltipla e escalonamento dinâmico: instruções de threads diferentes podem ocupar posições livres de emissão diferentes durante um ciclo. A renomeação de registradores mantém seus estados separados. O Hyper-Threading da Intel é uma implementação de SMT; alguns processadores IBM POWER suportam oito threads de hardware por núcleo.
Analise a ocultação de latência
Suponha que uma thread calcule por 20 ciclos e depois espere 200 ciclos pela memória. Seu ciclo tem 220 ciclos de duração. Sozinho, o trabalho útil ocupa , ou 9,1% do tempo.
Com quatro threads, trabalho escalonado livremente e sem custo de troca ou disputa adicional, o trabalho útil pode ocupar , ou 36,4%. O núcleo ainda tem intervalos ociosos porque quatro períodos de 20 ciclos não conseguem cobrir os períodos de espera.
Onze threads fornecem 220 ciclos de períodos de cálculo no total. Enquanto uma espera por 200 ciclos, as outras dez podem calcular por 20 cada uma. Esse escalonamento ideal mantém o núcleo ocupado. O desempenho real também depende de essas threads competirem ou não por recursos de memória e execução.
Vazão e tempo de conclusão de uma thread
O multithreading aumenta principalmente a vazão. Uma thread específica pode levar mais tempo porque outras threads usam ciclos e espaço de cache que ela receberia de outra forma. Duas threads de hardware que compartilham uma unidade aritmética não podem receber, ambas, a capacidade de um segundo núcleo completo.
Se ambas as threads já exigem as mesmas unidades de execução totalmente ocupadas, o SMT tem pouca capacidade livre para preencher. Se uma para enquanto a outra pode executar, o compartilhamento é útil. As GPUs aplicam a ocultação de latência em escala maior, mantendo muitos grupos de threads prontos para seus escalonadores.
Principais conclusões
- Threads de hardware duplicam o estado de execução enquanto compartilham os recursos de um núcleo.
- A troca de granularidade fina ocorre a cada ciclo; a de granularidade grossa responde a paradas longas.
- O SMT pode emitir instruções de threads diferentes durante um ciclo.
- As contagens de processadores lógicos incluem contextos de threads de hardware.
- A ocultação de latência precisa de trabalho pronto e pode ser limitada pela disputa por recursos.
- Uma vazão maior não precisa reduzir o tempo de execução de uma thread individual.
2Estime a aceleração paralela útil
Processadores extras dividem apenas o trabalho que pode ser executado em paralelo e introduzem custos próprios. Comece pelo tempo decorrido e pela fração sequencial; depois, distinga concluir uma tarefa fixa mais cedo de resolver uma tarefa maior no mesmo tempo. O equilíbrio de carga e a coordenação explicam outras perdas. O modelo Roofline acrescenta outro limite: se a memória consegue alimentar as unidades aritméticas disponíveis com rapidez suficiente.
2.1 Calcule o ganho e seu limite
Uma máquina paralela é útil quando altera o tempo decorrido. A aceleração compara a melhor execução sequencial com a execução paralela; a eficiência compara esse ganho com o número de processadores usados.
Comece pelo tempo medido
Para processadores, e . Uma tarefa sequencial de 100 s que termina em 16 s em oito núcleos tem aceleração . Sua eficiência é , cerca de 78%. Meça o tempo decorrido de relógio para ambas as execuções, usando a mesma tarefa fixa.
Divida o tempo em partes melhorada e inalterada
Na lei de Amdahl, é a fração do tempo de execução original que uma melhoria acelera. É uma fração de tempo, não uma fração das linhas de código-fonte. Se essa parte se torna vezes mais rápida, então
A parte inalterada ainda leva todo o seu tempo original. Para uma divisão paralela ideal entre processadores, faça . Esse modelo exclui sobrecargas de comunicação, desequilíbrio e sincronização; esses custos podem aumentar o tempo medido.
Com 90% de tempo paralelizável e dez processadores, o tempo normalizado é . A aceleração é , e a eficiência é de cerca de 53%. Com 100 processadores, o tempo é e a aceleração é de cerca de 9,17. Aumentar o número de processadores em dez vezes não dobrou a aceleração.
Encontre o limite antes de comprar mais processadores
À medida que o número de processadores cresce, o tempo paralelo se aproxima de zero. A fração sequencial permanece, produzindo o teto . Uma fração sequencial de 10% limita a aceleração ideal a 10; uma fração de 5% a limita a 20. Quantidades finitas de processadores se aproximam desses tetos por baixo.
A lei de Amdahl também avalia uma classe de instruções mais rápida. Se a multiplicação ocupa 30% de uma execução e se torna quatro vezes mais rápida, o tempo normalizado passa a ser . O programa inteiro fica apenas vezes mais rápido.
Resolva a partir de uma meta
Para obter aceleração 90 em 100 processadores, escreva . Portanto, . Apenas cerca de 0,11% do tempo original pode permanecer sequencial. Uma meta próxima do número de processadores exige uma fração inalterada muito pequena.
Uma aceleração medida pode às vezes superar o número de processadores. Dividir um grande conjunto de trabalho pode fazer cada parte caber na cache, reduzindo o custo por operação. Essa aceleração superlinear altera uma premissa do modelo simples: o trabalho paralelo já não é apenas o trabalho original dividido em parcelas iguais. Verifique o algoritmo, o tamanho dos dados e o comportamento da cache antes de interpretar essa medição.
Principais conclusões
- A aceleração é o tempo sequencial dividido pelo tempo paralelo; a eficiência é a aceleração dividida pelo número de processadores.
- A fração de Amdahl refere-se ao tempo de execução original.
- Apenas a fração melhorada é dividida pelo fator de melhoria.
- A fração sequencial determina o teto de aceleração para uma carga de trabalho fixa.
- Efeitos de cache podem alterar o custo do trabalho e produzir aceleração medida superlinear.
2.2 Escale o problema e inclua os custos
Adicionar processadores pode reduzir o tempo da mesma tarefa ou permitir que uma máquina trate uma tarefa maior. A escalabilidade forte e a escalabilidade fraca medem esses usos diferentes, e ambas dependem de quanto trabalho útil resta após os custos de coordenação.
Trabalho fixo e trabalho crescente
A escalabilidade forte mantém o tamanho do problema fixo. A escalabilidade fraca aumenta o trabalho proporcionalmente ao número de processadores, mantendo constante o trabalho por processador. A escalabilidade fraca perfeita mantém o tempo decorrido constante enquanto o trabalho total cresce.
Considere dez adições sequenciais seguidas de uma soma elemento a elemento de duas matrizes. Uma matriz de 10 por 10 precisa de 100 adições paralelas. O tempo total é de 110 unidades em um processador, 20 em dez e 12 em cinquenta: acelerações de 5,5 e cerca de 9,2. Uma matriz de 40 por 40 precisa de 1.600 adições paralelas. Os tempos passam a 1.610, 170 e 42 unidades: acelerações de cerca de 9,5 e 38,3. O problema maior dá mais peso ao trabalho paralelo útil em relação às mesmas dez adições sequenciais.
A base diferente de Gustafson
A lei de Gustafson usa a fração do tempo sequencial medida na execução paralela. Chamando essa fração de , a aceleração com tamanho escalonado é . Para e 100 processadores, .
A lei de Amdahl com 5% de tempo sequencial na execução original em um processador dá apenas cerca de 16,8 em 100 processadores. Essas frações usam denominadores diferentes e respondem a perguntas diferentes. Uma aceleração com tamanho escalonado de 95,05 não significa que a tarefa original de tamanho fixo terminou 95,05 vezes mais rápido.
A unidade mais lenta determina o tempo de conclusão
Se 400 unidades iguais de trabalho forem distribuídas entre oito núcleos, a parcela equilibrada será de 50 para cada um. Suponha que um receba 120 enquanto os outros sete recebem 40 cada. A etapa dura 120 unidades de tempo, portanto a aceleração é . Dividir pela carga média deixaria de considerar a espera pelo núcleo mais ocupado.
Criação de threads, escalonamento, mensagens, barreiras e disputa pela largura de banda compartilhada também consomem tempo. Granularidade é a quantidade de cálculo entre eventos de comunicação ou sincronização. Partes maiores reduzem o custo de coordenação por operação útil, mas partes em número insuficiente podem deixar algumas unidades de trabalho ociosas.
Mais processadores podem aumentar o tempo
Para uma tarefa totalmente paralela de 100 s com sobrecarga de segundos, . Dez processadores levam 15 s. Quatorze levam cerca de 14,14 s, perto do mínimo de aproximadamente processadores. Quarenta levam 22,5 s porque sua sobrecarga de 20 s supera a redução do tempo de cálculo útil.
Ao apresentar um resultado, informe se o trabalho permaneceu fixo ou cresceu e compare com o tempo do melhor programa sequencial. Usar como base uma implementação paralela lenta executada em um processador pode inflar a aceleração apresentada.
Principais conclusões
- A escalabilidade forte fixa o trabalho total; a fraca fixa o trabalho por processador.
- A fração sequencial de Gustafson é medida na execução paralela.
- A unidade de trabalho mais lenta determina o tempo de conclusão de uma etapa paralela.
- Comunicação, sincronização e disputa por recursos podem crescer com o número de processadores.
- A granularidade envolve um compromisso entre custo de coordenação e equilíbrio de carga.
- Use o tempo decorrido e o melhor programa sequencial como base ao apresentar a aceleração.
2.3 Encontre o teto de cálculo ou de memória
A taxa aritmética anunciada de um processador é apenas um dos limites. O modelo Roofline também pergunta se a memória consegue fornecer dados com rapidez suficiente para sustentar essa taxa. Ele fornece um limite superior, que ajuda a identificar uma direção útil para a otimização.
Conte operações por byte da DRAM
A intensidade aritmética é o número de operações de ponto flutuante dividido pelos bytes transferidos entre a DRAM e o processador. O trabalho original sobre o modelo Roofline chama essa medida baseada na DRAM de intensidade operacional. Conte o tráfego nessa fronteira, incluindo leituras e escritas.
DAXPY calcula usando números de precisão dupla. Cada elemento exige uma multiplicação e uma adição: dois FLOPs. Ler um valor de 8 bytes de cada vetor e escrever 8 bytes de volta transfere 24 bytes. A intensidade é FLOPs por byte. O coeficiente escalar é reutilizado; nesse modelo de tráfego, ele não exige uma nova carga da DRAM para cada elemento.
Aplique os dois limites
Se a capacidade de cálculo de pico é e a largura de banda de pico da memória é , o teto é . Largura de banda multiplicada por FLOPs por byte tem como unidade FLOPs por segundo. Em um gráfico log-log, o limite de largura de banda sobe em uma linha inclinada e o limite de cálculo é horizontal.
Para 1.000 GFLOP/s e 100 GB/s, o ponto de transição é FLOPs por byte. Abaixo dessa intensidade, o teto de largura de banda é menor; acima dela, o teto de cálculo é menor. DAXPY é limitado a GFLOP/s, menos de 1% da capacidade de cálculo de pico da máquina. Um kernel com intensidade 2 é limitado a 200 GFLOP/s.
Um kernel limitado pela largura de banda da memória ainda pode se beneficiar de núcleos extras ou de SIMD mais largo enquanto tiver poucas requisições em andamento para usar a largura de banda disponível. Quando essa largura de banda está saturada, a capacidade aritmética adicional não eleva seu teto. Aumentar a largura de banda ou realizar mais cálculo útil por byte transferido eleva esse limite.
A reutilização altera a intensidade
Multiplicar duas matrizes de precisão dupla de 1000 por 1000 realiza cerca de FLOPs. Se cada elemento das duas entradas e da saída atravessar a fronteira da DRAM uma vez, o tráfego total será de 24 MB, resultando em cerca de 83 FLOPs por byte. Esse valor está acima do ponto de transição da máquina do exemplo.
Uma implementação ingênua pode reler repetidamente os valores das matrizes da DRAM. A blocagem organiza os laços em torno de submatrizes que cabem na cache, de modo que os valores sirvam a muitas operações antes de serem substituídos. O algoritmo continua sendo a multiplicação de matrizes, mas a implementação transfere menos bytes da DRAM por operação.
Um teto não é um resultado medido
Um kernel pode ser executado abaixo do limite por causa de dependências, sobrecarga de instruções, padrões de acesso inadequados ou trabalho paralelo insuficiente. Tetos de desempenho mais baixos mostram essas restrições: a falta de SIMD pode reduzir o teto de cálculo, enquanto padrões de acesso inadequados reduzem a largura de banda utilizável. Um ponto abaixo de um teto precisa de investigação; o teto, por si só, não prevê sua taxa de execução exata.
Principais conclusões
- A intensidade conta FLOPs por byte na fronteira da DRAM.
- O teto é o menor valor entre a capacidade de cálculo de pico e a largura de banda multiplicada pela intensidade.
- O ponto de transição é a capacidade de cálculo de pico dividida pela largura de banda de pico.
- A reutilização pode aumentar a intensidade sem alterar o algoritmo matemático.
- O modelo Roofline fornece um limite superior; tetos mais baixos explicam restrições adicionais.
3Processe vetores com vias e threads de GPU
Vetores oferecem operações repetidas em elementos independentes, que podem ser distribuídas entre vias e threads. Acompanhe essa ideia desde registradores SIMD de largura fixa até laços vetoriais de comprimento variável e, depois, warps de GPU. Cada projeto precisa de uma organização eficaz dos dados e de trabalho suficiente para ocupar seu hardware. Um pequeno kernel mostra como índices de vetores se tornam índices de threads, enquanto os custos de transferência determinam se transferir o trabalho ajuda a tarefa completa.
3.1 Execute operações sobre vetores nas vias SIMD
Uma extensão SIMD divide um registrador largo em vias. Uma instrução realiza a mesma operação em cada via, tornando os laços regulares sobre elementos independentes uma boa opção.
Conte vias e iterações
O número de vias é igual à largura do registrador dividida pela largura do elemento. Um registrador de 256 bits comporta oito números de ponto flutuante de 32 bits, quatro de precisão dupla de 64 bits ou 32 elementos de um byte. SSE usa registradores XMM de 128 bits; AVX e AVX2 usam registradores YMM de 256 bits. No modo de 64 bits, há 16 registradores YMM. AVX-512 oferece 32 registradores ZMM de 512 bits, cada um comportando 16 números de ponto flutuante. Arm Neon usa registradores de 128 bits.
Para c[i] = a[i] + b[i] sobre 1.000 números de ponto flutuante, instruções de oito vias processam o vetor em 125 iterações vetoriais. Cada iteração carrega dois vetores, soma suas vias e armazena um vetor. Com 1.003 elementos, 125 iterações completas deixam três elementos. Um laço escalar para o restante ou uma operação com máscara trata essa parte curta sem acessar posições além dos vetores.
Oito vias representam capacidade aritmética, não uma garantia de aceleração de oito vezes do programa. A preparação, o tratamento do restante, o trabalho sequencial e a largura de banda da memória ainda consomem tempo.
Escolha uma organização que preencha um registrador
Cargas vetoriais simples funcionam bem com elementos contíguos, de passo unitário. Um vetor de pontos {x, y, z} com campos de 4 bytes coloca campos x consecutivos a 12 bytes de distância. Uma estrutura de vetores coloca os valores de x juntos, depois os valores de y e depois os de z. Processar apenas x agora pode preencher um vetor com uma carga contígua. Instruções de coleta e dispersão aceitam endereços espalhados, mas normalmente com custo de acesso maior.
Mantenha o trabalho condicional dentro das vias
Para c[i] = (a[i] > 0) ? a[i] : 0, uma comparação cria uma máscara por via. Uma seleção escolhe entre resultados candidatos, ou instruções com máscara atualizam apenas as vias selecionadas. As vias inativas mantêm ou recebem valores conforme o comportamento da máscara da instrução.
Se vias diferentes precisarem seguir ramos longos e diferentes, as instruções desses caminhos ainda deverão ser emitidas, com apenas as vias pertinentes ativas. O grupo não pode dar a cada via um fluxo de instruções separado. Uma máscara preserva a correção, mas não faz todas essas instruções de caminho desaparecerem.
Verifique a independência das iterações
Compiladores podem vetorizar laços automaticamente; programadores também podem usar bibliotecas ou funções intrínsecas como _mm256_add_ps. O compilador deve estabelecer que iterações simultâneas preservam o resultado. A recorrência a[i] = a[i-1] + b[i] depende do novo valor da iteração anterior e não pode ser vetorizada diretamente como elementos independentes. A possível sobreposição de ponteiros, chamada aliasing, também pode exigir uma verificação de sobreposição em tempo de execução ou impedir a vetorização.
Uma redução mantém várias somas parciais em um registrador e depois combina as vias. Reordenar adições de ponto flutuante pode alterar os últimos bits porque a adição não é associativa. Somas de inteiros coincidem quando a aritmética escolhida não apresenta estouro ou usa aritmética modular definida.
SIMD e execução em múltiplos núcleos podem ser combinados. Oito núcleos, cada um emitindo uma adição de oito vias por ciclo, podem realizar até 64 adições de ponto flutuante por ciclo. Eles ainda compartilham limites como a largura de banda da memória.
Principais conclusões
- O número de vias SIMD depende tanto da largura do registrador quanto da largura do elemento.
- Elementos restantes precisam de um trecho escalar ou de acesso com máscara correta.
- Organizações contíguas ajudam cargas vetoriais a usar suas vias com eficiência.
- Máscaras tratam condições por elemento enquanto compartilham a emissão de instruções.
- Dependências e sobreposição de ponteiros podem impedir a vetorização direta.
- Reduções de ponto flutuante podem alterar o arredondamento quando as operações são reagrupadas.
3.2 Deixe o comprimento do vetor controlar cada passagem do laço
Uma arquitetura vetorial expressa uma operação sobre uma sequência de elementos e armazena o comprimento do vetor ativo em um registrador. O mesmo programa pode ser executado em implementações com capacidades diferentes de registradores vetoriais.
Separe capacidade, comprimento e vias
A extensão vetorial RISC-V, RVV, versão 1.0, foi ratificada em 2021. Ela oferece 32 registradores vetoriais, de v0 a v31. Cada implementação escolhe a largura de seus registradores, VLEN, como uma potência de dois. A largura dos elementos e o agrupamento de registradores determinam quantos elementos cabem.
O comprimento ativo, vl, é o número de elementos tratados pelas próximas instruções vetoriais. vsetvli configura a operação vetorial a partir da quantidade restante de elementos e do formato desejado para eles, retornando o vl selecionado. O código avança pelo valor retornado. Isso importa porque o código portável deve usar o comprimento real selecionado pela implementação.
Vias são os pipelines paralelos que executam a operação vetorial. Uma adição de 32 elementos em quatro vias leva cerca de oito ciclos após o início do pipeline. Um vetor de 32 elementos não exige 32 unidades aritméticas. Vetores mais longos e mais vias são escolhas de projeto distintas.
Particione um laço em blocos
O particionamento do laço em blocos divide um laço longo em partes do tamanho de um vetor. Para 100 elementos e um máximo de 32 por operação, uma sequência válida de comprimentos é 32, 32, 32 e 4. Cada passagem carrega a próxima parte, calcula, armazena e reduz a quantidade restante pelo seu vl.
DAXPY sobre 1.000 números de precisão dupla pode, da mesma forma, usar 31 passagens de 32 seguidas por uma passagem de oito, totalizando 32 passagens. RVV pode escolher outros comprimentos válidos perto do fim, portanto o laço usa o vl retornado em vez de supor uma divisão final específica. Definir o comprimento ativo trata o trecho final curto sem um laço escalar separado para o restante.
O padrão de controle do laço é:
- Solicite um comprimento para os elementos restantes.
- Carregue e calcule essa quantidade de elementos.
- Armazene os resultados.
- Avance os ponteiros e subtraia o comprimento retornado.
Uma instrução vetorial descreve muitas operações sobre elementos, reduzindo o trabalho de busca e decodificação em comparação com um corpo escalar repetido para cada elemento.
Alimente operações dependentes e dados não contíguos
O encadeamento permite que uma instrução vetorial consumidora comece a usar os primeiros resultados antes que a produtora tenha terminado os elementos posteriores. Em uma multiplicação seguida de uma adição, o primeiro produto pode entrar no pipeline de adição enquanto os produtos posteriores ainda estão sendo formados.
Uma máscara, normalmente no registrador v0 de RVV, seleciona quais elementos são atualizados. Uma carga com passo constante acessa elementos com um espaçamento fixo em bytes. Em uma matriz de precisão dupla de 100 por 100 armazenada por linhas, descer uma coluna avança 100 elementos, ou 800 bytes. Cargas e armazenamentos indexados usam endereços explícitos para dados irregulares.
Arquiteturas vetoriais e extensões de largura fixa são ambas SIMD na taxonomia de Flynn. Extensões de largura fixa codificam larguras específicas; código RVV expressa comprimentos que se adaptam ao hardware disponível. Ambas ainda precisam de uma ordem de execução que respeite as dependências de dados do laço.
Principais conclusões
- O comprimento do vetor indica quantos elementos uma operação trata; as vias indicam quantos podem avançar juntos.
- O código RVV avança pelo comprimento real retornado por
vsetvli. - O particionamento do laço em blocos processa um vetor longo em partes do tamanho de um vetor.
- O encadeamento sobrepõe operações vetoriais dependentes elemento a elemento.
- Máscaras, passos e acessos indexados permitem tratar dados menos regulares.
3.3 Mantenha uma GPU ocupada com muitos warps
Uma CPU concentra recursos em baixa latência para poucas threads. Uma GPU concentra recursos em alta vazão entre muitas threads com paralelismo de dados. Escolher entre elas exige analisar a tarefa inteira, incluindo a movimentação de dados.
Threads são executadas em multiprocessadores de streaming
Uma GPU da NVIDIA contém muitos multiprocessadores de streaming, ou SMs. Um SM tem vias aritméticas, escalonadores de warps, um grande banco de registradores e memória compartilhada rápida no chip. Um “núcleo CUDA” designa uma via aritmética, não um núcleo completo e independente semelhante ao de uma CPU. A AMD chama o grupo de processamento correspondente de unidade de computação.
A NVIDIA agrupa threads em warps de 32. Uma instrução emitida opera sobre as threads ativas do warp, cada uma com seus próprios valores de registradores e dados. Isso é SIMT, instrução única e múltiplas threads. A AMD usa wavefronts, com 32 ou 64 threads, dependendo da arquitetura.
Um SM mantém muitos warps residentes. Quando um espera pela memória, o escalonador seleciona outro warp pronto. Ter mais threads prontas do que vias oculta a latência; isso não reduz a latência de um acesso individual à DRAM.
A divergência deixa vias inativas
Se threads de um warp seguirem ramos diferentes, o warp executará os caminhos necessários com as outras threads desativadas por máscara. Um if-else dividido igualmente, com ramos de mesmo custo, pode levar aproximadamente o dobro do tempo de um caminho porque ambos precisam ser executados. Um desvio pode não causar prejuízo quando sua condição é uniforme dentro de cada warp, mesmo que warps diferentes escolham caminhos diferentes.
Faça os acessos à memória trabalharem em conjunto
Registradores por thread armazenam valores privados. A memória compartilhada por bloco é um armazenamento no chip gerenciado pelo programa. As caches L1 e L2 permitem reutilização automática, enquanto a memória global é a DRAM da GPU, como GDDR ou HBM.
Quando 32 threads leem palavras consecutivas de 4 bytes, seu intervalo de 128 bytes pode ser atendido por um pequeno número de transações largas. Essa coalescência usa a largura de banda com eficiência. Endereços espalhados podem exigir muitas transações para os mesmos dados úteis. A reutilização na memória compartilhada pode reduzir ainda mais o tráfego repetido da memória global.
Inclua o tempo de transferência
Para uma GPU dedicada, entradas e resultados atravessam um enlace como PCIe ou NVLink. Enviar 800 MB e receber 400 MB a uma taxa efetiva de 20 GB/s transfere 1,2 GB em 0,06 s, ou 60 ms. Acrescentar um kernel de 10 ms resulta em 70 ms no total. Uma CPU que termina em 50 ms vence essa comparação apesar do cálculo muito mais rápido da GPU.
Manter dados na GPU ao longo de vários kernels evita transferências repetidas. Tarefas grandes e regulares também podem oferecer trabalho aritmético útil suficiente para compensar os custos de movimentação e lançamento. Tarefas pequenas, sequenciais e com muitos desvios frequentemente favorecem uma CPU.
Especialize ainda mais quando o trabalho permitir
Um sistema heterogêneo usa a CPU para executar o programa e o sistema operacional e um acelerador para as partes adequadas. Aceleradores de domínio específico, como TPUs e NPUs, dedicam hardware a uma tarefa mais restrita, frequentemente multiplicação de matrizes com inteiros de 8 bits ou ponto flutuante de 16 bits. A especialização pode melhorar o desempenho por watt nesse domínio, ao mesmo tempo que reduz a variedade de trabalhos que o hardware trata bem.
Principais conclusões
- Um SM escalona warps; um núcleo CUDA é uma via aritmética.
- Warps da NVIDIA contêm 32 threads com dados separados e emissão de instruções compartilhada.
- Warps residentes e prontos ocultam esperas pela memória.
- Divergência e acessos espalhados desperdiçam tempo das vias e largura de banda da memória.
- Decisões de transferir trabalho incluem as transferências e o tempo do kernel.
- Aceleradores especializados trocam flexibilidade por eficiência em um domínio mais restrito.
3.4 Mapeie elementos de vetores para threads de GPU
Um kernel de GPU é executado uma vez por thread lançada. O hospedeiro lança uma grade de blocos de threads, e cada thread calcula qual parte dos dados lhe cabe. CUDA chama a CPU de hospedeiro e a GPU de dispositivo; OpenCL usa os termos relacionados work-item e work-group.
Calcule um índice único
Para um lançamento unidimensional, o índice do elemento é blockIdx.x * blockDim.x + threadIdx.x. Com 256 threads por bloco, a thread 5 no bloco 2 trata o elemento 517: os dois blocos anteriores correspondem a 512 elementos, e a thread acrescenta um deslocamento de cinco. Os índices de threads e blocos começam em zero.
Um kernel SAXPY aplica uma multiplicação e uma adição a cada número de ponto flutuante:
__global__ void saxpy(int n, float a, float *x, float *y) {
int i = blockIdx.x * blockDim.x + threadIdx.x;
if (i < n) {
y[i] = a * x[i] + y[i];
}
}
A grade substitui o laço comum sobre os elementos. Cada thread ativa atualiza seu próprio y[i]; threads vizinhas usam endereços vizinhos, favorecendo a coalescência.
Arredonde o número de blocos para cima
Para 1.000.000 de elementos e 256 threads por bloco, a grade precisa de blocos. Eles lançam 1.000.192 threads. As últimas 192 têm índices fora do vetor, portanto a condição i < n impede seus acessos à memória. Arredondar para baixo lançaria threads insuficientes e deixaria elementos válidos sem tratamento.
Um bloco de 256 threads forma oito warps. Blocos podem ser atribuídos a qualquer SM e executados em qualquer ordem. A correção do programa não deve depender de o bloco 0 terminar antes do bloco 1.
Organize o trabalho do hospedeiro e do dispositivo
Um hospedeiro típico aloca armazenamento no dispositivo, copia as entradas, lança saxpy<<<3907, 256>>>(n, 2.0f, d_x, d_y) e obtém os resultados. O lançamento é assíncrono: a CPU pode continuar enquanto o kernel é executado. O hospedeiro deve esperar por meio de sincronização ou de uma cópia bloqueante adequada dos resultados antes de usar os dados concluídos.
Coopere dentro de um bloco
Threads de um bloco podem trocar valores pela memória compartilhada e se encontrar em __syncthreads(). Toda thread participante dessa barreira de todo o bloco deve alcançá-la. Colocar a barreira dentro de if (i < n) não é seguro quando apenas algumas threads satisfazem a condição.
Para uma redução de 1.024 valores na memória compartilhada, 512 threads somam pares, depois 256 combinam os resultados, depois 128 e assim por diante. Dez estágios de divisão pela metade deixam uma soma. Uma barreira entre estágios impede que uma thread consuma um resultado parcial antes que sua produtora o escreva.
Um lançamento comum não tem barreira que abranja toda a grade. Blocos separados podem escrever somas parciais e um segundo kernel pode combiná-las, ou operações atômicas adequadas podem atualizar um resultado global. Uma barreira de bloco, por si só, não pode coordenar blocos diferentes. Um laço com passo igual ao tamanho da grade é outro padrão de mapeamento: cada thread trata vários elementos, avançando pelo tamanho total da grade.
Principais conclusões
- Calcule índices a partir do tamanho do bloco, do índice do bloco e do índice da thread.
- Arredonde o número de blocos para cima e proteja acessos fora dos limites.
- Lançamentos de kernel são assíncronos em relação ao hospedeiro.
- A memória compartilhada e
__syncthreads()permitem cooperação dentro de um bloco. - Blocos comuns são executados independentemente; combinar resultados de blocos exige outro mecanismo.
4Compartilhe memória e acompanhe a posse de blocos de cache
Um espaço de endereçamento comum permite que threads troquem valores por operações comuns de memória. Caches privadas tornam essas operações rápidas, mas criam várias cópias que precisam de coordenação. Acompanhe uma redução desde o trabalho local até os resultados compartilhados e depois acompanhe as permissões que mantêm coerentes as cópias armazenadas em cache. O armazenamento do diretório e o falso compartilhamento relacionam esses mecanismos de correção ao custo de desempenho da disposição dos dados na memória.
4.1 Compartilhe um espaço de endereçamento e combine resultados parciais
Um multiprocessador de memória compartilhada oferece a seus processadores um espaço de endereçamento físico. As threads se comunicam com cargas e armazenamentos em variáveis compartilhadas, enquanto mantêm valores privados, como somas parciais locais.
Endereços compartilhados podem ter custos diferentes
Em UMA, acesso uniforme à memória, o tempo de acesso à memória é aproximadamente o mesmo a partir de qualquer processador. Em NUMA, acesso não uniforme à memória, um soquete acessa sua memória local mais rapidamente do que a memória de outro soquete. O espaço de endereçamento é compartilhado mesmo que a memória física seja distribuída.
Com 70% de acessos locais a 80 ns e 30% de acessos remotos a 140 ns, a média ponderada é ns. Mover dados para perto de quem mais os usa reduz a parcela remota. Contar todo acesso como local subestimaria o tempo.
Uma organização comum de caches oferece a cada núcleo caches L1 privadas de instruções e dados, frequentemente uma L2 privada e uma cache compartilhada de último nível. Um anel ou uma malha conecta os núcleos e as caches. Memória compartilhada descreve o endereçamento; ela não exige que todos os núcleos usem uma cache comum.
Divida, calcule e reduza
Para somar 64.000 valores em 64 núcleos, cada núcleo trata 1.000 valores. As 64 somas parciais podem ser combinadas em uma árvore de redução. O número de somadores ativos cai pela metade em cada estágio: 32, 16, 8, 4, 2 e 1. Seis estágios combinam os resultados parciais.
Usar aproximadamente 1.000 etapas de adição local mais seis etapas de combinação resulta em cerca de 1.006 etapas no caminho mais longo, antes da sobrecarga. A árvore evita que cada entrada atualize um contador compartilhado. Cada estágio depende dos valores concluídos do estágio anterior, portanto as unidades de trabalho se encontram em barreiras entre estágios.
OpenMP pode expressar isso com #pragma omp parallel for reduction(+:sum). Ele divide as iterações, dá às threads somas parciais privadas e as combina. Threads POSIX oferecem controle mais explícito sobre o gerenciamento de threads.
Torne uma atualização indivisível
Uma operação de leitura-modificação-escrita atômica torna uma atualização indivisível do ponto de vista dos outros processadores. A troca atômica e a busca e soma atômica são exemplos. Uma carga seguida de um armazenamento comum são duas operações separadas, portanto outra thread pode intervir.
RISC-V oferece lr.w e sc.w. A carga reservada lê uma palavra e estabelece uma reserva. O armazenamento condicional tenta escrever e informa sucesso ou falha. Uma escrita intermediária na posição reservada faz a tentativa falhar; o software tenta novamente. A reserva não bloqueia outros processadores, e a falha também pode ocorrer por outros motivos permitidos. Essas operações primitivas dão suporte a mecanismos de sincronização.
Observe os gargalos compartilhados
Se cada núcleo consegue transferir continuamente 15 GB/s, mas o soquete fornece 60 GB/s, cerca de quatro desses fluxos saturam a largura de banda. Mais núcleos não podem aumentar a taxa de dados do soquete. A comunicação por caches também exige trabalho: quem escreve sem permissão de escrita deve obter a posse e invalidar outras cópias. Quem escreve e já possui um bloco no estado modificado pode continuar localmente; leitores posteriores podem precisar buscar uma nova cópia.
Principais conclusões
- Memória compartilhada significa um espaço de endereçamento, com dados e caches privados ainda possíveis.
- NUMA torna a localização dos dados parte do desempenho.
- Somas parciais locais e uma árvore de redução limitam a disputa por recursos.
- Barreiras separam fases dependentes do trabalho.
- Operações atômicas protegem atualizações indivisíveis; LR/SC tenta novamente após tentativas malsucedidas.
- Núcleos compartilham a largura de banda da memória e arcam com o custo das transferências de posse.
4.2 Mantenha coerentes as cópias de uma posição
Caches privadas melhoram a latência, mas podem manter várias cópias da mesma posição de memória. A coerência de cache impede que essas cópias apresentem históricos conflitantes das escritas nessa posição.
Por que atualizar a memória não basta
Comece com X = 0 na memória. O núcleo A lê e armazena zero em sua cache; o núcleo B faz o mesmo. A escreve um em sua cache com escrita posterior. Sem um protocolo de coerência, B pode acertar em sua própria cache e continuar lendo zero. Escrever diretamente na memória não corrigiria a cópia já armazenada na cache de B.
A coerência funciona na granularidade de blocos de cache, normalmente de 64 bytes. Um controlador rastreia o estado de cada bloco e segue as regras do protocolo quando processadores leem ou escrevem nele. A migração move dados úteis para a cache de quem os usa no momento. A replicação permite que vários leitores mantenham cópias limpas. A coerência deve preservar ambos os benefícios enquanto controla as escritas.
Três propriedades necessárias
| Propriedade | O que exige |
|---|---|
| Ordem do programa para uma posição | Um processador lê sua própria escrita anterior se nenhuma escrita intermediária a substituir. |
| Propagação de escritas | Uma escrita acaba se tornando visível aos outros processadores. |
| Serialização de escritas | Todos os processadores concordam com a ordem das escritas nessa posição. |
Se uma posição recebe uma escrita de um seguida de uma escrita de dois, os leitores não podem discordar sobre qual escrita veio depois. Observar a escrita posterior e depois a anterior inverteria esse histórico. Uma nova escrita subsequente poderia, é claro, armazenar o valor um novamente; a serialização diz respeito a eventos de escrita, não à possibilidade de um valor numérico se repetir.
Controle a posse e as cópias
Em um protocolo de invalidação na escrita, quem escreve obtém permissão exclusiva de escrita e invalida outras cópias armazenadas em cache. Uma leitura posterior de um bloco invalidado sofre uma falta e busca os dados atuais. Essa é uma falta de coerência, além das faltas compulsórias, de capacidade e de conflito.
Um protocolo de atualização na escrita envia novos valores às cópias existentes. Escritas repetidas podem tornar isso custoso. A monitoração de coerência difunde requisições para que as caches possam reagir. Um diretório rastreia os detentores de cópias e direciona mensagens às caches pertinentes.
Coerência, ordenação e atomicidade
A coerência diz respeito a uma posição. Um modelo de consistência de memória define as ordenações observáveis permitidas e os resultados de leituras e escritas, incluindo operações em posições diferentes. A consistência sequencial exige um resultado que corresponda a um entrelaçamento que preserve a ordem do programa de cada processador. Modelos relaxados permitem mais reordenações; instruções de barreira de memória impõem a ordenação necessária quando preciso.
Nem cópias coerentes nem uma ordenação consistente tornam atômico um incremento de várias instruções. Suponha que duas threads incrementem um contador compartilhado inicialmente igual a cinco. Uma sequência possível é: A lê cinco, B lê cinco, A escreve seis, B escreve seis. Cada leitura e escrita pode ser coerente, mas o contador final é seis em vez de sete. O programa precisa de uma atualização atômica ou de sincronização adequada para preservar ambos os incrementos.
Principais conclusões
- A coerência é necessária mesmo quando as caches escrevem diretamente na memória.
- Sistemas coerentes preservam a ordem do programa para uma posição, propagam escritas e serializam escritas.
- A invalidação na escrita remove outras cópias utilizáveis antes que um novo detentor escreva.
- Dados invalidados podem causar faltas de coerência.
- Modelos de consistência tratam da ordenação entre posições.
- Uma leitura coerente e uma escrita coerente ainda formam duas operações separadas.
4.3 Acompanhe mudanças de posse em MSI e MESI
Um controlador de cache que monitora a coerência observa requisições em uma interconexão de difusão. Para acompanhar um protocolo, mantenha um estado para a cópia do bloco de cada núcleo e atualize todas as cópias afetadas após cada acesso.
Leia os estados como permissões
| Estado | Cópia utilizável? | Quem mais pode possuí-la? | A memória está atualizada? |
|---|---|---|---|
| Modificado (M) | Sim, leituras e escritas | Nenhuma outra cópia válida | Não |
| Compartilhado (S) | Sim, leituras | Outros leitores podem ter cópias | Sim |
| Inválido (I) | Não | Outras caches podem ter cópias | Depende do estado delas |
| Exclusivo (E), apenas MESI | Sim, leituras e transição silenciosa para escrita | Nenhuma outra cópia válida | Sim |
No MSI básico, uma falta de leitura envia uma leitura ao barramento e carrega o bloco em S. Escrever em um bloco em S exige uma promoção para invalidar outras cópias. Escrever a partir de I exige uma requisição de leitura exclusiva para buscar os dados e obter a posse. Quem escreve termina em M. Um acerto em M não exige transação de coerência.
Acompanhe cinco acessos
Comece com X = 0 na memória e A e B no estado inválido.
- A lê X. Uma leitura no barramento fornece zero. Estados: A = S, B = I.
- B lê X. Outra leitura no barramento fornece zero. Estados: A = S, B = S.
- A escreve um. Sua promoção invalida B. Estados: A = M, B = I.
- B lê X. B sofre uma falta; A fornece um e passa a S. No MSI básico, a memória também é atualizada. Estados: A = S, B = S.
- B escreve dois. Sua promoção invalida A. Estados: A = I, B = M.
Cada acesso nesse acompanhamento exige uma transação no barramento. O quarto acesso é a verificação importante de posse: a memória ainda tinha o valor antigo antes de A fornecer seus dados modificados.
O que o estado exclusivo economiza
O MESI acrescenta E para uma única cópia limpa em cache. Se A lê um bloco que não está em cache e nenhuma outra cache o possui, A recebe E. Uma escrita posterior muda E para M silenciosamente, pois não há outras cópias a invalidar. O MSI carregaria primeiro em S e depois enviaria uma promoção para essa escrita.
Se outro núcleo lê enquanto A possui E, ambos passam a S. M e E têm um único detentor válido, mas apenas M contém dados mais recentes que a memória.
Escritas repetidas e escala
Quem escreve e obteve M pode atualizar o bloco dez vezes sem dez novas invalidações. Um esquema de atualização na escrita enviaria os valores alterados aos detentores de cópias.
A monitoração por difusão se torna custosa à medida que mais núcleos observam cada requisição. Estruturas de diretório reduzem essa distribuição. Protocolos mais elaborados acrescentam estados úteis: o estado Owned do MOESI permite uma cópia modificada compartilhada, e o MESIF designa um detentor Forward para responder às requisições.
Principais conclusões
- MSI rastreia cópias nos estados modificado, compartilhado e inválido.
- Quem escreve precisa de posse exclusiva; acertos no estado modificado permanecem locais.
- Uma leitura remota faz o detentor no estado modificado fornecer dados atuais e passar a compartilhado no MSI básico.
- O estado exclusivo do MESI permite que um único leitor com cópia limpa escreva sem uma transação de promoção.
- Os estados exclusivo e modificado têm um único detentor, mas apenas o modificado contém dados alterados.
4.4 Rastreie detentores de cópias e separe dados independentes
Difundir cada requisição de coerência se torna custoso em máquinas grandes. Um diretório registra quais caches podem possuir cada bloco para que as requisições possam ser enviadas a essas caches. O mesmo rastreamento em nível de bloco também explica um problema comum de desempenho: o falso compartilhamento.
Consulte a origem de um bloco
Cada bloco tem uma entrada no diretório de origem que registra se ele não está em cache, está compartilhado ou modificado e quais caches o possuem. As origens são distribuídas entre nós ou partes do diretório, distribuindo o armazenamento e o tratamento de requisições.
Uma falta de leitura vai para a origem. Se a memória tiver os dados atuais, ela poderá fornecê-los e o diretório registrará o novo detentor de cópia. Se outra cache possuir uma cópia no estado modificado, a origem encaminhará a requisição a essa detentora para que os dados atuais sejam fornecidos. Em um protocolo básico de diretório, isso também atualiza a memória novamente.
Para escrever sem já ter a posse no estado modificado, um núcleo pede permissão à origem. O diretório envia invalidações aos detentores registrados, espera as confirmações e concede a posse exclusiva. Acertos de escrita repetidos em M não precisam de outras mensagens de coerência. A passagem pelo diretório acrescenta latência, mas o tráfego ponto a ponto evita consultar todas as caches sobre cada bloco. Filtros de monitoração no chip atendem a um objetivo relacionado, restringindo as requisições aos possíveis detentores.
Estime o armazenamento do diretório
Um vetor de presença completo tem um bit por núcleo por bloco. Para 64 núcleos, são 64 bits, ou oito bytes. Em relação a um bloco de dados de 64 bytes, apenas os bits de presença custam , ou 12,5%. Com 256 núcleos, o vetor de 32 bytes custa 50%. Bits de estado acrescentam mais. Listas limitadas de detentores, vetores de granularidade mais grossa e o rastreamento apenas de blocos em cache reduzem esse custo de armazenamento.
Reconheça o falso compartilhamento
O compartilhamento verdadeiro ocorre quando núcleos trocam dados pela mesma palavra. O falso compartilhamento ocorre quando eles acessam variáveis diferentes dentro de um bloco de cache e pelo menos um escreve. As variáveis são independentes no programa, mas a unidade de coerência é maior que cada uma delas.
Duas threads incrementam contadores separados de 8 bytes em 0x1000 e 0x1008. Com blocos de 64 bytes, seus números de bloco são e . Cada mudança de posse transfere a permissão para ambos os contadores em conjunto. Escritas alternadas frequentes podem fazer o bloco passar de uma cache para outra mesmo que nenhuma thread precise do valor da outra.
Mover o segundo contador para 0x1040 o coloca no bloco 65. Preenchimento ou alinhamento pode separar dados de cada thread; agrupar valores por quem os escreve também ajuda. Um acumulador local escrito de volta uma vez reduz o tráfego de posse sem acrescentar preenchimento a cada valor.
Quem escreve e quem lê uma variável vizinha também podem sofrer falso compartilhamento: quem escreve invalida o bloco que, de outra forma, seria útil ao leitor. Dois leitores sozinhos não o causam. O falso compartilhamento acrescenta tráfego e atraso; ele não faz, por si só, que atualizações de variáveis separadas produzam valores incorretos. Meça os padrões de acesso e a posição das linhas de cache antes de alterar uma organização de dados.
Principais conclusões
- Diretórios enviam mensagens de coerência aos detentores registrados por meio da origem de um bloco.
- O armazenamento de vetores de presença cresce com o número de núcleos e de blocos.
- O falso compartilhamento envolve variáveis diferentes em um bloco e pelo menos uma escrita.
- Separe a posse com preenchimento, posicionamento ou menos escritas compartilhadas.
5Conecte nós e opere em escala de centro de dados
Além de uma máquina de memória compartilhada, os nós trocam mensagens por uma rede. Um aglomerado de computadores deve posicionar dados e organizar a comunicação com o mesmo cuidado com que divide os cálculos. Em escala de centro de dados, a rede funciona junto com a alimentação elétrica, a refrigeração e as falhas rotineiras de hardware. Compare a capacidade da rede com um corte crítico e depois use cálculos de energia e latência para avaliar como um grande conjunto de servidores fornece um serviço confiável.
5.1 Compare nós de memória privada e suas redes
Um aglomerado de computadores conecta computadores completos, cada um com sua própria memória e sistema operacional. Os nós cooperam por mensagens explícitas. A localização dos dados e o custo de comunicação, portanto, passam a fazer parte do modelo de desempenho do programa.
Particione dados e combine resultados
MPI, a interface de passagem de mensagens, dá a cada processo um identificador no comunicador e operações como envio, recebimento, difusão e redução. Um programa SPMD pode usar esses identificadores para selecionar os dados de cada processo. Um ponteiro no espaço de endereçamento privado de um nó não é uma referência comum de memória compartilhada aos dados de outro nó.
Se um milhão de valores já estiverem distribuídos por 100 nós, cada nó somará 10.000 localmente. Uma redução em árvore combina as somas parciais em sete rodadas porque . Essas rodadas envolvem mensagens de rede, não apenas adições locais. Manter os dados perto do trabalho que os usa reduz as transferências.
Aglomerados podem crescer com componentes padronizados, e o hardware com falha pode ser substituído. Uma aplicação ainda pode precisar de recuperação ou reinício após a falha de um nó; nós substituíveis, por si só, não preservam o progresso de uma tarefa interrompida.
Meça mais que a velocidade do enlace
Latência é o tempo que uma mensagem leva para chegar. Largura de banda do enlace é a taxa de dados de um enlace. A largura de banda total da rede soma a capacidade dos enlaces e descreve um agregado ideal com todos os enlaces ocupados. A largura de banda de bisseção soma a capacidade que atravessa o corte de menor capacidade que divide os nós em metades iguais.
Para enlaces de mesma capacidade e largura de banda , compare redes de 64 nós usando uma convenção consistente de contagem de enlaces:
| Topologia | Enlaces | Capacidade total | Capacidade de bisseção |
|---|---|---|---|
| Anel | 64 | ||
| Malha de 8 por 8 | 112 | ||
| Toro de 8 por 8 | 128 | ||
| Hipercubo de 6 dimensões | 192 | ||
| Totalmente conectada | 2016 |
A malha tem oito linhas de sete enlaces horizontais e oito colunas de sete enlaces verticais, totalizando 112. Conectar as extremidades das duas dimensões produz os 128 enlaces do toro. Cada nó do hipercubo tem seis vizinhos, resultando em enlaces porque cada enlace é contado em duas extremidades.
Acompanhe o corte e depois considere o custo
Um corte que divide um anel em duas metades atravessa apenas dois enlaces. Muitas mensagens podem, portanto, disputar esse limite apesar dos 64 enlaces do anel no total. Uma rede totalmente conectada tem enlaces entre suas duas metades, mas precisa de enlaces no total.
Mais enlaces podem melhorar a largura de banda e reduzir saltos, ao mesmo tempo que aumentam o número de portas de comutadores, cabos e a potência necessária. Barramentos compartilhados têm um único recurso de comunicação compartilhado; malhas e toros distribuem os enlaces pelo espaço. Grandes aglomerados frequentemente usam redes comutadas de múltiplos estágios, como árvores gordas. Sua utilidade depende do padrão de tráfego e da capacidade agregada. Para comunicação entre metades de uma máquina, a bisseção revela um limite que o total oculta.
Principais conclusões
- Nós de aglomerados usam espaços de endereçamento privados e comunicação explícita.
- Identificadores MPI identificam processos; operações coletivas combinam trabalho distribuído.
- Rodadas de mensagens acrescentam custo além da aritmética local.
- A largura de banda total mede a capacidade agregada dos enlaces; a bisseção mede um corte crítico na máquina.
- A capacidade da rede envolve compromissos com portas, cabos, potência e saltos.
5.2 Meça um centro de dados como um computador
Um computador em escala de centro de dados combina dezenas de milhares de servidores com alimentação elétrica, refrigeração e uma rede para fornecer serviços de internet. Requisições independentes fornecem trabalho paralelo, enquanto estruturas de processamento em lote, como MapReduce, dividem grandes tarefas de processamento de dados entre máquinas.
Ajuste o projeto ao serviço
Sistemas em escala de centro de dados priorizam custo por requisição, eficiência energética e disponibilidade. O software tenta novamente o trabalho, replica dados e desvia das máquinas com falha. Um supercomputador prioriza mais frequentemente um único programa científico fortemente acoplado e uma interconexão rápida.
Os servidores se conectam a comutadores no topo dos racks, que se conectam por níveis superiores de comutadores. Níveis adicionais aumentam a latência de comunicação. Os enlaces de subida frequentemente são sobressubscritos, ou seja, sua capacidade é inferior à capacidade agregada dos enlaces dos servidores. Algumas redes não bloqueantes no estilo Clos oferecem capacidade suficiente nos níveis superiores para evitar essa restrição.
Quarenta servidores com enlaces de 10 Gbit/s oferecem 400 Gbit/s a um comutador de rack. Quatro enlaces de subida de 25 Gbit/s fornecem 100 Gbit/s, portanto a proporção é 4:1. Se todos os servidores enviarem dados para fora do rack ao mesmo tempo e dividirem a capacidade igualmente, cada um terá uma média de 2,5 Gbit/s. Um servidor com pouca carga pode usar mais quando os outros estão ociosos.
Separe a sobrecarga da instalação do cálculo útil
A efetividade do uso de energia, PUE, é a energia total da instalação dividida pela energia dos equipamentos de TI no mesmo período. Dez MW de carga constante de TI mais 1,5 MW de sobrecarga de refrigeração e distribuição resultam em . O valor ideal é 1,0. O Google informou uma PUE anual de 1,09 para o conjunto de suas instalações em 2025.
A PUE mede a sobrecarga da instalação, não os cálculos úteis por joule. Servidores ociosos ou ineficientes podem desperdiçar energia dentro da parcela de TI mesmo quando a instalação tem uma PUE excelente.
Para 50.000 servidores com média de 300 W, a potência de TI é de 15 MW. Com PUE de 1,2, a potência da instalação é de 18 MW. Mantida por 8.760 horas, ela consome 157.680 MWh; apenas a sobrecarga consome 26.280 MWh. Equipamentos de alimentação elétrica, refrigeração, eletricidade, servidores e edifícios contribuem para o custo de propriedade.
Uma carga baixa ainda pode consumir bastante potência
Proporcionalidade energética significa que a potência deve crescer proporcionalmente à carga. Um servidor com potência ociosa de 150 W e pico de 300 W, com crescimento linear, consome W com 30% de carga. Ele usa 65% da potência de pico para 30% do trabalho de pico. Medições históricas em centros de dados de grande escala encontraram muitos servidores operando entre aproximadamente 10% e 50% de utilização, tornando a potência ociosa importante.
Planeje para falhas e respostas lentas
Se 50.000 servidores apresentarem, cada um, uma média de uma falha a cada dez anos, espera-se que o conjunto apresente 5.000 falhas por ano, cerca de 14 por dia. Essa expectativa justifica redundância e novas tentativas; ela não prevê exatamente 14 falhas todos os dias.
Uma requisição que precisa de respostas de muitos servidores espera pela resposta necessária mais lenta. Se cada um de 100 servidores tiver, independentemente, uma chance de 1% de estar lento, a chance de nenhum estar lento é . Assim, pelo menos um está lento com probabilidade . A latência de cauda de um servidor se torna um atraso comum em nível de requisição quando a distribuição entre servidores é grande.
Principais conclusões
- O projeto em escala de centro de dados equilibra vazão do serviço, energia, custo e disponibilidade.
- Enlaces de subida sobressubscritos limitam o tráfego simultâneo para fora do rack.
- A PUE mede a sobrecarga da instalação, enquanto a eficiência dos servidores mede o trabalho útil dentro da parcela de TI.
- A potência ociosa torna a baixa utilização custosa.
- Grandes conjuntos de servidores apresentam falhas rotineiras, e a distribuição de requisições amplifica a latência de cauda.
Exercícios resolvidos de Processadores paralelos
1Escolha uma fonte útil de trabalho paralelo
15 passos
- 1IntroduçãoMais trabalho sem aquecer mais o clock
Um serviço precisa tratar mais tarefas, mas aumentar o clock da CPU excederia seu limite de potência. O hardware paralelo realiza mais trabalho dentro de um limite de potência fixo. Os projetistas podem acrescentar núcleos (MIMD), ampliar operações sobre dados (SIMD) ou manter mais threads prontas (multithreading). Cada escolha precisa de uma fonte adequada de trabalho. Comece identificando o que pode ser executado em conjunto e depois pergunte como esse trabalho chega ao hardware e se o benefício é um tempo de resposta menor ou maior capacidade de atendimento (vazão).
- 2ExplicaçãoA tensão tem efeito quadrático
A potência dinâmica segue aproximadamente . Com a capacitância inalterada, reduzir a tensão e a frequência para 85% multiplica a potência por . Essa grande redução ajuda a explicar por que vários núcleos modestos podem ser atraentes. A barreira de potência surgiu quando reduções de tensão já não conseguiam compensar o custo em calor e potência de elevar as frequências de clock.
- 3ExemploSepare uma requisição de muitas requisições
Se quatro downloads independentes forem executados em quatro núcleos, a máquina poderá concluir mais downloads por segundo mesmo que cada download leve o mesmo tempo. Isso é um ganho de vazão decorrente de trabalho em nível de requisição. Se uma imagem for dividida em regiões independentes e quatro threads as processarem, essa imagem poderá terminar mais cedo. O hardware paralelo atende aos dois objetivos, mas o programa deve disponibilizar o trabalho adequado.
- 4ExplicaçãoEncontre trabalho dentro de um programa
Um pipeline sobrepõe instruções de um fluxo: ILP. Uma operação sobre vetores se repete entre elementos: DLP. Threads separadas fornecem TLP, com seus próprios estados de execução e um espaço de endereçamento de processo compartilhado. Essas formas podem coexistir. Um programa com threads que opera sobre vetores pode dividir regiões entre núcleos, usar SIMD dentro de cada região e executar essas instruções pelo pipeline de cada núcleo.
- 5DesafioAlternar conta?
Um núcleo alterna entre duas tarefas. Ambas estão em andamento durante um segundo, mas suas instruções nunca são executadas no mesmo instante. Isso é execução paralela?
---reveal---
É execução concorrente por compartilhamento de tempo. O paralelismo exige operações simultâneas em recursos de hardware distintos. Outro núcleo poderia oferecer essa simultaneidade, mas ainda precisaria de trabalho pronto para executar.
- 6ExplicaçãoPergunte quem escolhe a próxima instrução
A taxonomia de Flynn começa pelos fluxos de instruções e de dados. Um núcleo escalar convencional é SISD. Uma operação larga que aplica uma instrução a vários elementos é SIMD. Processadores controlados independentemente que tratam seus dados são MIMD. MISD combina múltiplos fluxos de instruções com um fluxo de dados e tem poucos exemplos práticos inequívocos. Conte os fluxos em um nível de hardware escolhido.
- 7ExemploUm programa, progresso separado
Quatro unidades de trabalho usam seus identificadores para dividir um vetor de 4.000 elementos em quatro regiões de 1.000 elementos. Elas executam o mesmo programa, mas uma pode chegar à sua adição final enquanto outra ainda carrega valores. Isso é software SPMD em hardware MIMD. Compartilhar o texto do programa não exige emissão de instruções em conjunto. Uma instrução SIMD dentro de qualquer unidade acrescentaria outro nível de execução paralela.
- 8DesafioClassifique o nível escolhido
Uma CPU de múltiplos núcleos controlados independentemente usa adições vetoriais dentro de cada núcleo. Quais são as classes entre os núcleos e dentro de uma adição vetorial?
---reveal---
Os núcleos formam hardware MIMD porque escolhem instruções independentemente. Cada adição vetorial é SIMD porque uma instrução opera sobre vários elementos de dados. Uma única máquina pode ter ambas as descrições quando elas se referem a níveis diferentes.
- 9ExplicaçãoMantenha o estado de execução pronto
Um contexto de thread de hardware armazena um contador de programa e registradores. Vários contextos podem compartilhar as unidades aritméticas e as caches de um núcleo. Quando uma requisição de memória para uma thread, outra thread pronta pode preencher a capacidade de execução ociosa. O sistema operacional vê cada contexto como um processador lógico. Dois contextos em um núcleo ainda compartilham os recursos físicos de execução desse núcleo.
- 10ExplicaçãoEscolha quando as threads compartilham o núcleo
O multithreading de granularidade fina seleciona uma thread pronta a cada ciclo. O de granularidade grossa troca após uma parada longa, arcando com os custos de troca e de preenchimento do pipeline. O SMT vai além em um núcleo de emissão múltipla: instruções de threads diferentes podem ser emitidas durante o mesmo ciclo. Os três dependem de trabalho útil pronto; nenhum fornece capacidade aritmética adicional ilimitada.
- 11ExemploPrimeiro meça o intervalo ocioso
Uma thread calcula por 20 ciclos e depois espera 200. Seu período é de 220 ciclos, portanto o tempo ativo é . Uma espera longa deixa a maioria dos ciclos sem uso quando nenhuma outra thread está disponível. Mantenha o período completo de cálculo mais espera no denominador. Dividir apenas pela espera descreveria outra razão, não a fração de ciclos decorridos realizando trabalho útil.
- 12ExemploPreencha o intervalo com períodos de trabalho prontos
Com quatro threads escalonadas livremente, cada uma contribuindo com 20 ciclos de cálculo por período de 220 ciclos, a utilização ideal é . Onze threads podem preencher o período: enquanto uma espera 200 ciclos, as outras dez contribuem com 200 ciclos de cálculo. Esse modelo ideal tem troca sem custo e nenhuma disputa adicional; a competição real por largura de banda e cache pode deixar menos trabalho útil pronto.
- 13DesafioOutro contexto resolveria?
As unidades aritméticas de um núcleo já estão totalmente ocupadas, e suas duas threads precisam dessas mesmas unidades. Acrescentar outra thread de hardware forneceria a capacidade de outro núcleo? Explique usando o recurso que elas compartilham.
---reveal---
Não. Um novo contexto fornece outro fluxo de instruções, mas ainda compartilha as unidades de execução ocupadas. Outro núcleo completo acrescenta hardware de execução. O multithreading é mais útil quando preenche capacidade que paradas ou um número limitado de instruções prontas deixam sem uso.
- 14ConexãoRelacione a melhoria do serviço à sua causa
O serviço acrescenta contextos de hardware e agora conclui mais requisições independentes por segundo, enquanto o trabalho de CPU de cada requisição leva um pouco mais de tempo. Esse resultado é compatível com uma melhora de vazão: requisições prontas preenchem posições ociosas enquanto compartilham recursos. Seria enganoso chamá-lo de melhora na latência de uma única requisição. Escolha uma medida de desempenho que corresponda ao trabalho que os usuários precisam concluir.
- 15RecapitulaçãoTome a primeira decisão de hardware
Para uma nova carga de trabalho, primeiro identifique instruções, elementos de dados, threads ou requisições independentes. Depois, localize o nível de hardware que controla seus fluxos de instruções. Se o ganho proposto vier de contextos extras, examine quais paradas deixam capacidade disponível e quais recursos os contextos compartilham. Isso fornece uma base concreta para escolher mais núcleos, operações mais largas ou mais threads prontas antes de medir o resultado.
2Encontre o limite antes de acrescentar processadores
16 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoTrês razões pelas quais hardware extra pode decepcionar
- 2ExplicaçãoEscolha a referência de tempo
- 3ExemploDivida apenas a parte paralela
- 4Ideia-chaveA parte fixa determina o limite total
- 5DesafioA meta de aceleração é possível?
- 6ExplicaçãoMantenha visível a questão da carga de trabalho
- 7ExemploUse a fração da execução paralela
- 8ExemploEspere pela unidade de trabalho mais ocupada
- 9DesafioQuando acrescentar núcleos aumenta o tempo?
- 10ExplicaçãoConte os bytes que saem da memória
- 11ExemploConstrua os dois tetos
- 12ExplicaçãoA reutilização desloca o kernel para a direita
- 13DesafioQual melhoria eleva o limite atual?
- 14DesafioUm kernel rápido dentro de um programa lento
- 15DicaTorne o ganho apresentado reproduzível
- 16RecapitulaçãoEscolha a próxima medição
3Transforme um laço sobre vetor em trabalho para GPU
22 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoComece com elementos independentes de um vetor
- 2ExemploConte elementos antes de instruções
- 3ExplicaçãoColoque os valores lado a lado
- 4ExplicaçãoSelecione elementos com uma máscara
- 5DesafioTodas as iterações podem começar juntas?
- 6ExplicaçãoDeixe o comprimento ativo descrever a passagem
- 7ExemploDivida um vetor longo em passagens
- 8ConexãoAlimente uma operação vetorial com outra
- 9DesafioAvance pelo que realmente foi executado
- 10ExplicaçãoEscalone um warp enquanto outro espera
- 11ExemploCaminhos diferentes desperdiçam vias ativas
- 12ExplicaçãoFaça uma transação atender muitas threads
- 13DesafioInclua o percurso até o dispositivo
- 14ConexãoEspecialize para uma carga de trabalho mais restrita
- 15ExemploEncontre o elemento do vetor de uma thread
- 16ExemploCubra o último bloco parcial
- 17ExplicaçãoEspere antes de o hospedeiro usar os resultados
- 18ExemploFaça uma redução dentro de um bloco
- 19DesafioUm bloco pode esperar por todos os outros?
- 20Ideia-chaveUma redução altera a ordem aritmética
- 21DesafioCombine um mapeamento seguro com acesso eficiente
- 22RecapitulaçãoVerifique o caminho completo do vetor
4Acompanhe um bloco compartilhado do leitor ao escritor
19 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoVariáveis compartilhadas ainda precisam de coordenação
- 2ExplicaçãoUm espaço de endereçamento, caminhos de acesso diferentes
- 3ExemploConclua o trabalho local antes de combinar
- 4DesafioO que acontece após uma escrita intermediária?
- 5ExemploEncontre o acerto em cache desatualizado
- 6ExplicaçãoConcorde sobre o histórico de uma posição
- 7DesafioA coerência pode preservar ambos os incrementos?
- 8ConexãoMantenha ordenação separada de posse
- 9ExplicaçãoLeia as permissões no MSI
- 10ExemploPrimeiro dê cópias limpas aos dois núcleos
- 11ExemploTransfira a posse para quem escreve
- 12Ideia-chaveO estado exclusivo elimina uma requisição para dados privados
- 13DesafioAcompanhe uma leitura e duas escritas
- 14ExplicaçãoEnvie a requisição pela origem
- 15ExemploConverta bits antes de medir a sobrecarga
- 16ExemploDescubra quais bytes compartilham a posse
- 17DesafioQuem lê a variável vizinha precisa escrever?
- 18DesafioReduza a disputa em uma soma correta
- 19RecapitulaçãoExamine o programa e o bloco
5Acompanhe dados, energia e respostas lentas em um conjunto de servidores
14 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoUm nó agora é um computador completo
- 2ExplicaçãoColoque o trabalho perto de sua entrada
- 3ExemploCombine somas parciais em rodadas de mensagens
- 4ExplicaçãoConte o corte estreito
- 5DesafioPague por uma rede mais larga
- 6ExplicaçãoCompartilhe os enlaces de subida
- 7ExemploInclua refrigeração e distribuição
- 8ExemploTransforme potência constante em energia anual
- 9DesafioQual eficiência a mudança melhorou?
- 10ExemploUma carga baixa ainda consome potência
- 11ExplicaçãoPequenas taxas de falha se somam no conjunto
- 12ExemploUma resposta lenta pode atrasar a requisição
- 13DesafioMais servidores reduzirão o tempo de toda requisição?
- 14RecapitulaçãoEscolha uma métrica para o conjunto com um objetivo
Questões de Processadores paralelos
Conjunto 1: Reconheça o trabalho paralelo e seus custos10 Questões de Prática
Questão 1 de 10
Mostrar respostaOcultar resposta
Questão 2 de 10
Mostrar respostaOcultar resposta
Questão 3 de 10
Mostrar respostaOcultar resposta
Questão 4 de 10
Mostrar respostaOcultar resposta
Questão 5 de 10
Mostrar respostaOcultar resposta
Questão 6 de 10
Mostrar respostaOcultar resposta
Questão 7 de 10
Mostrar respostaOcultar resposta
Questão 8 de 10
Mostrar respostaOcultar resposta
Questão 9 de 10
Mostrar respostaOcultar resposta
Questão 10 de 10
Mostrar respostaOcultar resposta
Conjunto 2: Aplique regras de escalabilidade, indexação e coerência10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 3: Diagnostique limites de desempenho no sistema10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
a[i] = a[i-1] + b[i] da esquerda para a direita. Por que o compilador não pode substituir diretamente iterações consecutivas por vias SIMD independentes?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
vl = 28. O programador avança ambos os ponteiros em 32 elementos e subtrai 32 da quantidade restante. Qual é o primeiro intervalo de dados perdido?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
0x2040; B lê repetidamente um valor de estado independente de 8 bytes em 0x2078. Por que B pode sofrer faltas de coerência?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 4: Combine o comportamento do hardware com modelos de desempenho10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
if (i < n) { load_into_shared(); __syncthreads(); combine(); }. Em seu último bloco, apenas algumas threads satisfazem a condição. Que correção estrutural torna segura a barreira de bloco?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 5: Aplique os modelos a novas decisões de projeto10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
0x3000 e 0x3038 com blocos de cache de 64 bytes. Cada um tem sua própria thread escritora. Que mudança os separa em blocos diferentes?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Travou em uma questão sua? Ajuda com Tarefas
Termos-Chave
A
Aceleração
Aceleração superlinear
Acelerador de domínio específico
Acesso com passo constante
Acesso indexado
Acesso não uniforme à memória (NUMA)
Acesso uniforme à memória (UMA)
Aglomerado de computadores
Á
Árvore de redução
B
Barreira de potência
Barreira de sincronização
Bloco de threads
Busca e soma atômica
C
Coalescência de acessos à memória
Coerência de cache
Compartilhamento verdadeiro
Comprimento do vetor
Computador em escala de centro de dados
Concorrência
Consistência sequencial
D
Dependência entre iterações do laço
Diretório de coerência
Disponibilidade
Distribuição de uma requisição entre servidores
Divergência de desvios
E
Efetividade do uso de energia (PUE)
Eficiência energética
Eficiência paralela
Encadeamento
Equilíbrio de carga
Escalabilidade forte
Escalabilidade fraca
Estado compartilhado (S)
Estado exclusivo (E)
Estado inválido (I)
Estado modificado (M)
Estrutura de vetores
F
Falso compartilhamento
Falta de coerência
Fração sequencial
G
Grade de blocos
Granularidade
H
Hospedeiro
I
Identificador do processo no comunicador
Instrução única e múltiplas threads (SIMT)
Intensidade aritmética
Interface de passagem de mensagens (MPI)
K
Kernel
Kernel limitado pela capacidade de cálculo
Kernel limitado pela largura de banda da memória
L
Lançamento assíncrono
Largura de banda de bisseção
Largura de banda do enlace
Largura do registrador vetorial em bits (VLEN)
Latência de cauda
Lei de Amdahl
Lei de Gustafson
Leitura-modificação-escrita atômica
M
Máscara
Memória compartilhada
Memória global
MIMD
MISD
Modelo de consistência de memória
Modelo Roofline
Monitoração de requisições de coerência
Multiprocessador de memória compartilhada
Multiprocessador de streaming
Multithreading de granularidade fina
Multithreading de granularidade grossa
Multithreading em hardware
Multithreading simultâneo
N
Nó de origem
O
Ocultação de latência
P
Paralelismo
Paralelismo em nível de dados
Paralelismo em nível de instrução
Paralelismo em nível de requisição
Paralelismo em nível de thread
Particionamento do laço em blocos
Ponto de transição do modelo Roofline
Processador lógico
Propagação de escritas
Proporcionalidade energética
Protocolo de invalidação na escrita
S
Serialização de escritas
SIMD
SISD
Sobrecarga do paralelismo
Sobreposição de referências (aliasing)
Sobressubscrição da rede
SPMD
T
Taxonomia de Flynn
Teto de desempenho
Topologia em toro
V
Verificação de limites
Vetor de presença
Vetorização automática
Via SIMD
W
Warp
Sobre esta aula
Crie seus próprios Materiais de Estudo
Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.