Pipeline Até agora, nos prendemos muito em economizar espaço na memória e baratear o custo de uma máquina Mas, e quando quisermos uma máquina mais veloz, isto é, com melhor  desempenho ?
Até aqui, sempre assumimos que o tempo de um ciclo era fixo e pré-definido. E por causa disso, o número de microinstruções a serem executadas definia o tempo gasto na execução do programa Esquecendo um pouco a memória, vamos focar agora em como reduzir o tempo gasto na execu- ção das microinstruções A seguir, veremos o uso do pipeline
Até aqui, seguindo o modelo de Von Neumann, vimos que as etapas de execução de uma instrução seguem uma ordem:  busca da instrução ,  identificação ,  busca dos operandos ,  execução da operação  e  armazenamento do resultado Podemos representar desta forma, onde cada quadrado representa um subciclo: B I BO E AR
Vimos também que, por este modelo, uma nova microinstrução só pode ser executada após o término da anterior, mesmo que não haja interdependência entre elas Esquematizando, teríamos: Como otimizar este processo? 1 2 tempo 3 B I BO E AR B I BO E AR B ...
Curiosidades Henry Ford (1863 – 1947) nasceu nos EUA, fundou a Ford – fábrica de auto- móveis – e defendia for- temente o consumismo Mas nada disso nos interessa
Curiosidades Ford utilizava a chamada “linha  de montagem”, que consistia em especializar seus empregados em funções definidas O mesmo empregado passava todo o tempo realizando uma única tarefa, mais específica possível e repetidas vezes, de forma que a prática o levasse a diminuir a chance de erros e o fizesse gastar menos tempo para concluir a tarefa
Aplicaremos o “fordismo” aos nossos estudos: as componentes deverão estar exercendo suas funções sempre que possível, em vez de ter que esperar o que chamávamos de um ciclo para voltar a trabalhar O ganho no desempenho é bastante significativo 1 2 tempo 3 B I BO E AR B I BO E AR B ... B I BO E AR
Aplicaremos o “fordismo” aos nossos estudos: as componentes deverão estar exercendo suas funções sempre que possível, em vez de ter que esperar o que chamávamos de um ciclo para voltar a trabalhar O ganho no desempenho é bastante significativo 1 2 tempo 3 B I BO E AR B I BO E AR B I BO E AR
Dessa forma, assim que a busca de uma instrução for concluída, pode ser iniciada a busca da próxima, já que as componentes especializadas nesta tarefa (no caso, PC, IR e MAR) já estarão livres. E o mesmo serve para identificação, busca de operandos etc Podemos chamar cada um dos quadrados de um  estágio  do pipeline Antes, o tempo total era dado pelo tempo de uma instrução multiplicado pelo total de instruções: t = n.t inst
No pipeline, o tempo de uma instrução é dado pelo número de estágios multiplicado pelo tempo de um estágio: t inst  = n e .t e E, se analisarmos o esquema de execução das instruções no pipeline feito há pouco, teremos o tempo total de execução no pipeline: t pipe  = t inst  + (n – 1).t e = (n e  + n – 1).t e Com isso, podemos conhecer o  speedup , ou seja, o quanto mais rápido é a execução por pipeline em relação à arquitetura anterior
O cálculo se dá dividindo o tempo total  t  do modelo de Von Neumann pelo tempo gasto no pipeline, o que nos dá: O número de estágios vai ser sempre muito inferior ao número de instruções, portanto podemos ignorar os valores  n e  e  -1  no denominador. No numerador, isso não é possível por ser uma multiplicação, e não uma soma Passamos a ter então:
Com o resultado, inferimos que a execução de um programa é, idealmente, n e  vezes mais rápida no pipeline É fácil visualizar isso: Note que na área entre os pontilhados, 4 tarefas estão sendo executadas ao mesmo tempo, enquanto apenas uma estaria sendo no modelo antigo. Isto porque são 4 estágios
Lembre-se de que, em uma aplicação real, o esquema anterior teria centenas de microinstruções. Isto é, a área entre as linhas pontilhadas sempre vai ser a imensa maioria Mas, como sempre, existem problemas E é deles que vamos falar a partir de agora
Dependência de dados Quando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h Vamos acompanhar a sucessão dos ciclos para entender o que acontece I BO B E GR I BO B E GR I BO
Dependência de dados Quando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h B No primeiro ciclo, a instrução é buscada. Ou seja, ao seu final, a máquina apenas tem a instrução sem nem sequer saber o que significa, pois ainda não foi identificada I BO B E GR I BO B E GR I BO
Dependência de dados Quando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h I BO B Aqui, a máquina identifica a instrução “a = b + c” e já busca o valor dos operandos  b  e  c . Neste mesmo ciclo, já é buscada a instrução “d = a + h” I BO B E GR I BO B E GR I BO
Dependência de dados Quando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h I BO E I BO Agora, aparece o problema. Neste ciclo, buscamos os operandos  a  e  h  da instrução 2, sendo que  a  é o resultado da instrução 1. E este resultado ainda não foi gravado, já que isto só terá sido feito ao final do ciclo seguinte B E GR I BO B E GR I BO
Dependência de dados Quando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h Portanto, faz-se necessário esperar até que o valor de  a  esteja corretamente gravado em algum registrador B - - B E GR I BO E GR I BO
Note que, sem esse problema, levaríamos 5 ciclos para executar as 2 instruções. Com o impasse, levamos 2 ciclos a mais Se a dependência de dados ocorresse seguidamente em 500 instruções, levaríamos 2 ciclos a mais para cada dependência De pouco mais de 500 ciclos, a sequência passaria a levar cerca de 1500 ciclos para ser executada Há ainda outro problema, muito mais comum do que a dependência de dados
Dependência de controle Sabemos que o endereço da instrução a ser buscada na memória se encontra no registrador PC Sabemos também que, se não há desvios, a próxima instrução a ser buscada está no endereço dado por  pc  (conteúdo de PC) + 1 No pipeline, busca-se uma instrução em um estágio, e já no próximo busca-se a instrução seguinte, no endereço  pc  + 1
MUX AMU X C O N D N1 N0 LMS N Z Controle Controle Convém uma pequena revisão. Lembra-se deste esquema? É sobre como são feitos os desvios de instruções U L A .  .  .  .  . A D D R Memória de Controle MPC INC ULA
Na verdade, não é necessário relembrar o que acontece em cada parte no desenho Tudo o que precisamos ter em mente é que os desvios condicionais são realizados após alguma operação na ULA, a qual libera os sinais N e Z que contêm informações sobre a saída da ULA. Esta saída é, então, avaliada de acordo com a condição do desvio Dito isso, conclui-se então que só no terceiro estágio saberemos se ocorrerá desvio B E GR I BO
Isso significa que teremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então  goto  8 I BO B E GR I BO B E GR I BO
Isso significa que teremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então  goto  8 B I BO Neste ciclo, estaremos buscando a nossa instrução. PC contém seu endereço, então o conteúdo de PC é 1 B E GR I BO B E GR I BO
Isso significa que teremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então  goto  8 I BO B I BO Agora, identificamos nossa instrução e buscamos o operando  a . Vamos supor que este seja igual a 0. Neste mesmo ciclo, buscamos a próxima instrução, por  default , no endereço  pc  + 1. Está sendo buscada, então, a instrução no endereço 2 B E GR I BO B E GR I BO
Isso significa que teremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então  goto  8 I E I BO Porém, chegamos agora ao ciclo onde a primeira instrução é executada. A ULA dará como saída o próprio operando  a , que será avaliado na lógica de microssequenciamento e, como é igual a 0, a execução do programa teria de ser desviada para a instrução no endereço 8 ( goto  8) B E GR I BO B E GR I BO
Isso significa que teremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então  goto  8 E agora? Constatamos anteriormente que a instrução no endereço 2 já foi buscada, e a máquina a essa altura já identificou e buscou os operandos dessa instrução que não nos interessa - - B E GR I BO B E GR I BO
Isso significa que teremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então  goto  8 Mais uma vez, é necessário esperar alguns ciclos até que tenhamos a confirmação de que haverá desvio, para só depois buscar a próxima instrução - - B E GR I BO B E GR I BO
Nós, como projetistas da máquina, precisamos sempre buscar formas de passar por todos os obstáculos existentes em uma implementação A saída geralmente é pensar em  otimizações  que diminuam o prejuízo causado por possíveis problemas de uma implementação
A primeira otimização, que qualquer bom compilador deve ser capaz de fazer, é uma arrumação na sequência de instruções a fim de diminuir ao máximo o número de ocorrências de dependência de dados em um programa Vimos que a sequência a = b + c d = a + h causaria um desperdício de 2 ciclos na máquina Entretanto, o compilador pode “procurar” outras instruções que nada tenham a ver com estas e executá-las neste espaço
Por exemplo, se houver no programa outras duas instruções de soma, a ordem de execução pode ser: a = b + c x = y + z m = n + p d = a + h Desta forma, não haverá perda de tempo a  = b + c x = y + z m = n + p d =  a  + h O processador acaba de gravar o resultado em algum registrador Inicia-se a busca dos operandos. Quando o registrador onde está  a  for consultado, lá já estará o valor correto de  a B E GR I BO B E GR I BO B E GR I BO B E GR I BO
Outra otimização possível é conhecida como  Data Forwarding Consiste em buscar os operandos sem esperar que o resultado da instrução anterior seja gravado em um registrador, mesmo que um desses operandos seja esse resultado Registradores ULA
Na sequência: a = b + c d = a + h sabemos que a segunda instrução também pode ser escrita como “d = b + c + h” Desta forma, não precisamos esperar até que o registrador da variável  a  seja atualizado para buscar os operandos da segunda instrução Em outras palavras, não é necessário esperar chegarmos ao final do estágio onde o resultado é gravado (GR) para conhecermos um dos operandos da segunda instrução
B Antes, precisávamos do valor gravado em um registrador - - B E GR I BO E GR I BO
B Agora, podemos reaproveitar este valor logo após o término da execução da operação na ULA Esta seria uma opção bastante útil para um caso do tipo: a = b + c d = a + e f = d + g h = f + i j = h + k x = j + h - - B E GR I BO E GR I BO
Processadores como o da Intel possuem uma série de outras otimizações na implementação do pipeline Prejuízos causados por dependência de controle são diminuídos com maneiras de “prever” se a instrução atual causará desvio na execução da sequência de instruções, com probabilidades altas de acerto Outra otimização possível é armazenar certas informações quando houver desvios na instrução, para serem usadas quando esta instrução aparecer novamente. Por exemplo, em um loop onde são feitas 10 iterações, ocorrem 9 desvios para a mesma instrução (a primeira)
Acompanhe: i <- 1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop i = 1
Acompanhe: i <- 1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop A condição é analisada e não ocorre desvio: entramos no loop
Acompanhe: i <- 1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop Hora de analisar novamente se i é menor ou igual a 10
Acompanhe: i <- 1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop Neste momento, i = 2, então para iniciar a segunda iteração...
Acompanhe: i <- 1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop ...desviamos de volta para a primeira instrução no loop
Há ainda uma última forma de otimização que melhora o desempenho da nossa máquina, conhecida como  superpipelining Vimos que a implementação do pipeline agiliza, idealmente, n e  vezes a execução das instruções em relação à nossa máquina antiga Ora, por que então usar apenas 4 estágios? Um dos processadores da Intel possui pipeline de 20 estágios. Apenas para dar uma ideia, os primeiros 4 estágios são usados para operações de busca de instruções B1 B2 B3 B4 .  .  .  .  .  .
Esta configuração caracteriza exatamente um superpipeline Ok, 20 estágios já está melhor que 4. Mas por que não usar, talvez, 1000 estágios? Para executar várias operações do mesmo tipo ao mesmo tempo, precisaríamos aumentar o número de componentes. No caso de 4 operações de busca, por exemplo, o processador precisa ter 4 PCs para armazenar o endereço dessas instruções, 4 IRs para armazenar as instruções propriamente ditas, etc Aumentar o número de componentes encarece a máquina, o que tornaria um desastre elevar demais o número de estágios do pipeline
Muito bem, falamos bastante sobre como amenizar os revés do pipeline, mas não podemos esquecer que estes não são os únicos que afetam o desempenho da máquina Até agora, economizamos alguns ciclos aqui, outros lá, já executamos várias instruções ao mesmo tempo e por aí vai Mas não nos aprofundamos ainda em um outro problema que aumenta consideravelmente o tempo gasto pela máquina na execução de problemas: leitura e escrita na memória principal Estas operações levam aproximadamente 100 ciclos para serem realizadas!

