11.04.2013 Views

Execução concorrente de instruções: Pipelines

Execução concorrente de instruções: Pipelines

Execução concorrente de instruções: Pipelines

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong><br />

João Canas Ferreira<br />

Outubro <strong>de</strong> 2004<br />

Contém figuras <strong>de</strong> “Computer Architecture: A Quantitative Approach”, J. Hennessey & D. Patterson, 3 a . ed., MKP<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 1/33<br />

Assuntos<br />

1 <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong><br />

Conceito e finalida<strong>de</strong><br />

Dependências entre <strong>instruções</strong><br />

2 Fundamentos da operação <strong>de</strong> pipelines<br />

O que são pipelines<br />

Pipeline <strong>de</strong> 5 andares<br />

3 Resolução <strong>de</strong> conflitos<br />

Conflitos estruturais<br />

Conflitos <strong>de</strong> dados<br />

Conflitos <strong>de</strong> controlo<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 2/33


<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Conceito e finalida<strong>de</strong><br />

O mo<strong>de</strong>lo sequencial <strong>de</strong> computação<br />

No mo<strong>de</strong>lo sequencial <strong>de</strong> computação, a execução <strong>de</strong> um programa<br />

processa-se do seguinte modo:<br />

1. O CPU obtém uma instrução <strong>de</strong> memória.<br />

2. A operação é efectuada.<br />

3. É <strong>de</strong>terminado o en<strong>de</strong>reço da próxima instrução. Repetir a partir <strong>de</strong> 1.<br />

Os efeitos observáveis da execução incluem a alteração <strong>de</strong> registos ou<br />

posições <strong>de</strong> memória, a alteração <strong>de</strong> flags, geração <strong>de</strong> excepções, etc.<br />

Numa implementação que corresponda directamente ao mo<strong>de</strong>lo apenas se<br />

po<strong>de</strong> aumentar o <strong>de</strong>sempenho tornando a execução da operação mais<br />

rápida.<br />

Para ultrapassar esse limite é preciso executar <strong>instruções</strong> parcial ou<br />

totalmente em simultâneo.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 3/33<br />

3.1. O mo<strong>de</strong>lo sequencial permite atribuir <strong>de</strong> uma forma simples um “significado<br />

operacional” a um programa. Tem a gran<strong>de</strong> vantagem e ser relativamente<br />

próximo <strong>de</strong> uma possível implementação em hardware (com a unida<strong>de</strong> <strong>de</strong><br />

controlo implementada por uma máquina <strong>de</strong> estados) e do mo<strong>de</strong>lo formal <strong>de</strong><br />

máquina <strong>de</strong> Turing. Tem a <strong>de</strong>svantagem <strong>de</strong> impor uma or<strong>de</strong>m na execução<br />

<strong>de</strong> <strong>instruções</strong> cuja necessida<strong>de</strong> não <strong>de</strong>corre logicamente do algoritmo a<br />

implementar.<br />

3.2. No passo 3, a <strong>de</strong>terminação da próxima instrução a executar é feita<br />

geralmente <strong>de</strong> forma implícita: trata-se da instrução que resi<strong>de</strong> na posição a<br />

seguir à da instrução executada antes. Apenas as <strong>instruções</strong> <strong>de</strong> controlo <strong>de</strong><br />

fluxo indicam explicitamente a origem da próxima instrução (o “alvo” do<br />

salto).<br />

3.3. São concebíveis conjuntos <strong>de</strong> <strong>instruções</strong> em que cada instrução especifique o<br />

en<strong>de</strong>reço da seguinte (i.e., cada instrução é uma instrução <strong>de</strong> controlo <strong>de</strong><br />

fluxo). Muitos esquemas <strong>de</strong> microcódigo usam uma arquitectura <strong>de</strong>sse tipo.<br />

3


<strong>Execução</strong> <strong>concorrente</strong><br />

<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Conceito e finalida<strong>de</strong><br />

Concorrência parcial: A execução <strong>de</strong> uma instrução é dividida em fases.<br />

Num mesmo instante, diferentes <strong>instruções</strong> po<strong>de</strong>m estar em diferentes<br />

fases da sua execução.<br />

Problema: Dado um programa, i<strong>de</strong>ntificar que <strong>instruções</strong> po<strong>de</strong>m ser<br />

executadas <strong>concorrente</strong>mente, sem alterar os efeitos do programa.<br />

Efeitos do programa: Sequência <strong>de</strong> alterações visíveis do estado da<br />

memória e do processador.<br />

Existem muitas técnicas para <strong>de</strong>tectar e aproveitar o paralelismo entre<br />

<strong>instruções</strong> (i.e. a capacida<strong>de</strong> <strong>de</strong> executar <strong>instruções</strong> <strong>concorrente</strong>mente).<br />

Essa técnicas caem em duas categorias gerais:<br />

1. técnicas dinâmicas — o processador <strong>de</strong>tecta o paralelismo durante a<br />

execução do programa (Pentium III e 4, PowerPC G4);<br />

2. técnicas estáticas — o paralelismo é <strong>de</strong>tectado antes da execução<br />

pelo compilador (IA-64, sistemas embutidos).<br />

Não se trata <strong>de</strong> uma divisão estanque; algumas técnicas po<strong>de</strong>m ser<br />

adoptadas nos dois domínios.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 4/33<br />

4.1. As técnicas estáticas obrigam à recompilação dos programas para cada<br />

mo<strong>de</strong>lo diferente do compilador, mesmo que o conjunto <strong>de</strong> instrução não<br />

mu<strong>de</strong>. Quando a compatibilida<strong>de</strong> binária é importante, apenas as técnicas<br />

dinâmicas po<strong>de</strong> ser usadas. Excepção: Po<strong>de</strong> ser possível produzir um<br />

“tradutor binário” que converte um programa em binário <strong>de</strong> um mo<strong>de</strong>lo para<br />

o outro, refazendo as optimizações necessárias. Consultar, por exemplo,<br />

http://www.research.compaq.com/wrl/projects/om/om.html ou http:<br />

//www.experimentalstuff.com/Technologies/Walkabout/in<strong>de</strong>x.html.<br />

4.2. A utilização <strong>de</strong> técnicas dinâmicas não exclui o emprego das outras.<br />

Consi<strong>de</strong>re-se o caso dos processadores da Intel que implementam a<br />

arquitectura IA-32. A compatibilida<strong>de</strong> binária entre mo<strong>de</strong>los é garantida,<br />

mas a recompilação <strong>de</strong> um programa po<strong>de</strong> permitir a geração <strong>de</strong> código mais<br />

eficiente para um mo<strong>de</strong>lo particular (mas igualmente correcto para qualquer<br />

mo<strong>de</strong>lo).<br />

4


Aspectos básicos<br />

<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Conceito e finalida<strong>de</strong><br />

➛ O quantida<strong>de</strong> <strong>de</strong> paralelismo existente num bloco básico é reduzida:<br />

Blocos básicos têm tipicamente entre 5 e 7 <strong>instruções</strong> em média (MIPS).<br />

➛ Paralelismo simples <strong>de</strong> i<strong>de</strong>ntificar: loop-level parallelism<br />

Paralelismo entre iterações <strong>de</strong> um ciclo.<br />

