Parte 7 Pipeline: Conceitos básicos, implementação e ganho de desempenho 1 Melhorando o Desempenho com Pipelining Baseado nas anotações do Livro do Hennessey & Patterson e no material do Prof. José Luís Güntzel [www.ufpel.edu.br/~guntzel/AOC2/AOC2.html] 2 O que é um Pipeline? • • • A técnica de pipelining é usada por todos os processadores atuais para melhorar o desempenho pela superposição da execução de instruções. A analogia mais commum para um pipeline é uma linha de montagem. Supondo 3 fases da linha: 1. Montagem 2. Pintura 3. Polimento Assuma, por exemplo, que cada fase gaste 1 hora para ser concluída 3 O que é um Pipeline? • Se uma pessoa trabalha na linha de produção, ela levará 3 horas para produzir 1 produto. • Se existem 3 pessoas, 1 pessoa poderia se ocupar de cada estágio e cada vez que terminassem sua parte na produção, poderiam passar seus produtos para a próxima pessoa (estágio), sem nenhum tempo de espera. • Desta maneira, seria possível produzir 1 produto por hora assumindo que a linha de montagem está preenchida. 4 O que é um pipeline: Analogia Lavanderia 5 O que é um pipeline: Analogia Lavanderia 6 Pensando em termos de instruções MIPS • • Considere os tempos de resposta de cada um dos componentes da via de dados e os tempos para execução das instruções conforme a tabela abaixo. Podemos estimar que o período de clock será igual a 8ns para uma CPU MIPS na sua versão monociclo. • Pensando na execução de 3 loads (instrução mais lenta) 7 Execução sem e com pipeline 8 Características do Pipelining • Se os estágios do pipeline não estiverem balanceados e um dos estágios for mais lento que os outros, a vazão do pipeline será afetada como um todo. • Idealmente, cada estágio é balanceado (todos os estágios estão prontos para iniciar ao mesmo tempo e levam a mesma quantidade de tempo para serem concluídos). • Assim, o tempo de execução por instrução no pipeline seria definido por: 9 Características do Pipelining • A expressão anterior corresponde ao ganho ideal (máximo). – Existe um overhead para preencher o pipeline e os estágios podem não estar perfeitamente balanceados… • Em termos de uma CPU, a implementação do pipeline tem efeito de reduzir o tempo médio por instrução e, portanto, o valor médio do CPI. – Ex: Se cada instrução num microprocessador leva 5 ciclos de clock (sem pipelined) e se houver um pipeline de 4 estágios, o CPI ideal teórico seria 1.25 10 Voltando ao exemplo dos 3 loads... • Sem pipeline: o tempo decorrido entre o início da primeira instrução e o início da quarta instrução é 3x8 = 24 ns • Com pipeline: o tempo decorrido entre o início da primeira instrução e o início da quarta instrução é 3x2 = 6 ns • Melhora de desempenho com pipeline = 24/6 = 4 vezes! – Mas o ganho máximo teórico não deveria ser 5x, já que esse é o número de estágio do pipeline? – Onde está a diferença no exemplo? • E se agora fossem realizadas 1.000.003 instruções load? Qual o tempo total de execução com e sem pipeline? E o ganho Sem pipeline: 1.000.003x8 = 8.000.024 ns Com pipeline: 8 + 1.000.003x2= 2.000.014 ns Ganho 4.0 11 RISC Instruction Set (Hennessey & Patterson) • Propriedades da arquitetura MIPS: – Todos os operandos estão em registradores (32-bits). – Acesso à Memória somente por operações load /store – Instruções de tamanho único (32 bits) – Poucos formatos de instruções, sempre com o registrador-fonte localizado na mesma posição – Operandos do MIPS alinhados na memória • Conjunto de instruções pensado para o pipeline!!! • Instruções aritméticas (ULA), acesso a memória e mudança de fluxo de controle (desvios) 12 Tipos de Instruções MIPS • ULA (ou tipo R) – Aritméticas com 2 registradores ou 1 registrador e um imediato como operandos. Resultado escrito num registrador destino • Load/store – Um registrador (base) e um operando 16-bits como valor imediato. A soma deles define o endereço efetivo para o acesso à memória. – Um segundo registrador: destino para a operação de load e dado a ser armazenado na operação de stored. • Branches e Jumps – Mudanças de fluxo de controle. Um branch resulta na soma de um valor imediato ao valor atual do PC. 13 5 passos para execução de instruções MIPS • Assume-se que qualquer instrução MIPS pode ser executada em no máximo 5 ciclos de clock: 1. Busca da instrução na memória (BI/IF) 2. Leitura dos registradores, enquanto a instrução é decodificada (ID/DI) 3. Execução de uma operação ou cálculo de um endereço (EX) 4. Acesso a um operando na memória (MEM) 5. Escrita do resultado em um registrador (EM/WB) 14 Pensando em ciclos de clock • Resumo dos ciclos para executar instruções numa CPU não pipeline: • Branch - 2 clocks • Store - 4 clocks • Outras - 5 clocks • EX: Assumindo que as instruções de desvio correspondem a 12% de todas as instruções e que stores a 10%, qual o CPI médio da CPU? CPImédio = 0.12*2+0.10*4+0.78*5 = 4.54 15 Pipeline RISC de 5 estágios • Implementação clássica do conceito de pipeline proposta por Hennessy e Patterson para o DLX (MIPS) • Para o caso ideal, o pipeline deveria começar uma nova instrução a cada novo ciclo de clock. • Infelizmente isso nem sempre é possível: – Um ADD não gasta o mesmo tempo de ULA que um MULT – Dependências de dados entre instruções – … • Mas cada estágio pode ser tratado de forma independente e assim as fases de execução podem ser “superpostas” 16 Representação Gráfica do Pipeline de Instrução 17 Lembram-se dos possíveis caminhos para os dados na via de dados da CPU? 18 Alguns Problemas à vista… 1. A memória é acessada 2x durante cada ciclo de clock. – Separar memória de dados e de instruções – Importante: o período do clock é o mesmo para a CPU com pipeline e sem pipeline… Com isso, a memória deve trabalhar 5x mais rápido. 2. Registradores acessados 2x por ciclo – Para tentar evitar o conflito por recurso, realizar a escrita na 1a metade do ciclo e a leitura na 2a metade do ciclo de clock. – Escreve-se primeiro porque o resultado de uma escrita (dado) pode ser usado por outra instrução com execução mais adiantada no pipeline 19 Alguns Problemas à vista… 3. Interação entre o PC e o pipeline ao fim da fase IF/BI. Se a decodificação identifica uma instrução de desvio que modifica o PC, como isso afeta o pipeline? – O uso de registradores específicos para o pipeline fornecem à CPU uma memória temporária que permite armazenar estados intermediários da execução das instruções no pipeline. 20 Conflitos de Pipeline (Pipeline “Hazards”) • O ganho de desempenho porque é possível se iniciar a execução de uma nova instrução a cada ciclo de clock. Porém, em um cenário realista, isso nem sempre é possível… • Os chamados conflitos de pipeline (“pipeline hazards”) atrasam a execução da próxima instrução por alguns ciclos de clock, até que haja tempo para que sejam solucionados... – Usaremos hazard = conflito (hazard: azar, risco, acaso, …) • Três tipos: – Estruturais – De controle – De dados 21 1. Conflitos Estruturais (Structural Hazards) • O hardware (do datapath) não tem recursos suficientes para atender às solicitações da execução sobreposta das instruções no pipeline em um dado ciclo de clock • O conjunto de instruções do MIPS foi projetado para executar em pipeline (é muito fácil evitar esses conflitos no design) • Uma possível solução é a parada do pipeline (“bolha”), isto é interromper a progressão das instruções pelo pipeline. 22 1. Conflitos Estruturais (Structural Hazards) • Se na CPU multiciclo vista anteriormente fosse mantida apenas uma memória única para dados e instruções, ocorreria um conflito estrutural quando uma instrução estiver sendo buscada ao mesmo tempo que um dado é escrito na memória (estágios BI e MEM) • Outro problema aconteceria se considerarmos que o banco de registradores só puder ser ou escrito ou lido num mesmo ciclo (estágios DI e ER) 23 Conflito estrutural (Acesso duplo à memória) Conflito estrutural (Leitura e escrita dos registradores) 24 2. Conflitos de Controle (Control Hazards) • Interação PC – pipeline: conflitos se originam da necessidade de se tomar uma decisão para o valor de PC baseada nos resultados de uma instrução, a qual ainda não foi concluída. • Muito comuns em instruções de salto condicional (beq, no caso do MIPs reduzido) 25 Parada do pipeline num conflito de controle • Assumir que um hardware extra foi adicionado para permitir testar registradores, calcular o endereço de desvio condicional e atualizar o PC, tudo isso no segundo estágio (decodificação). Isso é uma solução comum para minimizar o efeito desse tipo de conflito. 26 Parada do pipeline num conflito de controle • Se for necessário resolver o desvio condicional em um estágio posterior ao segundo (o que é o ocorre na maioria das CPUs reais), ocorrerá uma perda maior de desempenho em função da necessidade de encher novamente o pipeline 27 Outra solução para conflito de controle • Predição estática: esquema muito usado em CPUs reais • Simples: assumir que os desvios condicionais sempre irão falhar (teste gera FALSO) • Se acertar, o pipeline prossegue com velocidade máxima • Se errar, será necessário atrasar o pipeline • Mais sofisticado: assumir que parte dos desvios ocorrem e outros não ocorrem • Desvios para endereços anteriores supostamente falham (instruções tipo if-then-else) • Desvios para endereços posteriores supostamente são feitos (última instrução de um loop) 28 Pipeline com predição de desvio 29 Mais uma solução para conflito de controle • Predição dinâmica: realizada em função do comportamento anterior (histórico) de cada desvio • Podem mudar a predição para um mesmo ponto de desvio com o decorrer da execução do programa • Um esquema comum é manter uma história para cada desvio realizado ou não-realizado • Preditores dinâmicos são implementados em hardware e apresentam até 90% de acerto Qualquer que seja o esquema de predição, quando o palpite (previsão) estiver errado(a), o controle do pipeline precisa assegurar que as instruções seguintes ao desvio não terão influência na execução das instruções futuras. 30 Mais uma solução para conflito de controle • O esquema de retardar a decisão (delayed branch) consiste em encaixar uma instrução “útil” para ser executada logo após a instrução de desvio, de modo a manter o pipeline preenchido, evitando a parada • Isto é um trabalho para o Compilador! – Lembrem-se que o compilador tem papel fundamental para o desempenho de máquinas RISC 31 Solução para conflito de controle: delayed branch 32 Soluções similares ao delayed branch 33 3. Conflitos de Dados (Data Hazards) • Ocorre quando uma instrução depende de dados resultantes da execução de outra que ainda está no pipeline 34 Uma solução para conflito de dados • Passar para o compilador a solução deste tipo de conflito é inviável, pois ele é muito frequente • Adiantamento (forwarding ou bypass): tão logo a ULA calcule o resultado da operação, ele pode ser disponibilizado como operando para as instruções que vem logo a seguir. – Necessidade de um hardware de roteamento para detectar a dependência entre dados de instruções subsequentes. • Supondo a sequência de execução anterior: 35 Solução do conflito por adiantamento • Solução: conexão entre a saída da ULA e a entrada da própria ULA Não haverá mais bolha no pipeline! 36 Outro exemplo de adiantamento • O adiantamento para uma instrução lw seguida de uma instrução que usa o valor que acaba de ser buscado na memória: Sempre haverá uma bolha no pipeline nesses casos! Inevitável! 37 Solução por reordenação de código • • O compilador reordena as instruções de forma a evitar os possíveis conflitos de dados. Ex: o código do procedimento swap abaixo exibe um conflito. lw lw sw sw $t0, $t2, $t2, $t0, 0($t1) 4($t1) 0($t1) 4($t1) # # # # # reg $t1 possui o endereco de v[k] reg $t0 (temp) = v[k] reg $t2 = v[k+1] v[k] = reg $t2 v[k+1] = reg $t0 (temp) 38 Solução por reordenação de código • Solução: trocar a 2ª e a 3ª linhas de posição: Código sem conflito lw lw sw sw $t0, $t2, $t0, $t2, 0($t1) 4($t1) 4($t1) 0($t1) # # # # # reg $t1 possui o endereco de v[k] reg $t0 (temp) = v[k] reg $t2 = v[k+1] v[k+1] = reg $t0 (temp) v[k] = reg $t2 39 Conflitos provocam a parada do pipeline • Com os conflitos, algumas expressões envolvendo ganhos mais realistas de pipeline em termos de CPI poderiam ser calculados da seguinte forma: Speedup = CPI unpipelined / CPI pipelined = No estágios / (1 + paradas por instrução) = Tmédio por Inst unpipelined / Tmédio por Inst pipelined OBS: Assume-se que o período de clock é o mesmo para as implementação com ou sem pipeline. 40 Conflitos provocam a parada do pipeline • Pode-se pensar no desempenho em termos de um ciclo de clock mais rápido para a CPU pipelined da seguinte forma: Speedup = Tempo Ciclo Clock unpipelined CPI unpipelined x Tempo Ciclo_Clock_pipelined CPI pipelined Tempo Ciclo_Clock_pipelined = Tempo Ciclo Clock unpipelined No estágios 1 Speedup = x No estágios 1 + Paradas do pipeline por Instrução 41 Speedup x conflitos • A solução básica para conflitos é a inserção de uma parada ou bolha no pipeline. O efeito é o retardamento da execução da próxima instrução de 1 ciclo a cada bolha inserida. – Obviamente, isso aumenta o CPI, piorando o desempenho! • Ex: Considere a comparação entre 2 CPUs. Uma delas tem conflito estrutural que ocorre 40% do tempo, causando uma bolha, mas com isso, trabalha com uma taxa de clock 1.05x mais alta que a CPU sem conflito. Quanto a CPU com conflito é mais rápida do que a sem conflito? 42 Speedup x conflitos CPI sem_conflito Speedup = T ciclo_clock sem_conflito x T ciclo_clock com_conflito CPI com_conflito 1 1 x Speedup = 1+0.4*1 1/1.05 Speedup = 0.75 Note que: (1) Apesar da taxa de clock do processador com conflito ser um pouco maior, o speedup é um pouco menor que 1 (perde desempenho, mas não muito…) e (2) Não cuidar do conflito poderia ser uma solução adotada por conta de custos envolvendo as alterações na via de dados, aliada à baixa probabilidade de ocorrência deste conflito 43 Pipeline não resolve sozinho o desempenho • • Precisaremos de buffers entre estágios do pipeline – Armazenar os estados intermediários da execução de cada um das instruções que está momentaneamente no pipeline – Detecção de dependências Além dos conflitos, ainda existem outros problemas a serem resolvidos... – Instruções com tempos diferentes por estágio (Adição x multiplicação, ponto flutuante x inteiros) – Múltiplos pipelines em arquiteturas superescalares – Paralelismo em nível de instrução x compiladores paralelos – Predição de desvio por hardware 44 Operações com múltiplos clocks • Algumas aplicações não serão completadas em apenas 1 clock. Exemplos: • Multiplicação Floating Point • Divisão Floating Point • Soma Floating Point • • Pode se supor que existe um hardware específico para executar esse tipo de instrução. Em geral, Multiplicação e soma FP são totalmente pipelined, mas a divisão é não pipelined. 45 Múltiplos estágios de execução na via de dados 46 Estágios de execução (EX) pipelined 47 Previsão de desvio via hardware 48