Pipeline

  • 1.
    Pipeline Até agora,nos prendemos muito em economizar espaço na memória e baratear o custo de uma máquina Mas, e quando quisermos uma máquina mais veloz, isto é, com melhor desempenho ?
  • 2.
    Até aqui, sempreassumimos que o tempo de um ciclo era fixo e pré-definido. E por causa disso, o número de microinstruções a serem executadas definia o tempo gasto na execução do programa Esquecendo um pouco a memória, vamos focar agora em como reduzir o tempo gasto na execu- ção das microinstruções A seguir, veremos o uso do pipeline
  • 3.
    Até aqui, seguindoo modelo de Von Neumann, vimos que as etapas de execução de uma instrução seguem uma ordem: busca da instrução , identificação , busca dos operandos , execução da operação e armazenamento do resultado Podemos representar desta forma, onde cada quadrado representa um subciclo: B I BO E AR
  • 4.
    Vimos também que,por este modelo, uma nova microinstrução só pode ser executada após o término da anterior, mesmo que não haja interdependência entre elas Esquematizando, teríamos: Como otimizar este processo? 1 2 tempo 3 B I BO E AR B I BO E AR B ...
  • 5.
    Curiosidades Henry Ford(1863 – 1947) nasceu nos EUA, fundou a Ford – fábrica de auto- móveis – e defendia for- temente o consumismo Mas nada disso nos interessa
  • 6.
    Curiosidades Ford utilizavaa chamada “linha de montagem”, que consistia em especializar seus empregados em funções definidas O mesmo empregado passava todo o tempo realizando uma única tarefa, mais específica possível e repetidas vezes, de forma que a prática o levasse a diminuir a chance de erros e o fizesse gastar menos tempo para concluir a tarefa
  • 7.
    Aplicaremos o “fordismo”aos nossos estudos: as componentes deverão estar exercendo suas funções sempre que possível, em vez de ter que esperar o que chamávamos de um ciclo para voltar a trabalhar O ganho no desempenho é bastante significativo 1 2 tempo 3 B I BO E AR B I BO E AR B ... B I BO E AR
  • 8.
    Aplicaremos o “fordismo”aos nossos estudos: as componentes deverão estar exercendo suas funções sempre que possível, em vez de ter que esperar o que chamávamos de um ciclo para voltar a trabalhar O ganho no desempenho é bastante significativo 1 2 tempo 3 B I BO E AR B I BO E AR B I BO E AR
  • 9.
    Dessa forma, assimque a busca de uma instrução for concluída, pode ser iniciada a busca da próxima, já que as componentes especializadas nesta tarefa (no caso, PC, IR e MAR) já estarão livres. E o mesmo serve para identificação, busca de operandos etc Podemos chamar cada um dos quadrados de um estágio do pipeline Antes, o tempo total era dado pelo tempo de uma instrução multiplicado pelo total de instruções: t = n.t inst
  • 10.
    No pipeline, otempo de uma instrução é dado pelo número de estágios multiplicado pelo tempo de um estágio: t inst = n e .t e E, se analisarmos o esquema de execução das instruções no pipeline feito há pouco, teremos o tempo total de execução no pipeline: t pipe = t inst + (n – 1).t e = (n e + n – 1).t e Com isso, podemos conhecer o speedup , ou seja, o quanto mais rápido é a execução por pipeline em relação à arquitetura anterior
  • 11.
    O cálculo sedá dividindo o tempo total t do modelo de Von Neumann pelo tempo gasto no pipeline, o que nos dá: O número de estágios vai ser sempre muito inferior ao número de instruções, portanto podemos ignorar os valores n e e -1 no denominador. No numerador, isso não é possível por ser uma multiplicação, e não uma soma Passamos a ter então:
  • 12.
    Com o resultado,inferimos que a execução de um programa é, idealmente, n e vezes mais rápida no pipeline É fácil visualizar isso: Note que na área entre os pontilhados, 4 tarefas estão sendo executadas ao mesmo tempo, enquanto apenas uma estaria sendo no modelo antigo. Isto porque são 4 estágios
  • 13.
    Lembre-se de que,em uma aplicação real, o esquema anterior teria centenas de microinstruções. Isto é, a área entre as linhas pontilhadas sempre vai ser a imensa maioria Mas, como sempre, existem problemas E é deles que vamos falar a partir de agora
  • 14.
    Dependência de dadosQuando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h Vamos acompanhar a sucessão dos ciclos para entender o que acontece I BO B E GR I BO B E GR I BO
  • 15.
    Dependência de dadosQuando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h B No primeiro ciclo, a instrução é buscada. Ou seja, ao seu final, a máquina apenas tem a instrução sem nem sequer saber o que significa, pois ainda não foi identificada I BO B E GR I BO B E GR I BO
  • 16.
    Dependência de dadosQuando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h I BO B Aqui, a máquina identifica a instrução “a = b + c” e já busca o valor dos operandos b e c . Neste mesmo ciclo, já é buscada a instrução “d = a + h” I BO B E GR I BO B E GR I BO
  • 17.
    Dependência de dadosQuando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h I BO E I BO Agora, aparece o problema. Neste ciclo, buscamos os operandos a e h da instrução 2, sendo que a é o resultado da instrução 1. E este resultado ainda não foi gravado, já que isto só terá sido feito ao final do ciclo seguinte B E GR I BO B E GR I BO
  • 18.
    Dependência de dadosQuando há dependência de dados entre instruções, algumas componentes precisam se manter ociosas durante alguns ciclos Isto caracteriza desperdício de tempo a = b + c d = a + h Portanto, faz-se necessário esperar até que o valor de a esteja corretamente gravado em algum registrador B - - B E GR I BO E GR I BO
  • 19.
    Note que, semesse problema, levaríamos 5 ciclos para executar as 2 instruções. Com o impasse, levamos 2 ciclos a mais Se a dependência de dados ocorresse seguidamente em 500 instruções, levaríamos 2 ciclos a mais para cada dependência De pouco mais de 500 ciclos, a sequência passaria a levar cerca de 1500 ciclos para ser executada Há ainda outro problema, muito mais comum do que a dependência de dados
  • 20.
    Dependência de controleSabemos que o endereço da instrução a ser buscada na memória se encontra no registrador PC Sabemos também que, se não há desvios, a próxima instrução a ser buscada está no endereço dado por pc (conteúdo de PC) + 1 No pipeline, busca-se uma instrução em um estágio, e já no próximo busca-se a instrução seguinte, no endereço pc + 1
  • 21.
    MUX AMU XC O N D N1 N0 LMS N Z Controle Controle Convém uma pequena revisão. Lembra-se deste esquema? É sobre como são feitos os desvios de instruções U L A . . . . . A D D R Memória de Controle MPC INC ULA
  • 22.
    Na verdade, nãoé necessário relembrar o que acontece em cada parte no desenho Tudo o que precisamos ter em mente é que os desvios condicionais são realizados após alguma operação na ULA, a qual libera os sinais N e Z que contêm informações sobre a saída da ULA. Esta saída é, então, avaliada de acordo com a condição do desvio Dito isso, conclui-se então que só no terceiro estágio saberemos se ocorrerá desvio B E GR I BO
  • 23.
    Isso significa queteremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então goto 8 I BO B E GR I BO B E GR I BO
  • 24.
    Isso significa queteremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então goto 8 B I BO Neste ciclo, estaremos buscando a nossa instrução. PC contém seu endereço, então o conteúdo de PC é 1 B E GR I BO B E GR I BO
  • 25.
    Isso significa queteremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então goto 8 I BO B I BO Agora, identificamos nossa instrução e buscamos o operando a . Vamos supor que este seja igual a 0. Neste mesmo ciclo, buscamos a próxima instrução, por default , no endereço pc + 1. Está sendo buscada, então, a instrução no endereço 2 B E GR I BO B E GR I BO
  • 26.
    Isso significa queteremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então goto 8 I E I BO Porém, chegamos agora ao ciclo onde a primeira instrução é executada. A ULA dará como saída o próprio operando a , que será avaliado na lógica de microssequenciamento e, como é igual a 0, a execução do programa teria de ser desviada para a instrução no endereço 8 ( goto 8) B E GR I BO B E GR I BO
  • 27.
    Isso significa queteremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então goto 8 E agora? Constatamos anteriormente que a instrução no endereço 2 já foi buscada, e a máquina a essa altura já identificou e buscou os operandos dessa instrução que não nos interessa - - B E GR I BO B E GR I BO
  • 28.
    Isso significa queteremos problemas no pipeline se tivermos uma instrução parecida com: Suponha que a instrução acima esteja no endereço 1 da memória principal se a = 0 então goto 8 Mais uma vez, é necessário esperar alguns ciclos até que tenhamos a confirmação de que haverá desvio, para só depois buscar a próxima instrução - - B E GR I BO B E GR I BO
  • 29.
    Nós, como projetistasda máquina, precisamos sempre buscar formas de passar por todos os obstáculos existentes em uma implementação A saída geralmente é pensar em otimizações que diminuam o prejuízo causado por possíveis problemas de uma implementação
  • 30.
    A primeira otimização,que qualquer bom compilador deve ser capaz de fazer, é uma arrumação na sequência de instruções a fim de diminuir ao máximo o número de ocorrências de dependência de dados em um programa Vimos que a sequência a = b + c d = a + h causaria um desperdício de 2 ciclos na máquina Entretanto, o compilador pode “procurar” outras instruções que nada tenham a ver com estas e executá-las neste espaço
  • 31.
    Por exemplo, sehouver no programa outras duas instruções de soma, a ordem de execução pode ser: a = b + c x = y + z m = n + p d = a + h Desta forma, não haverá perda de tempo a = b + c x = y + z m = n + p d = a + h O processador acaba de gravar o resultado em algum registrador Inicia-se a busca dos operandos. Quando o registrador onde está a for consultado, lá já estará o valor correto de a B E GR I BO B E GR I BO B E GR I BO B E GR I BO
  • 32.
    Outra otimização possívelé conhecida como Data Forwarding Consiste em buscar os operandos sem esperar que o resultado da instrução anterior seja gravado em um registrador, mesmo que um desses operandos seja esse resultado Registradores ULA
  • 33.
    Na sequência: a= b + c d = a + h sabemos que a segunda instrução também pode ser escrita como “d = b + c + h” Desta forma, não precisamos esperar até que o registrador da variável a seja atualizado para buscar os operandos da segunda instrução Em outras palavras, não é necessário esperar chegarmos ao final do estágio onde o resultado é gravado (GR) para conhecermos um dos operandos da segunda instrução
  • 34.
    B Antes, precisávamosdo valor gravado em um registrador - - B E GR I BO E GR I BO
  • 35.
    B Agora, podemosreaproveitar este valor logo após o término da execução da operação na ULA Esta seria uma opção bastante útil para um caso do tipo: a = b + c d = a + e f = d + g h = f + i j = h + k x = j + h - - B E GR I BO E GR I BO
  • 36.
    Processadores como oda Intel possuem uma série de outras otimizações na implementação do pipeline Prejuízos causados por dependência de controle são diminuídos com maneiras de “prever” se a instrução atual causará desvio na execução da sequência de instruções, com probabilidades altas de acerto Outra otimização possível é armazenar certas informações quando houver desvios na instrução, para serem usadas quando esta instrução aparecer novamente. Por exemplo, em um loop onde são feitas 10 iterações, ocorrem 9 desvios para a mesma instrução (a primeira)
  • 37.
    Acompanhe: i <-1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop i = 1
  • 38.
    Acompanhe: i <-1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop A condição é analisada e não ocorre desvio: entramos no loop
  • 39.
    Acompanhe: i <-1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop Hora de analisar novamente se i é menor ou igual a 10
  • 40.
    Acompanhe: i <-1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop Neste momento, i = 2, então para iniciar a segunda iteração...
  • 41.
    Acompanhe: i <-1; para i = 1 até 10 faça instrução 1; instrução 2; instrução 3; i <- i + 1; fim do loop ...desviamos de volta para a primeira instrução no loop
  • 42.
    Há ainda umaúltima forma de otimização que melhora o desempenho da nossa máquina, conhecida como superpipelining Vimos que a implementação do pipeline agiliza, idealmente, n e vezes a execução das instruções em relação à nossa máquina antiga Ora, por que então usar apenas 4 estágios? Um dos processadores da Intel possui pipeline de 20 estágios. Apenas para dar uma ideia, os primeiros 4 estágios são usados para operações de busca de instruções B1 B2 B3 B4 . . . . . .
  • 43.
    Esta configuração caracterizaexatamente um superpipeline Ok, 20 estágios já está melhor que 4. Mas por que não usar, talvez, 1000 estágios? Para executar várias operações do mesmo tipo ao mesmo tempo, precisaríamos aumentar o número de componentes. No caso de 4 operações de busca, por exemplo, o processador precisa ter 4 PCs para armazenar o endereço dessas instruções, 4 IRs para armazenar as instruções propriamente ditas, etc Aumentar o número de componentes encarece a máquina, o que tornaria um desastre elevar demais o número de estágios do pipeline
  • 44.
    Muito bem, falamosbastante sobre como amenizar os revés do pipeline, mas não podemos esquecer que estes não são os únicos que afetam o desempenho da máquina Até agora, economizamos alguns ciclos aqui, outros lá, já executamos várias instruções ao mesmo tempo e por aí vai Mas não nos aprofundamos ainda em um outro problema que aumenta consideravelmente o tempo gasto pela máquina na execução de problemas: leitura e escrita na memória principal Estas operações levam aproximadamente 100 ciclos para serem realizadas!