for (i=1; i


<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Dependências entre <strong>instruções</strong><br />

O conceito <strong>de</strong> <strong>de</strong>pendência entre <strong>instruções</strong><br />

Duas <strong>instruções</strong> in<strong>de</strong>pen<strong>de</strong>ntes po<strong>de</strong>m ser executadas em simultâneo<br />

sem conflitos, <strong>de</strong>s<strong>de</strong> que existam recursos suficientes.<br />

Quando existe uma relação <strong>de</strong> <strong>de</strong>pendência entre duas <strong>instruções</strong>,<br />

estes <strong>de</strong>vem ser executadas em série (embora talvez com sobreposição<br />

parcial).<br />

<strong>de</strong>pendências <strong>de</strong> dados:<br />

<strong>de</strong>pendências verda<strong>de</strong>iras e <strong>de</strong>pendências <strong>de</strong> nomes.<br />

<strong>de</strong>pendências <strong>de</strong> controlo<br />

Um conflito ocorre sempre que existe uma <strong>de</strong>pendência entre<br />

<strong>instruções</strong> suficientemente próximas para que a sobreposição ou<br />

re-or<strong>de</strong>nação modifique a or<strong>de</strong>m <strong>de</strong> acesso ao operando envolvido na<br />

<strong>de</strong>pendência.<br />

A satisfação das <strong>de</strong>pendências garante a manutenção da or<strong>de</strong>m do<br />

programa , i.e., garante que as alterações <strong>de</strong> estado (observáveis) são as<br />

especificadas pelo mo<strong>de</strong>lo sequencial <strong>de</strong> execução.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 6/33<br />

6.1. O conceito <strong>de</strong> <strong>de</strong>pendência <strong>de</strong>pen<strong>de</strong> expressar formalmente a relação <strong>de</strong><br />

precedência entre duas <strong>instruções</strong>.<br />

6.2. Instruções <strong>de</strong>pen<strong>de</strong>ntes não po<strong>de</strong>m executar <strong>de</strong> forma totalmente <strong>concorrente</strong><br />

com as <strong>instruções</strong> <strong>de</strong> que <strong>de</strong>pen<strong>de</strong>m. Isto não implica que uma execução<br />

parcialmente <strong>concorrente</strong> seja impossível, como no caso <strong>de</strong> pipelines.<br />

6.3. Um conflito ocorre sempre que a execução (parcialmente) <strong>concorrente</strong> <strong>de</strong><br />

<strong>instruções</strong> leva à violação <strong>de</strong> uma <strong>de</strong>pendência. Se um conflito ocorre ou não<br />

(para uma dada <strong>de</strong>pendência) <strong>de</strong>pen<strong>de</strong> da organização interna do CPU. De<br />

um modo geral, preten<strong>de</strong>-se minimizar a ocorrência <strong>de</strong> conflitos.<br />

6.4. Um conflito po<strong>de</strong> ser sempre evitado se a execução <strong>de</strong> <strong>instruções</strong> retomar o<br />

modo <strong>de</strong> funcionamento completamente sequencial. Ou seja, quando ocorre<br />

um conflito é sempre possível resolvê-lo atrasando a execução das <strong>instruções</strong><br />

<strong>de</strong>pen<strong>de</strong>ntes. Assim garante-se para cada instrução que aquelas <strong>de</strong> que<br />

<strong>de</strong>pen<strong>de</strong> já foram certamente executadas.<br />

6


Dependências <strong>de</strong> dados<br />

<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Dependências entre <strong>instruções</strong><br />

A instrução j <strong>de</strong>pen<strong>de</strong> da instrução i (i is data-<strong>de</strong>pen<strong>de</strong>nt on j) se ocorrer<br />

uma das duas situações seguintes:<br />

1. a instrução i produz um resultado que po<strong>de</strong> ser usado pela instrução j;<br />

2. a instrução j <strong>de</strong>pen<strong>de</strong> da instrução k, que, por sua vez, <strong>de</strong>pen<strong>de</strong> da<br />

instrução i.<br />

A ca<strong>de</strong>ia <strong>de</strong> <strong>de</strong>pendências po<strong>de</strong> englobar o programa completo.<br />

Exemplo com 3 <strong>de</strong>pendências:<br />

Loop: L.D F0 , 0(R1) ; F0


<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Dependências entre <strong>instruções</strong><br />

Características das <strong>de</strong>pendências <strong>de</strong> dados<br />

A presença <strong>de</strong> uma <strong>de</strong>pendência <strong>de</strong> dados numa sequência <strong>de</strong><br />

<strong>instruções</strong> reflecte uma <strong>de</strong>pendência no programa original:<br />

<strong>de</strong>pendências são proprieda<strong>de</strong>s dos programas.<br />

O facto <strong>de</strong> uma <strong>de</strong>pendência resultar na <strong>de</strong>tecção <strong>de</strong> um conflito e/ou<br />

<strong>de</strong> causar um protelamento são proprieda<strong>de</strong>s da organização da<br />

pipeline.<br />

Uma <strong>de</strong>pendência:<br />

1. indica a possibilida<strong>de</strong> <strong>de</strong> existência <strong>de</strong> um conflito;<br />

2. <strong>de</strong>termina a or<strong>de</strong>m <strong>de</strong> cálculo;<br />

3. estabelece um limite superior para a quantida<strong>de</strong> <strong>de</strong> paralelismo que<br />

po<strong>de</strong> ser aproveitado.<br />

Fluxo <strong>de</strong> dados: (i) por registos [e flags]; (ii) por memória.<br />

Soluções:<br />

1. manter a <strong>de</strong>pendência, mas evitar o conflito;<br />

2. eliminar a <strong>de</strong>pendência por transformação do código.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 8/33<br />

8.1. Dependências causadas por transferências <strong>de</strong> informação via memória po<strong>de</strong>m<br />

ser difíceis <strong>de</strong> <strong>de</strong>tectar. Por exemplo, as <strong>instruções</strong> L.D R1, 100(R4) e<br />

L.D R1, 64(R6) po<strong>de</strong>m <strong>de</strong>signar a mesma posição <strong>de</strong> memória (por<br />

exemplo, se R4=0 e R6=36). Neste caso, diz-se que os en<strong>de</strong>reços efectivos<br />

são iguais.<br />

8.2. O en<strong>de</strong>reço efectivo <strong>de</strong> uma instrução também po<strong>de</strong> variar durante a<br />

execução do programa: basta que o conteúdo do registo associado mu<strong>de</strong>.<br />

Portanto, para efeitos <strong>de</strong> <strong>de</strong>tecção <strong>de</strong> conflitos, não basta analisar os códigos<br />

das <strong>instruções</strong>, é necessário ter em conta também o estado dos registos.<br />

8.3. Quando não é possível garantir a ausência <strong>de</strong> conflitos, é necessário assumir<br />

que eles po<strong>de</strong>m existir, caso contrário, não seria possível garantir a execução<br />

correcta do programa.<br />

8


Dependências <strong>de</strong> nome<br />

<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Dependências entre <strong>instruções</strong><br />

Uma <strong>de</strong>pendência <strong>de</strong> nome ocorre quando duas <strong>instruções</strong> usam o mesmo<br />

registo ou posição <strong>de</strong> memória (um «nome»), mas sem que haja um fluxo<br />

<strong>de</strong> dados associado com esse nome. Existem dois tipos <strong>de</strong> <strong>de</strong>pendências <strong>de</strong><br />

nome envolvendo uma instrução i que prece<strong>de</strong> a instrução j num programa:<br />

Uma anti<strong>de</strong>pendência entre i e j ocorre quando a instrução j escreve<br />

num registo ou posição <strong>de</strong> memória lido pela instrução i.<br />

Uma <strong>de</strong>pendência <strong>de</strong> saída ocorre quando ambas as <strong>instruções</strong><br />

escrevem no mesmo registo ou posição <strong>de</strong> memória. A or<strong>de</strong>m das<br />

<strong>instruções</strong> <strong>de</strong>ve ser preservada para garantir que o valor final<br />

correspon<strong>de</strong> a j.<br />

Como não se trata <strong>de</strong> verda<strong>de</strong>iras <strong>de</strong>pendências, as <strong>instruções</strong> i e j po<strong>de</strong>m<br />

ser executadas simultaneamente (ou por or<strong>de</strong>m diferente) <strong>de</strong>s<strong>de</strong> que o<br />

«nome» usado seja mudado. Esta operação é mais fácil <strong>de</strong> executar (pelo<br />

compilador ou processador) para registos: register renaming.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 9/33<br />

9.1. Dependências <strong>de</strong> nome ocorrem, por exemplo, quando um registo (associado<br />

a uma variável) é reutilizado para guardar o valor <strong>de</strong> outra variável.<br />

9.2. Em geral, <strong>de</strong>pendências <strong>de</strong> nome envolvendo registos po<strong>de</strong>m ser evitadas se<br />

existirem registos temporários que permitam guardar todos os valores. Todas<br />

as <strong>instruções</strong> que referem o «nome» original <strong>de</strong>vem ser modificadas<br />

dinamicamente para usarem os dados dos registos temporários apropriados.<br />

9


Conflitos <strong>de</strong> dados<br />

<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Dependências entre <strong>instruções</strong><br />

Conflitos <strong>de</strong> dados possíveis entre duas <strong>instruções</strong> i e j (que ocorrem no<br />

programa por esta or<strong>de</strong>m):<br />

RAW (read after write) — j tenta ler uma fonte antes que i aí coloque<br />

um valor. Correspon<strong>de</strong> a uma verda<strong>de</strong>ira <strong>de</strong>pendência <strong>de</strong> dados.<br />

WAW (write after write) — j tenta escrever num local antes <strong>de</strong> i.<br />

Correspon<strong>de</strong> a uma <strong>de</strong>pendência <strong>de</strong> saída. Ocorre em pipelines que<br />

efectuam escritas em mais que um andar ou que permitem que<br />

<strong>instruções</strong> continuem mesmo quando uma instrução anterior é<br />

protelada.<br />

WAR (write after read) — j tenta escrever num local antes <strong>de</strong> este<br />

ser lido por i. Correspon<strong>de</strong> a uma anti<strong>de</strong>pendência. Não ocorre na<br />

maioria das pipelines com emissão estática <strong>de</strong> <strong>instruções</strong>.<br />

RAR (read after read) não constitui um conflito.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 10/33<br />

10.1. O nome dos conflitos é dado <strong>de</strong> acordo com a or<strong>de</strong>m do programa que <strong>de</strong>ve<br />

ser preservada.<br />

10.2. Conflitos do tipo war ten<strong>de</strong>m a surgir apenas em processadores que emitem<br />

<strong>instruções</strong> fora <strong>de</strong> or<strong>de</strong>m (emitir uma instrução = iniciar a sua execução) ou<br />

que suportam conjuntos heterogéneos <strong>de</strong> <strong>instruções</strong> em que algumas<br />

<strong>instruções</strong> alteram dados no início da execução e outras lêem dados nas fases<br />

finais da execução. Muitos processadores nunca po<strong>de</strong>m ter conflitos <strong>de</strong>ste<br />

tipo.<br />

10.3. Conflitos do tipo waw também não correm nas organizações <strong>concorrente</strong>s<br />

mais simples. Por exemplo, a pipeline básica analisada mais à frente não tem<br />

<strong>de</strong>stes conflitos.<br />

10


<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Dependências entre <strong>instruções</strong><br />

Dependências <strong>de</strong> controlo<br />

Uma <strong>de</strong>pendência <strong>de</strong> controlo <strong>de</strong>termina a or<strong>de</strong>m <strong>de</strong> uma instrução i face<br />

a uma instrução <strong>de</strong> salto condicional. Todas as <strong>instruções</strong> <strong>de</strong> um<br />

programa, excepto as do primeiro bloco básico, <strong>de</strong>pen<strong>de</strong>m <strong>de</strong> algum<br />

conjunto <strong>de</strong> saltos condicionais.<br />

Dependências <strong>de</strong> controlo impõem duas restrições:<br />

Uma instrução <strong>de</strong>pen<strong>de</strong>nte <strong>de</strong> um salto não po<strong>de</strong> ser colocada antes do<br />

salto, porque já não seria controlada pelo instrução <strong>de</strong> salto condicional.<br />

Uma instrução que não está <strong>de</strong>pen<strong>de</strong>nte <strong>de</strong> um salto não po<strong>de</strong> ser movida<br />

para <strong>de</strong>pois <strong>de</strong> um salto, porque passaria a ser controlada por esse salto.<br />

No caso mais simples, <strong>de</strong>pendências <strong>de</strong> controlo são preservadas porque<br />

1. as <strong>instruções</strong> são executadas pela or<strong>de</strong>m em que surgem no programa;<br />

2. o controlo <strong>de</strong> conflitos garante que uma instrução não é executada antes <strong>de</strong> se<br />

conhecer o <strong>de</strong>stino do salto.<br />

Respeitar as <strong>de</strong>pendências <strong>de</strong> controlo não é um fim em si; o que se quer<br />

garantir é o fluxo <strong>de</strong> dados e o comportamento face a excepções.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 11/33<br />

11.1. Exemplo <strong>de</strong> uma <strong>de</strong>pendência <strong>de</strong> controlo simples:<br />

if cond1 instr1;<br />

if cond2 instr2;<br />

A instrução instr1 apresenta uma <strong>de</strong>pendência <strong>de</strong> controlo em relação a<br />

cond1 e instr2 tem uma <strong>de</strong>pendência <strong>de</strong> controlo <strong>de</strong> cond2, mas não <strong>de</strong><br />

cond1.<br />

11


<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Dependências entre <strong>instruções</strong><br />

Comportamento correcto na presença <strong>de</strong> excepções<br />

➛ Comportamento correcto na presença <strong>de</strong> excepções significa que<br />

qualquer alteração da or<strong>de</strong>m <strong>de</strong> execução das <strong>instruções</strong> não modifica a<br />

forma como as excepção são levantadas no programa.<br />

➛ Frequentemente usa-se uma condição mais relaxada: a nova or<strong>de</strong>m não<br />

<strong>de</strong>ve causar a ocorrência <strong>de</strong> novas excepções no programa.<br />

DADDU R2 , R3, R4<br />

BEQZ R2 , L1 ; saltar para L1 se R2=0<br />

LW R1, 0( R2 )<br />

L1: . . .<br />

Existe uma <strong>de</strong>pendência <strong>de</strong> dados envolvendo R2.<br />

É possível trocar as duas últimas <strong>instruções</strong>? Não existe nenhuma <strong>de</strong><br />

<strong>de</strong>pendência <strong>de</strong> dados entre elas. Mas a instrução LW po<strong>de</strong> causar uma<br />

excepção no acesso a memória.<br />

Uma técnica <strong>de</strong>signada por especulação permite ultrapassar este problema.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 12/33<br />

12.1. A <strong>de</strong>pendência <strong>de</strong> dados envolvendo R2 impõe que a primeira instrução seja<br />

executada em primeiro lugar, mas não impõe uma or<strong>de</strong>m relativa entre as<br />

outras duas; essa or<strong>de</strong>m é imposta pela <strong>de</strong>pendência <strong>de</strong> controlo <strong>de</strong> LW em<br />

relação a BEQZ. Não existe uma <strong>de</strong>pendência <strong>de</strong> dados entre estas duas<br />

<strong>instruções</strong>.<br />

12.2. Como é que a instrução LW po<strong>de</strong> causar uma excepção? Por exemplo,<br />

ace<strong>de</strong>ndo a uma zona <strong>de</strong> memória que não pertença ao seu processo. Assim,<br />

po<strong>de</strong>ria ocorrer uma excepção que não surgiria se a or<strong>de</strong>m do programa fosse<br />

alterada.<br />

12.3. As técnicas <strong>de</strong> especulação <strong>de</strong>vem ser capazes <strong>de</strong> anular o lançamento da<br />

excepção caso o salto condicional seja efectivamente tomado.<br />

12


<strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> Dependências entre <strong>instruções</strong><br />

Preservação do fluxo <strong>de</strong> dados<br />

Fluxo <strong>de</strong> dados: fluxo <strong>de</strong> valores entre as <strong>instruções</strong> que os produzem e as<br />

que os consomem. As <strong>instruções</strong> <strong>de</strong> salto condicional fazem com que o<br />

fluxo seja dinâmico, i.e., o valor <strong>de</strong> um dado registo/posição <strong>de</strong> memória<br />

po<strong>de</strong> provir <strong>de</strong> diferentes origens.<br />

DADDU R1, R2, R3<br />

BEQZ R4, L<br />

DSUBU R1, R5, R6<br />

L: . . .<br />

OR R7, R1, R8<br />

DSUBU não po<strong>de</strong> ser colocada antes do salto por alterar o fluxo <strong>de</strong> dados<br />

<strong>de</strong> OR. O valor <strong>de</strong> R1 <strong>de</strong>pen<strong>de</strong> do salto BEQZ.<br />

Por vezes, é possível <strong>de</strong>terminar que o <strong>de</strong>srespeito <strong>de</strong> uma <strong>de</strong>pendência <strong>de</strong><br />

controlo não afecta o fluxo ou a geração <strong>de</strong> excepções. Esta tarefa é<br />

geralmente efectuada pelos compiladores.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 13/33<br />

13.1. Exemplo <strong>de</strong> uma situação DADDU em R1, que R2, umaR3<strong>de</strong>pendência <strong>de</strong> controlo po<strong>de</strong> ser<br />

BEQZ R12, skipnext<br />

<strong>de</strong>srespeitada:<br />

DSUBU R4, R5, R6 ; po<strong>de</strong> ser "adiantada"<br />

DADDU R5, R4, R9<br />

skipnext: OR R7, R8, R9 ; R4 não é usado mais<br />

Suponhamos que o registo R4não era usado no bloco <strong>de</strong> código colocado após<br />

a etiqueta skipnext. Então passar a instrução DSUBU para antes do salto<br />

não alteraria os efeitos do programa (o item <strong>de</strong> dados em R4 está “morto”).<br />

13.2. Determinar se os dados guardados num registo estão “vivos” (vão ser ainda<br />

usados) ou “mortos” (não são mais usados) é uma das tarefas que<br />

geralmente incumbe ao compilador (para saber quando po<strong>de</strong> reutilizar<br />

registos).<br />

13


<strong>Pipelines</strong><br />

Fundamentos da operação <strong>de</strong> pipelines O que são pipelines<br />

Pipelining é uma técnica <strong>de</strong> implementação em que a execução <strong>de</strong><br />

múltiplas <strong>instruções</strong> é feita <strong>concorrente</strong>mente.<br />

Analogia: Linha <strong>de</strong> montagem.<br />

A B C D<br />

andar 1 andar 2 andar 3 andar 4<br />

ciclo 1 2 3 4 5 6 · · ·<br />

inst 1 A B C D<br />

inst 2 A B C D<br />

inst 3 A B C D<br />

inst 4 A B C · · ·<br />

inst 5 A B · · ·<br />

inst 6 A · · ·<br />

Notas:<br />

Cada andar trabalha <strong>concorrente</strong>mente<br />

com os outros, embora sobre<br />

uma “parte” diferente da instrução.<br />

débito: n o <strong>de</strong> <strong>instruções</strong> que são completadas<br />

(i.e. abandonam a pipeline) por unida<strong>de</strong><br />

<strong>de</strong> tempo.<br />

ciclo do processador: tempo necessário<br />

para “mover” a instrução através <strong>de</strong> 1 andar.<br />

O ciclo do processador é <strong>de</strong>terminado pelo<br />

andar mais lento.<br />

I<strong>de</strong>al: Equilibrar o tempo <strong>de</strong> todos os andares.<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 14/33<br />

14.1. Em cada instante po<strong>de</strong>m estar até 4 <strong>instruções</strong> em execução (neste<br />

exemplo); em cada ciclo (a partir do 4) é terminada uma instrução.<br />

14.2. Como os andares estão interligados, é necessário que todos estejam prontos<br />

ao mesmo tempo: esse tempo constitui o período do ciclo <strong>de</strong> relógio do<br />

processador.<br />

14.3. Porque os andares <strong>de</strong>vem prosseguir todos ao mesmo tempo, a duração do<br />

ciclo é <strong>de</strong>terminado pelo tempo necessário para que o andar mais lento<br />

execute a sua tarefa.<br />

14.4. Se o tempo <strong>de</strong> processamento <strong>de</strong> todos os andares for idêntico, então o<br />

tempo médio por operação é (em condições i<strong>de</strong>ais)<br />

tempo por instrução do CPU sem pipeline<br />

número <strong>de</strong> andares<br />

14.5. Pipelining é tipicamente invisível para o programador (em CPUS com<br />

interlocks).<br />

14


Fundamentos da operação <strong>de</strong> pipelines Pipeline <strong>de</strong> 5 andares<br />

Um conjunto <strong>de</strong> <strong>instruções</strong> RISC básico<br />

Para efeitos <strong>de</strong> análise das questões que surgem em pipelines, usaremos<br />

um subconjunto do MIPS64 (ver tb. a página www da disciplina).<br />

➛ Todas as operações sobre dados aplicam-se a registos <strong>de</strong> 64 bits e<br />

modificam todo o registo;<br />

➛ Apenas <strong>instruções</strong> load/store afectam a memória; po<strong>de</strong>m operar sobre<br />

parte <strong>de</strong> um registo (por exemplo, afectando 32 bits <strong>de</strong> 64);<br />

➛ As <strong>instruções</strong> têm todas o mesmo comprimento e os formatos<br />

diferentes são poucos.<br />

➛ Instruções da ALU: Tomam dois registos, ou um registo e um valor<br />

imediato <strong>de</strong> 16 bits, como operandos e guardam o resultado num<br />

terceiro registo.<br />

➛ Instruções load/store: Tomam um registo (a base) e um<br />

<strong>de</strong>slocamento (<strong>de</strong> 16 bits) como operandos. Um segundo registo é o<br />

<strong>de</strong>stino/origem da transferência.<br />

➛ Saltos condicionais e incondicionais: Os saltos condicionais<br />

baseiam-se no resultado da comparação entre dois registos.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 15/33<br />

15.1. As <strong>instruções</strong> indicadas constituem um subconjunto <strong>de</strong> MIPS64. Esta<br />

arquitectura <strong>de</strong> conjunto <strong>de</strong> <strong>instruções</strong> será analisada com mais pormenor<br />

numa aula teórico-prática.<br />

15.2. Os saltos condicionais são relativos e têm um <strong>de</strong>slocamento <strong>de</strong> 16 bits (são<br />

interpretados como números com sinal).<br />

15.3. Todas as <strong>instruções</strong> têm todas o mesmo tamanho: 32 bits.<br />

15


Fundamentos da operação <strong>de</strong> pipelines Pipeline <strong>de</strong> 5 andares<br />

Implementação multi-ciclo sem pipelining<br />

1. IF (instruction fetch): Usa o en<strong>de</strong>reço contido no contador <strong>de</strong><br />

programa (PC) para ir buscar a instrução actual a memória. Actualiza<br />

PC: PC ← PC+4.<br />

2. ID (instruction <strong>de</strong>co<strong>de</strong>/register fetch): Descodifica a instrução e lê<br />

os registos fonte. Compara registos. Efectua extensão do<br />

<strong>de</strong>slocamento. Calcula en<strong>de</strong>reço <strong>de</strong> <strong>de</strong>stino e actualiza PC (se saltar).<br />

3. EX (execution/effective address): Uma <strong>de</strong> 3 operações: (i) calcula<br />

en<strong>de</strong>reço efectivo para acesso a memória; (ii) a ALU executa a<br />

operação sobre os registos; (iii) a ALU executa operação sobre registo e<br />

valor imediato.<br />

4. MEM (memory access): Para <strong>instruções</strong> load/store: transferir dados.<br />

5. WB (write-back): Instrução <strong>de</strong> ALU ou load: guardar dados em<br />

registo.<br />

Saltos: 2 ciclos, store: 4 ciclos, outras: 5 ciclos. Globalmente, CPI=4.54 se<br />

assumirmos frequências <strong>de</strong> 12%, 10%, e 78%, respectivamente.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 16/33<br />

16.1. Este esquema apresenta uma divisão possível das etapas pelas quais passa a<br />

execução <strong>de</strong> cada instrução. Trata-se <strong>de</strong> um passo preliminar, com vista a<br />

simplificar a <strong>de</strong>scrição do funcionamento da pipeline básica.<br />

16.2. Nem todas as <strong>instruções</strong> necessitam <strong>de</strong> todas as etapas. As <strong>instruções</strong> <strong>de</strong><br />

salto terminam na 2 a etapa. As <strong>instruções</strong> <strong>de</strong> escrita em memória terminam<br />

na 4 a etapa.<br />

16.3. As <strong>instruções</strong> <strong>de</strong> ALU não fazem nada na etapa 4, terminando na etapa 5.<br />

Seria possível antecipar a última tarefa da etapa 5 para a etapa 5. Contudo,<br />

isso já não será possível na implementação em pipeline, pelo que também<br />

não é feito aqui.<br />

16


Fundamentos da operação <strong>de</strong> pipelines Pipeline <strong>de</strong> 5 andares<br />

Pipeline <strong>de</strong> cinco andares<br />

O processamento po<strong>de</strong> ser implementado com pipeline <strong>de</strong> 5 andares (aliás<br />

a divisão <strong>de</strong> tarefas da transparência anterior já foi feita a pensar nisso).<br />

Ciclo <strong>de</strong> processador<br />

Instrução 1 2 3 4 5 6 7 8 9<br />

i IF ID EX MEM WB<br />

i + 1 IF ID EX MEM WB<br />

i + 2 IF ID EX MEM WB<br />

i + 3 IF ID EX MEM WB<br />

i + 4 IF ID EX MEM WB<br />

Restrição: Não é possível usar os mesmos recursos em duas tarefas<br />

diferentes no mesmo ciclo! Memórias cache separadas para dados e<br />

<strong>instruções</strong> evitam conflitos entre IF e MEM.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 17/33<br />

17.1. A fase IF tem um acesso implícito a memória, pelo que po<strong>de</strong>ria interferir<br />

com <strong>instruções</strong> na fase MEM. Para evitar um conflito, vamos assumir que<br />

memória <strong>de</strong> <strong>instruções</strong> e memória <strong>de</strong> dados são diferentes. Embora tal não<br />

corresponda estritamente à realida<strong>de</strong>, a utilização <strong>de</strong> caches separadas para<br />

dados e <strong>instruções</strong> faz com que seja uma aproximação razoável.<br />

17.2. Para já assumimos que o acesso a memória po<strong>de</strong> ser feito apenas num ciclo<br />

<strong>de</strong> relógio do processador. Trata-se <strong>de</strong> uma suposição menos realista que a<br />

anterior. Veremos mais tar<strong>de</strong> como remover esta restrição e <strong>de</strong> que maneira<br />

é afectado o <strong>de</strong>sempenho global.<br />

17.3. As <strong>instruções</strong> <strong>de</strong> salto só usam dois andares: IF e ID.<br />

17.4. As <strong>instruções</strong> <strong>de</strong> escrita em memória (store) não têm WB.<br />

17.5. Estamos a assumir que as operações executadas em EX apenas necessitam<br />

<strong>de</strong> um ciclo <strong>de</strong> relógio. Isso não se aplica a operações como a divisão nem a<br />

operações com vírgula flutuante.<br />

17


Fundamentos da operação <strong>de</strong> pipelines Pipeline <strong>de</strong> 5 andares<br />

Múltiplos percursos <strong>de</strong> dados <strong>de</strong>sfasados no tempo<br />

O banco <strong>de</strong> registos tem <strong>de</strong> suportar 2 leituras e 1 escrita por ciclo.<br />

Problema: Salto condicional só modifica PC no andar ID.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 18/33<br />

18.1. Implicitamente estamos a assumir que existem recursos para executar<br />

<strong>concorrente</strong>mente as várias operações. Por exemplo, o cálculo do novo valor<br />

<strong>de</strong> PC no caso <strong>de</strong> um salto não po<strong>de</strong> ser feito pela ALU (que estará ocupada<br />

com o processamento <strong>de</strong> outra instrução).<br />

18.2. O banco <strong>de</strong> registos po<strong>de</strong> tornar-se facilmente num factor <strong>de</strong> contenção.<br />

Vamos assumir que todas as leituras são feitas no fim do ciclo <strong>de</strong> relógio (por<br />

<strong>instruções</strong> na fase ID) e que a escrita é feita no início do ciclo <strong>de</strong> relógio<br />

(pela instrução que passar para WB).<br />

período <strong>de</strong> relógio<br />

escrita<br />

18.3. Como estamos assumir uma implementação relativamente agressiva dos<br />

saltos condicionais, supomos que o PC é modificado no segundo ciclo da<br />

instrução (ID). Mesmo assim, os saltos (condicionais ou incondicionais) vão<br />

introduzir um conflito <strong>de</strong> controlo.<br />

18<br />

leitura


Fundamentos da operação <strong>de</strong> pipelines Pipeline <strong>de</strong> 5 andares<br />

Inserção <strong>de</strong> registos entre andares<br />

Evitam a interferência entre andares e preservam valores intermédios.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 19/33<br />

19.1. Sem cuidados especiais, a activida<strong>de</strong> “lógica” não po<strong>de</strong> ser limitada a um<br />

certo andar (i.e., os efeitos <strong>de</strong> qualquer mudança propagar-se-iam mais ou<br />

menos rapidamente por todo o circuito). Para evitar essa interferência, todos<br />

os os sinais que saem <strong>de</strong> um andar são “registados”, ou seja, os seus valores<br />

são guardados num elemento <strong>de</strong> memória (registo) cujo conteúdo apenas é<br />

alterado no flanco ascen<strong>de</strong>nte do relógio.<br />

19.2. Muitos dos registo já seriam necessários numa implementação multi-ciclo<br />

para preservar valores entre os diferentes ciclos.<br />

19.3. Os registos também serão aproveitados para evitar alguns conflitos<br />

provocados por <strong>de</strong>pendências <strong>de</strong> dados (cf. forwarding).<br />

19


Fundamentos da operação <strong>de</strong> pipelines Pipeline <strong>de</strong> 5 andares<br />

Desempenho <strong>de</strong> pipelines (1 a abordagem)<br />

Pipeline i<strong>de</strong>almente equilibrada: tinst_p = tinst<br />

Nandares<br />

Na prática, o tempo <strong>de</strong> execução <strong>de</strong> cada instrução aumenta<br />

ligeiramente <strong>de</strong>vido a overhead <strong>de</strong> controlo.<br />

O programa é mais rápido embora nenhuma instrução seja mais<br />

rápida!<br />

Speedup: Sp = tinst/tinst_p<br />

Na prática, certa <strong>instruções</strong> po<strong>de</strong>m necessitar <strong>de</strong> ciclos <strong>de</strong><br />

protelamento em algumas circunstâncias. Seja nprot o número médio<br />

<strong>de</strong> ciclos <strong>de</strong> protelamento por instrução. Então:<br />

CPIp = CPIi<strong>de</strong>al + nprot = 1 + nprot<br />

Assumindo igual frequência <strong>de</strong> relógio:<br />

Notas:<br />

Sp = CPI<br />

1 + nprot<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 20/33<br />

20.1. A melhoria <strong>de</strong> <strong>de</strong>sempenho proporcionada por pipelining é directamente<br />

<strong>de</strong>pen<strong>de</strong>nte do número médio <strong>de</strong> ciclos <strong>de</strong> protelamento. Torna-se, portanto,<br />

imperioso reduzir nprot ao mínimo. Como os saltos são, em muitas<br />

organizações <strong>de</strong> CPU, a principal fonte <strong>de</strong> ciclos <strong>de</strong> protelamento, torna-se<br />

vital reduzir a sua frequência ou o seu impacto.<br />

20.2. A expressão final para Sp assume que a frequência <strong>de</strong> relógio <strong>de</strong> uma<br />

implementação pipelined é igual à <strong>de</strong> uma implementação multi-ciclo. Na<br />

prática, será ligeiramente maior (≈ 10%). O número <strong>de</strong> <strong>instruções</strong><br />

executadas é naturalmente o mesmo.<br />

20


Resolução <strong>de</strong> conflitos<br />

Alguns problemas na utilização <strong>de</strong> pipelines<br />

Existem situações (hazards) em que uma instrução não po<strong>de</strong> ser executada<br />

durante o ciclo apropriado. Existem três tipos <strong>de</strong> conflitos:<br />

estruturais É um conflito <strong>de</strong> recursos: o hardware não suporta a<br />

execução <strong>concorrente</strong> <strong>de</strong> todas as combinações possíveis <strong>de</strong><br />

tarefas;<br />

<strong>de</strong> dados Este conflito surge quando uma instrução <strong>de</strong>pen<strong>de</strong> dos<br />

resultados <strong>de</strong> uma instrução anterior <strong>de</strong> uma forma que é<br />

“exposta” pela linha <strong>de</strong> processamento.<br />

<strong>de</strong> controlo este conflito resulta <strong>de</strong> saltos condicionais ou <strong>de</strong> outras<br />

<strong>instruções</strong> que alteram o PC.<br />

Conflitos reduzem o <strong>de</strong>sempenho i<strong>de</strong>al da pipeline.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 21/33<br />

21.1. Conflitos <strong>de</strong> dados e <strong>de</strong> controlo são <strong>de</strong>vidos, respectivamente, a<br />

<strong>de</strong>pendências <strong>de</strong> dados e <strong>de</strong> controlo. Conflitos estruturais resultam da<br />

inexistência <strong>de</strong> recursos suficientes para executar algumas operações<br />

<strong>concorrente</strong>mente.<br />

21


Resolução <strong>de</strong> conflitos<br />

Protelamento <strong>de</strong> operações<br />

Conflitos po<strong>de</strong>m obrigar a protelar (stall) o processamento <strong>de</strong> <strong>instruções</strong>.<br />

Habitualmente quando uma instrução é protelada:<br />

1. todas as <strong>instruções</strong> emitidas posteriormente também são proteladas;<br />

2. todas as <strong>instruções</strong> emitidas anteriormente <strong>de</strong>vem prosseguir (para<br />

“limpar” a situação <strong>de</strong> conflito).<br />

Consequência: durante o protelamento não são processadas novas<br />

<strong>instruções</strong>.<br />

Po<strong>de</strong> não ser economicamente proveitoso eliminar conflitos que ocorram<br />

raramente, porque os protelamentos associados são raros (número médio<br />

<strong>de</strong> ciclos <strong>de</strong> protelamento causados por esses conflitos é baixo).<br />

Nota: Existem esquemas em que as <strong>instruções</strong> emitidas posteriormente<br />

po<strong>de</strong>m “passar à frente” da instrução protelada (se não violarem nenhuma<br />

<strong>de</strong>pendência).<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 22/33<br />

22.1. O protelamento <strong>de</strong> operação é a solução “universal”. Contudo, é sempre<br />

preciso implementar circuitos <strong>de</strong> <strong>de</strong>tecção <strong>de</strong> conflitos (pipeline interlocks).<br />

22


Conflitos estruturais<br />

Resolução <strong>de</strong> conflitos Conflitos estruturais<br />

A execução <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong> em pipeline po<strong>de</strong> requerer que as<br />

unida<strong>de</strong>s funcionais sejam também pipelined e que outros recursos sejam<br />

duplicados para acomodar todas as combinações possíveis <strong>de</strong> <strong>instruções</strong>. O<br />

processamento po<strong>de</strong> exibir conflitos estruturais quando tal não acontece.<br />

Exemplo: processador com uma memória cache partilhada para<br />

dados/<strong>instruções</strong> (memória comum <strong>de</strong> dados e <strong>instruções</strong>).<br />

Ciclo <strong>de</strong> processador<br />

Instrução 1 2 3 4 5 6 7 8 9 10<br />

load IF ID EX MEM WB<br />

i + 1 IF ID EX MEM WB<br />

i + 2 IF ID EX MEM WB<br />

i + 3 stall IF ID EX MEM WB<br />

i + 4 IF ID EX MEM WB<br />

i + 5 IF ID EX MEM<br />

i + 6 IF ID EX<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 23/33<br />

23.1. Esta situação não ocorre na organização <strong>de</strong> base que estamos a analisar,<br />

porqie assumimos a existência <strong>de</strong> caches separadas <strong>de</strong> dados e <strong>instruções</strong>.<br />

23


Resolução <strong>de</strong> conflitos Conflitos estruturais<br />

Ilustração <strong>de</strong> um conflito estrutural<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 24/33<br />

24.1. Notar que não existe nenhum conflito estrutural associado ao banco <strong>de</strong><br />

registos.Por exemplo, no ciclo 5, ocorrem uma escrita no banco <strong>de</strong> registos<br />

(associado à instrução load) e duas leituras (associadas à instrução 3). Estas<br />

operações ocorrem em partes diferentes do ciclo, conforme indicado<br />

graficamente pelo tracejado: a escrita acontece no início do ciclo, as leituras<br />

no fim.<br />

24


Conflitos <strong>de</strong> dados<br />

Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> dados<br />

Um gran<strong>de</strong> efeito <strong>de</strong> pipelining é modificar a temporização relativa das<br />

operações, o que po<strong>de</strong> introduzir conflitos.<br />

Conflitos <strong>de</strong> dados ocorrem quando a or<strong>de</strong>m <strong>de</strong> leitura/escrita <strong>de</strong><br />

operandos é modificada (por referência à versão sem pipelining).<br />

Exemplo:<br />

DADD R1, R2, R3<br />

DSUB R4, R1, R5 ;ADD altera R1 em WB, mas DSUB requer valor em ID<br />

AND R6, R1, R7 ;R1 correcto fim do ciclo 5; AND lê registos no 4<br />

OR R8, R1, R9 ;OR não tem conflitos; leituras na 2 a parte do ciclo<br />

XOR R10, R1, R11 ;não tem conflitos<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 25/33<br />

25.1. O registos R1 é alterado pela primeira instrução. Como o resultado da<br />

instrução só atinge os registos no quinto ciclo, a instrução DSUB produz um<br />

conflito ao querer usar o novo valor <strong>de</strong> R1 no quarto ciclo (a sua etapa EX),<br />

já que isso implica a leitura dos registos no fim do ciclo anterior (o ciclo 3).<br />

25.2. A instrução AND também produz um conflito: precisa do novo valor logo no<br />

início do quinto ciclo (a sua etapa EX), e portanto, a leitura dos registos foi<br />

feita no ciclo anterior, quando o banco <strong>de</strong> registos ainda tinha o valor antigo<br />

<strong>de</strong> R1.<br />

25.3. A instrução OR já não provoca conflito.<br />

25.4. Este tipo <strong>de</strong> conflito entre <strong>instruções</strong> da ALU é muito frequente e introduz 2<br />

ciclos <strong>de</strong> protelamento, o que é muito. Consequentemente, este tipo <strong>de</strong><br />

conflito <strong>de</strong>ve necessariamente ser resolvido.<br />

25.5. Notar que o conflito surge porque a alteração do banco <strong>de</strong> registos é<br />

efectuada 2 ciclos <strong>de</strong>pois do cálculo do resultado. O resultado propriamente<br />

dito já foi calculado (no fim do ciclo 3).<br />

25


Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> dados<br />

Forwarding po<strong>de</strong> resolver conflitos <strong>de</strong> dados<br />

O resultado da ALU é realimentado para a sua entrada. O banco <strong>de</strong><br />

registos (leitura e escrita em partes diferentes do ciclo) também serve para<br />

fazer forwarding. A sequência analisada executa sem protelamento.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 26/33<br />

26.1. O novo valor <strong>de</strong> R1 é calculado antes <strong>de</strong> ser necessário para as operações<br />

seguintes. Apenas o banco <strong>de</strong> registos não é actualizado suficientemente<br />

<strong>de</strong>pressa.<br />

26.2. Para resolver o conflito, basta “agulhar” o futuro valor <strong>de</strong> R1 do registo<br />

temporário on<strong>de</strong> se encontra para a entrada do andar que necessita do seu<br />

valor. Locais <strong>de</strong> origem e <strong>de</strong>stino dos dados estão indicados a tracejado na<br />

figura.Sempre que o <strong>de</strong>stino estiver à frente da origem, <strong>de</strong>ve proce<strong>de</strong>r-se ao<br />

agulhamento necessário.<br />

26.3. Para além dos circuitos <strong>de</strong> agulhamento (basicamente multiplexadores), o<br />

CPU <strong>de</strong>ve dispor também <strong>de</strong> circuitos <strong>de</strong> <strong>de</strong>tecção dos conflitos.<br />

26.4. A utilização <strong>de</strong> forwarding é indispensável para um bom <strong>de</strong>sempenho.<br />

26


Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> dados<br />

Protelamento po<strong>de</strong> ser inevitável<br />

LD R1, 0(R2) ; dados prontos apenas no fim do ciclo 4<br />

DSUB R4, R1, R5 ; necessita <strong>de</strong> dados no início <strong>de</strong> 4<br />

AND R6, R1, R7<br />

OR R8, R1, R9<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 27/33<br />

27.1. O esquema <strong>de</strong> forwarding não resolve todos os problemas. Por exemplo, o<br />

conflito que ocorre quando uma instrução usa um valor lido <strong>de</strong> memória pela<br />

instrução imediatamente prece<strong>de</strong>nte não po<strong>de</strong> ser resolvido <strong>de</strong>sta maneira.<br />

27.2. De facto, o valor ainda não está no CPU no instante em que se preten<strong>de</strong>ria<br />

utilizá-lo. Isso é indicado pelo segmento a tracejado em que o <strong>de</strong>stino (o<br />

“lugar” on<strong>de</strong> o valor é necessário para o restante processamento) está<br />

“atrás” da origem.<br />

27


Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> dados<br />

Protelar resolve o problema. . .<br />

Ciclo <strong>de</strong> processador<br />

Instrução 1 2 3 4 5 6 7 8 9<br />

LD R1,0(R2) IF ID EX MEM WB<br />

DSUB R4, R1, R5 IF ID EX MEM WB<br />

AND R6, R1, R7 IF ID EX MEM WB<br />

OR R8, R1, R9 IF ID EX MEM WB<br />

LD R1,0(R2) IF ID EX MEM WB<br />

DSUB R4, R1, R5 IF ID stall EX MEM WB<br />

AND R6, R1, R7 IF stall ID EX MEM WB<br />

OR R8, R1, R9 stall IF ID EX MEM WB<br />

A sequência <strong>de</strong> etapas <strong>de</strong> processamento da tabela inferior mostra como o<br />

protelamento resolve o problema <strong>de</strong> ter os dados correctos em R1.<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 28/33<br />

28.1. Notar que o processamento <strong>de</strong> todas as <strong>instruções</strong> subsequentes à que<br />

provoca o conflito também são proteladas.<br />

28.2. A obtenção <strong>de</strong> <strong>instruções</strong> (etapa IF) também é protelada.<br />

28


Conflitos <strong>de</strong> controlo<br />

Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> controlo<br />

Saltos condicionais causam conflitos <strong>de</strong> controlo porque po<strong>de</strong>m alterar ou<br />

não o PC (quando o fazem é no fim <strong>de</strong> ID).<br />

O que fazer enquanto não é possível <strong>de</strong>terminar se o salto é realmente<br />

feito (ou tomado) ? Nada. . . e repetir quando já existir a informação.<br />

Ciclo <strong>de</strong> processador<br />

Instrução 1 2 3 4 5 6 7 8 9<br />

salto relativo IF ID EX MEM WB<br />

sucessor IF IF ID EX MEM WB<br />

sucessor + 1 IF ID EX MEM WB<br />

sucessor + 2 IF ID EX MEM WB<br />

Dada a frequência <strong>de</strong> saltos relativos, estes conflitos po<strong>de</strong>m levar a perdas<br />

<strong>de</strong> <strong>de</strong>sempenho na or<strong>de</strong>m dos 10%–30% !<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 29/33<br />

29.1. Nesta arquitectura um salto condicional <strong>de</strong>mora tanto como um salto<br />

incondicional. Em ambos os caso, o PC tem o novo valor do en<strong>de</strong>reço no fim<br />

da etapa ID.<br />

29.2. Em muitas organizações <strong>de</strong> pipeline, o salto condicional necessita <strong>de</strong> mais<br />

ciclos que o incondicional.<br />

29.3. A instrução “sucessor” não po<strong>de</strong> entrar imediatamente na fase <strong>de</strong><br />

<strong>de</strong>scodificação. O primeiro IF (da 2 a linha) obtém a instrução do valor<br />

“regular” do PC (a instrução resi<strong>de</strong>nte em memória a seguir ao salto<br />

relativo). Este valor po<strong>de</strong> não ser o correcto. O segundo IF já usa o valor <strong>de</strong><br />

PC <strong>de</strong>finido no ciclo 2 (o valor correcto).<br />

29.4. Quando o salto não é tomado, o segundo IF é <strong>de</strong>snecessário. Esse facto po<strong>de</strong><br />

ser aproveitado para reduzir o impacto do conflito <strong>de</strong> controlo.<br />

29


Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> controlo<br />

Alternativa: Optar por uma das alternativas<br />

O CPU assume que o salto não é tomado e corrige a sua <strong>de</strong>cisão quando<br />

<strong>de</strong>terminar o valor da condição (se necessário).<br />

Ciclo <strong>de</strong> processador<br />

Instrução 1 2 3 4 5 6 7 8 9<br />

salto não tomado IF ID EX MEM WB<br />

i + 1 IF ID EX MEM WB<br />

i + 2 IF ID EX MEM WB<br />

i + 3 IF ID EX MEM WB<br />

i + 4 IF ID EX MEM WB<br />

salto tomado IF ID EX MEM WB<br />

i + 1 IF inact. inact. inact. inact.<br />

alvo IF ID EX MEM WB<br />

alvo + 1 IF ID EX MEM WB<br />

alvo + 2 IF ID EX MEM WB<br />

Também se po<strong>de</strong> partir do princípio que o salto é tomado. No caso<br />

presente, isso não tem interesse. (Porquê?)<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 30/33<br />

30.1. Assumir que o salto é tomado obriga ainda assim a calcular a posição da<br />

instrução seguinte (“alvo” do salto).<br />

30.2. Quando o salto é tomado, a instrução subsequente em processamento é<br />

errada: internamente é transformado numa instrução NOP (no operation).<br />

No nosso caso, isso é simples, porque a instrução ainda não alterou o estado<br />

interno do CPU.<br />

30


Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> controlo<br />

<strong>Execução</strong> incondicional da instrução seguinte<br />

Outra opção: Executar sempre a instrução colocada a seguir ao salto!<br />

Ciclo <strong>de</strong> processador<br />

Instrução 1 2 3 4 5 6 7 8 9<br />

salto não tomado IF ID EX MEM WB<br />

(<strong>de</strong>lay slot) i + 1 IF ID EX MEM WB<br />

i + 2 IF ID EX MEM WB<br />

i + 3 IF ID EX MEM WB<br />

i + 4 IF ID EX MEM WB<br />

salto tomado IF ID EX MEM WB<br />

(<strong>de</strong>lay slot) i + 1 IF ID EX MEM WB<br />

alvo IF ID EX MEM WB<br />

alvo + 1 IF ID EX MEM WB<br />

alvo + 2 IF ID EX MEM WB<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 31/33<br />

31.1. A este tipo <strong>de</strong> salto chama-se <strong>de</strong>layed btanch e a posição da instrução<br />

executada incondicionalmente <strong>de</strong>signa-se por <strong>de</strong>lay slot. Algumas<br />

arquitecturas têm dois <strong>de</strong>lay slots.<br />

31.2. Neste caso, o trabalho <strong>de</strong> encontrar uma instrução para o <strong>de</strong>lay slot é<br />

<strong>de</strong>ixado ao compilador ou programador em assembly.<br />

31.3. Caso não seja possível encontrar uma instrução apropriada, coloca-se uma<br />

instrução NOP no <strong>de</strong>lay slot.<br />

31


Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> controlo<br />

Branch <strong>de</strong>lay slot: estratégias <strong>de</strong> sequenciamento<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 32/33<br />

32.1. A situação (a) é a melhor. As estratégias (b) e (c) são usadas quando a<br />

estratégia (a) não é possível.<br />

32.2. A estratégia (b) requer geralmente a duplicação da instrução colocada no<br />

<strong>de</strong>lay slot. Esta estratégia é boa para casos em que o salto é tomado com<br />

elevada probabilida<strong>de</strong> (como no caso dos ciclos).<br />

32.3. Para que (b) e (c) sejam legais, é necessário que a execução da instrução não<br />

altere o resultado do programa. Quando muito, o trabalho executado por<br />

essa instrução é <strong>de</strong>sperdiçado.<br />

32.4. No caso do exemplo (c), o registo R7 po<strong>de</strong>ria conter um valor temporário<br />

que simplesmente não é usado quando o salto é tomado. Note-se que o caso<br />

(b) o valor final <strong>de</strong> R4 não é o mesmo; se isso for importante, a duplicação<br />

da instrução não po<strong>de</strong> ser feita.<br />

32


Resolução <strong>de</strong> conflitos Conflitos <strong>de</strong> controlo<br />

Impacto da arquitectura do conjunto <strong>de</strong> <strong>instruções</strong><br />

A arquitectura do conjunto <strong>de</strong> <strong>instruções</strong> po<strong>de</strong> introduzir factores <strong>de</strong><br />

ineficiência e dificulda<strong>de</strong>s <strong>de</strong> implementação.<br />

Instruções que que alteram o estado a “meio” da execução dificultam<br />

o tratamento <strong>de</strong> excepções. Exemplos: auto-incremento em IA-32. O<br />

processador necessita <strong>de</strong> ter a capacida<strong>de</strong> para reverter o estado.<br />

Instruções <strong>de</strong> cópia <strong>de</strong> strings também pertencem a esta categoria<br />

(solução: usar registos como memória <strong>de</strong> trabalho).<br />

Alguns elementos <strong>de</strong> estado (p. ex. códigos <strong>de</strong> condição) po<strong>de</strong>m<br />

dificultar o funcionamento da pipeline (p. ex. <strong>instruções</strong> que alterem<br />

os c.c. não po<strong>de</strong>m ser colocadas no <strong>de</strong>lay slot). Po<strong>de</strong> ser difícil<br />

<strong>de</strong>terminar quando é que o código <strong>de</strong> condição é válido.<br />

Instruções multi-ciclo introduzem gran<strong>de</strong>s <strong>de</strong>sequilíbrios (<strong>instruções</strong><br />

po<strong>de</strong>m <strong>de</strong>morar <strong>de</strong> 1 a >100 ciclos). Solução: pipeline <strong>de</strong><br />

microcódigo (VAX8800, IA-32 <strong>de</strong>pois <strong>de</strong> 1995).<br />

Notas:<br />

c○JCF, 2004 — AAC (FEUP/LEIC) <strong>Execução</strong> <strong>concorrente</strong> <strong>de</strong> <strong>instruções</strong>: <strong>Pipelines</strong> 33/33<br />

33.1. Na arquitectura IA-32, a utilização modos <strong>de</strong> en<strong>de</strong>reçamento com<br />

auto-incremento implica a actualização <strong>de</strong> registos a meio da execução do<br />

programa.<br />

33.2. Durante muito tempo, partiu-se do princípio que a interacção entre a<br />

arquitectura do conjunto <strong>de</strong> <strong>instruções</strong> e a implementação era reduzida, pelo<br />

que s questões <strong>de</strong> implementação não tinham peso na concepção dos<br />

conjuntos <strong>de</strong> <strong>instruções</strong>. A partir dos anos 80 tornou-se claro que a<br />

dificulda<strong>de</strong> <strong>de</strong> implementar pipelines e a sua ineficiência po<strong>de</strong>m ser<br />

aumentadas por más escolhas a nível da ACI.<br />

33

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!