Organização de Computadores Antônio Borges / Gabriel P. Silva 6. Pipeline “A quinta parte de um enxame pousou na flor de Kadamba, a terça parte numa flor de Silinda, o triplo da diferença entre estes dois números voa sobre uma flor de Krutaja, e uma abelha adeja sozinha, no ar, atraída pelo perfume de um jasmim e de um pandnus. Dizme, bela menina, qual o número de abelhas” Malba Tahan O Homem que Calculava 6.1. Introdução O pipeline é uma técnica de implementação de processadores que permite a sobreposição temporal das diversas fases de execução das instruções. A execução de uma instrução é dividida em várias etapas ou estágios. Assim, o processador inicia a execução da próxima instrução logo que a execução do primeiro estágio da instrução atual terminar, ao invés de esperar o término da execução de toda a instrução. Embora o tempo gasto para completar cada instrução individualmente não seja reduzido, o uso da técnica de pipeline aumenta o número de instruções executadas simultaneamente e a taxa de instruções iniciadas e terminadas por unidade de tempo. Por exemplo, a fabricação de um carro completo leva, por hipótese, seis horas para ser terminada. Ao final de um dia, em três turnos de 8 horas, uma fábrica com apenas uma linha de produção terá produzido 4 carros. Contudo, podemos dividir o processo de fabricação em várias etapas, como a seguir: – – – – Montagem do Chassi Colocação do Motor Montagem da Carroceria Colocação de Bancos e Acessórios Supondo-se que cada uma dessas etapas leve 90 minutos para ser realizada, um carro continuará levando 6 horas para ser fabricado. Entretanto, podemos iniciar a fabricação de um carro novo a cada 90 minutos, até que tenhamos 4 carros sendo fabricados simultaneamente, um em cada etapa do “pipeline”. Depois das primeiras 6 horas, teremos um carro sendo produzido a cada 90 minutos. Ao final de um dia, em três turnos de 8 horas, uma fábrica com apenas uma linha de produção terá fabricado 16 carros. 6.2. O Pipeline do DLX Em nosso estudo estaremos considerando um modelo de processador baseado no DLX. È uma arquitetura simples, onde todas as instruções possuem tamanho fixo (32 bits); apenas as instruções de LOAD e STORE fazem acesso à memória; existem 32 registradores inteiros (32 bits) de uso geral e um registrador especial, o apontador de instruções (PC), também de 32 bits, que contém o endereço da próxima instrução a ser buscada na memória. Vamos propor a divisão da execução de cada uma das instruções no nosso processador em 5 estágios: − − Busca (B) Decodificação (D) Organização de Computadores − − − Antônio Borges / Gabriel P. Silva Execução (E) Memória (M) Escrita (W) Busca da Instrução Decodificação Execução Memória Escrita do Resultado Figura 9 – Exemplo de pipeline com 5 estágios O estágio de Busca (B) utiliza o endereço armazenado no Apontador de Instruções (PC) para a busca da instrução na memória. Assim que a instrução for carregada nos registradores internos do processador, o valor do PC é atualizado para apontar para a próxima instrução a ser buscada na memória. O estágio de Decodificação (D) realiza a decodificação da instrução, verifica se tem operandos, quantos são e faz a leitura dos valores do banco de registradores. O estágio de Execução (E) é responsável pela execução das operações aritméticas e lógicas definidas pela instrução. Neste estágio também é calculado o endereço de memória dos operandos das instruções de LOAD e STORE e o endereço-alvo para as instruções de desvio. No estágio de Memória (M) é feito o acesso propriamente dito (leitura ou escrita) aos operandos que estão em memória. O endereço utilizado é aquele calculado no estágio de execução. Apenas as instruções de LOAD e STORE realizam alguma tarefa útil neste estágio. O resultado da execução das instruções, se houver, é escrito no banco de registradores no estágio de Escrita (W). Para que esito possa ser feito sem conflito, o banco de registradores permite a leitura e a escrita simultânea de operandos. Se houver a leitura e a escrita simulatêneas de um mesmo registrador, o banco de registradores retorna o novo valor que está sendo escrito. 6.3. Relógio O relógio é um sinal elétrico periódico que cadencia todas as operações no processador. A passagem de uma instrução e seus resultados de um estágio para outro no pipeline do processador também é controlada pelo relógio e se dá normalmente ao final do seu ciclo. Relógio Ciclo Organização de Computadores Antônio Borges / Gabriel P. Silva Figura 10 – Relógio O relógio, por ser periódico, possui uma freqüência e tempo de ciclo bem definidos. Quanto maior a freqüência (f), menor o tempo de ciclo (T) do relógio (T = 1/f). Nos processadores modernos a freqüência é expressa em GHz e o tempo de ciclo de relógio em ns (10-9 s) ou ps (10-12 s). O tempo do ciclo do relógio do processador deve ser igual ao tempo de execução do estágio mais lento do “pipeline”. Ou seja, no projeto de um pipeline, a freqüência do relógio é determinada pelo inverso do tempo de execução do estágio mais lento. O projetista do processador deve dividir a execução da instrução em estágios com o mesmo tempo de execução, para obter o máximo desempenho. Uma outra condição para que este desempenho máximo seja alcançado, é que o pipeline deve ser mantido sempre “cheio”, ou seja, não pode haver estágios sem instruções úteis em execução. 6.4. Caminho de Dados Uma instrução para ser executada no pipeline percorre um caminho de dados que corresponde à divisão em estágios da arquitetura do DLX, conforme a figura abaixo. A execução das instruções obedece a um fluxo da esquerda para a direita. As únicas exceções ocorrem quando é feita a escrita do resultado no banco de registradores, no estágio de escrita, que utiliza o mesmo recurso do estágio de decodificação que é o banco de registradores; e na seleção do próximo valor do PC, que é escolhido entre o PC incrementado de 4 e o endereço do desvio condicional calculado pelo somador no estágio de execução. Figura 11 – Diagrama do Pipeline do DLX Para que possa haver a leitura simultânea de até dois operandos, da instrução que está no estágio de decodificação (D), e a escrita de um resultado, da instrução que está no estágio de escrita (W), possam ser feitas simultaneamente, o banco de registradores deve possuir duas portas de leitura e uma de escrita. Cada porta é constituída por uma saída/entrada de 32 bits de dados e um endereço de 5 bits, que corresponde ao número do registrador que está sendo lido/escrito. Organização de Computadores Antônio Borges / Gabriel P. Silva Para que o controle do pipeline possa ocorrer corretamente, é necessário que cada estágio esteja isolado do outro por meio de registradores que vão armazenar o resultado das operações de cada estágio. A própria instrução deve ser enviada de estágio para estágio, para que em cada um deles as funções apropriadas possam ser executadas. Ao final do pipeline, a instrução é descartada. 6.5. Conflitos no Pipeline Existem situações em que a próxima instrução não pode ser executada no ciclo de relógio seguinte: 6.5.1. Conflitos Estruturais Quando dois ou mais estágios necessitam do mesmo recursos simultaneamente. Por exemplo, pode haver acessos simultâneos à memória sendo feitos tanto pelo estágio de busca de instrução (B) como pelo estágio de acesso à memória (M). Busca de Instrução Decodificação Memória Execução Memória Escrita Resultado Memória Figura 12 – Conflitos Estruturais Soluções possíveis: A solução normalmente empregada é a duplicação de recursos. No caso do acesso simultâneo à memória pelos estágios de Busca e Memória, a solução usual é o uso de caminhos separados para acesso aos dados e instruções, normalmente armazenados em memórias caches separadas para dados e instruções. Memórias caches são elementos da hierarquia de memória que possuem cópias dos dados e instruções mais freqüentemente utilizados pelo processador. 6.5.2. Conflitos de Controle Ocorrem devido às instruções de desvio e de chamada de procedimento. Nesse caso, a próxima instrução a ser executada não estará no endereço de memória subseqüente ao da instrução atual. – Organização de Computadores Antônio Borges / Gabriel P. Silva decisão sobre desvio Tempo desvio condicional Instruções abandonadas próxima instrução Figura 13 – Desvio Condicional Por exemplo, o efeito dos desvios condicionais: se o desvio ocorre, o pipeline precisa ser esvaziado, contudo, não se sabe se desvio ocorrerá ou não até o momento em que a instrução de desvio chegue no estágio de Execução. Soluções possíveis são: − “Desvio Atrasado”: é uma acomodação ao problema, a instrução após o desvio é sempre executada. Nesse caso cabe ao compilador encontrar instruções que possam ser movidas para depois do desvio. Caso isso não seja possível a posição é preenchida com uma instrução de “nop”; − Predição estática de desvios: o compilador presume que o desvio vai ser tomado ou não, levando em conta o endereço alvo do desvio, a instrução de alto nível que gerou o desvio, etc. A taxa de acerto para a predição estática costuma ser na ordem de 80%; − Predição dinâmica de desvios: nesse caso o processador possui circuitos que fazem a predição do resultado do desvio condicional no comportamento daquele desvio no passado. As taxas de acerto obtidas com esse método são bastante altas, chegando até a 97% nos esquemas mais sofisticados Organização de Computadores 6.5.3. Antônio Borges / Gabriel P. Silva Conflito por Dependência de Dados As instruções dependem de resultados de instruções anteriores, que estão no pipeline e ainda não foram completadas. Por exemplo, no trecho de código a seguir a instrução sub precisa do valor de r1 já no estágio de Decodificação, mas a instrução "add" ainda está no estágio de Execução, e o resultado só será escrito no estágio de Escrita: add R1, R2, R3 sub R5, R4, R1 Soluções: – No caso das dependências verdadeiras, o pipeline precisa ser parado durante certo número de ciclos. A instrução que precisa do dado fica parada no estágio de decodificação até que o resultado seja atualizado no banco de registradores. – O uso de adiantamento dos dados, que é um caminho de dados direto entre a saída da ALU e sua entrada, é uma solução usualmente empregada, e resolve o problema quando as instruções dependentes são consecutivas uma à outra no pipeline. Veja a ilustração a seguir: D B M E W Figura 23 - Adiantamento de Dados Adiantamento B D B E D M E W M W Em realidade, há diversos tipos de dependências de dados: Dependências verdadeiras ou diretas: que são as vistas anteriormente e se constituem em um problema para os pipelines convencionais. Dependências falsas: são um problema apenas em pipelines de arquiteturas avançadas, que executam as instruções fora da ordem especificada no código objeto. Podem ser classificadas em: – – antidependência: a instrução seguinte escreve em um registrador que é lido pela instrução anterior. dependência de saída: a instrução seguinte escreve no mesmo registrador que é escrito pela instrução anterior. Organização de Computadores Antônio Borges / Gabriel P. Silva 6.6. Tratamento de Exceções nos Pipelines Uma instrução pode ter problemas durante a sua execução. Por exemplo, uma instrução de multiplicação pode dar “overflow”, ou seja, o resultado pode não caber em 32 bits. Toda vez que uma instrução não consegue terminar normalmente sua execução, diz-se que ocorreu uma exceção. O uso do pipeline dificulta o tratamento das exceções, pois precisamos evitar que as instruções que já estão no pipeline, mas que foram buscadas depois da instrução que causou a exceção, alterem o estado da máquina, ou seja, que escrevam seus resultados no banco de registradores ou na memória. Essas instruções precisam ser anuladas ou descartadas do pipeline, e o apontador de instruções (PC) deve apontar para a instrução correta, aquela que causou a exceção, no início da rotina do que irá fazer o tratamento das exceções. Existe também um problema quando várias exceções ocorrem ao mesmo tempo no pipeline (p.ex. “overflow” e acesso a um endereço de memória inválido). A solução nesse caso é priorizar as exceções, fazendo o atendimento daquela mais prioritária. Em máquinas com despacho de várias instruções por ciclo, garantir sempre um estado da máquina consistente pode ser muito complexo em termos de “hardware”. Nesses casos, pode-se utilizar um modelo de exceções imprecisas, em que a exceção é sempre detectada, mas não se pode garantir que o estado da máquina não foi alterado. 6.7. Máquinas que Despacham Múltiplas Instruções por Ciclo 6.7.1. Superescalares As máquinas superescalares são conhecidas por possuírem mais de um pipeline em paralelo em sua arquitetura. Desse modo, duas ou mais instruções são buscadas, decodificadas, executadas e escrevem seus resultados a cada ciclo de máquina. Claro, isto gera problemas de acesso aos recursos comuns, que precisam ser duplicados em sua maioria. Mas em alguns casos isso é problemático, como por exemplo, a duplicação do barramento de acesso à memória. No caso do banco de registradores, é comum haver várias portas de leitura e de escrita, para permitir a leitura de vários operandos e a escrita de vários resultados a cada ciclo. Um outro fator muito importante nas arquiteturas superescalares é o escalonamento das instruções que vão ser executadas. Devido aos problemas de dependências de dados e controle, algumas instruções não estão prontas para serem executadas. Esquemas mais simples de despacho, simplesmente congelam o pipeline nesse caso. Esquemas mais sofisticados continuam a busca e tentam executar as instruções fora-de-ordem, com mecanismos no ciclo de escrita que permitam a retirada dessas instruções, e atualização do estado da máquina, na mesma ordem estabelecida pelo programa objeto. Exemplos de processadores com arquitetura superescalar são o Pentium IV da Intel, Athlon da AMD e UltraSPARC da Sun. Organização de Computadores 6.7.2. Antônio Borges / Gabriel P. Silva VLIW VLIW é acrônimo para Very Long Instruction Word. São máquinas que exploram o paralelismo no nível das instruções. Várias operações são executadas em paralelo em diferentes unidades funcionais, tais como em máquinas superescalares, a diferença está no controle do despacho e na terminação das operações: nas máquinas superescalares: as dependências são resolvidas em tempo de execução por um hardware dedicado, nas máquinas VLIW as dependências são resolvidas em tempo de compilação pelo compilador. Em uma máquina VLIW, várias operações (instruções em uma máquina normal) são codificadas em uma mesma instrução. A palavra de instrução é bastante longa, podendo conter várias operações (que operam sobre vários operandos) independentes. A posição de cada operação dentro da palavra VLIW determina a unidade funcional que será usada. Deste modo, o hardware de despacho é simples. O escalonamento das operações consiste em determinar as operações que serão executadas em paralelo. Em uma máquina VLIW o compilador é responsável por esta tarefa. Operações que são executadas em paralelo são atribuídas à mesma palavra de instrução. Dentro de um mesmo bloco básico (seqüencial) estas instruções podem ser escalonadas com base no fluxo de dados. Já o escalonamento que ultrapasse as fronteiras entre os blocos básicos exige técnicas mais elaboradas. Exemplos de arquitetura do tipo VLIW são o Itanium da Intel e o Crusoe, da Transmeta.