Como o Cache de Memória Funciona
Por Gabriel Torres e Cássio Lima em 20 de setembro de 2007

Introdução

Cache de memória é uma memória de alto desempenho localizada dentro do processador e que serve para aumentar a velocidade no acesso aos dados e instruções armazenados na memória RAM. Neste tutorial explicaremos como este circuito funciona em uma linguagem simples e objetiva.

Um computador é completamente inútil se você não diz ao processador o que ele precisa fazer. Isto é feito através de um programa, que é um conjunto de instruções que dizem ao processador o que deve ser feito.

O processador busca os programas na memória RAM. O problema é que quando a alimentação do computador é cortada, o conteúdo da memória RAM é perdido. Por isso que classificamos as memórias RAM como voláteis. Por essa razão, programas e dados devem ser armazenados em uma mídia não volátil (ou seja, onde o conteúdo não seja perdido após desligarmos o computador) caso você queira tê-los de volta após ter desligado o computador. As mídias de armazenamento não voláteis mais conhecidas são os discos rígidos e as mídias ópticas (CDs e DVDs).

Quando você clica duas vezes sobre o ícone de um programa no Windows, o programa, que está normalmente armazenado no disco rígido da máquina, é carregado para a memória RAM. Em seguida, o processador carrega o programa a partir da memória RAM através de um circuito chamado controlador de memória, que está localizado dentro do chipset (chip ponte norte), no caso dos processadores da Intel, ou dentro do próprio processador, no caso dos processadores da AMD. Na Figura 1 nós resumimos esta idéia (para os processadores da AMD ignore o desenho do chipset).


clique para ampliar
Figura 1: Como os dados armazenados são transferidos para o processador.

O processador não pode buscar dados diretamente do disco rígido porque os discos são muito lentos, mesmo se você considerar o disco rígido mais rápido disponível no mercado. Só para você ter uma idéia do que estamos falando, um disco rígido SATA-300 – o tipo mais rápido encontrado no mercado hoje para o usuário comum – tem uma taxa de transferência máxima teórica de 300 MB/s. Um processador trabalhando internamente a 2 GHz com caminhos de dados* internos de 64 bits consegue transferir dados internamente a 16 GB/s – ou seja, 50 vezes mais rápido.

* Traduzindo: são os caminhos entre os circuitos internos do processador. Esta é uma conta grosseira e serve apenas para te dar uma idéia, já que os processadores têm internamente vários caminhos de dados diferentes, cada um transferindo um número diferente de bits por vez. Por exemplo, nos processadores da AMD o caminho de dados entre o cache de memória L2 e o cache de memória L1 é de 128 bits, enquanto que nos atuais processadores da Intel este caminho de dados é de 256 bits. Se você está confuso, não se preocupe. Isto é só para explicar que o número mostrado no parágrafo acima não é fixo, mas o processador é sempre muito mais rápido do que os discos rígidos.

A diferença de desempenho vem do fato de que os discos rígidos são dispositivos mecânicos, que são muito mais lentos do que os dispositivos puramente eletrônicos, já que as partes mecânicas precisam ser movidas para buscar um dado (o que é muito mais lento do que mover elétrons). A memória RAM, por outro lado, é 100% eletrônica e por esse motivo ela é muito mais rápida do que os discos rígidos, e idealmente tão rápida quanto o processador.

E aqui está o problema. Mesmo a memória RAM mais rápida disponível não consegue acompanhar o processador. Se você tomar como exemplo as memórias DDR2-800, elas transferem dados a 6.400 MB/s – 12.800 MB/s no modo de dois canais. Apesar deste número se aproximar dos 16 GB/s do exemplo acima, como os processadores modernos são capazes de buscar dados do cache de memória L2 a uma taxa de 128 ou 256 bits, nós estamos falando de uma taxa de transferência de 32 GB/s ou 64 GB/s, isso se o processador trabalhar internamente a 2 GHz. Não se preocupe com o tal do “cache de memória L2” por enquanto, nós explicaremos sobre ele mais adiante. Tudo o que queremos agora é que você consiga visualizar que a memória RAM é mais lenta do que o processador.

A propósito, a taxa de transferência é calculada usando a seguinte fórmula (em todos os exemplos dados até o momento “dados por clock” era igual a “1”):

Taxa de transferência = largura (número de bits) x clock x dados por clock / 8

O problema não é apenas a taxa de transferência, ou seja, a velocidade da transferência, mas também a latência. A latência (também conhecida como tempo de acesso) é a quantidade de tempo que a memória demora em entregar um dado solicitado pelo o processador – esta entrega não é instantânea. Quando o processador solicita uma instrução (ou dado) que está armazenado em um determinado endereço, a memória demora um certo tempo para entregar esta instrução (ou dado) de volta ao processador. Nas memórias atuais, caso elas sejam rotuladas como CL de 5 (CL significa CAS Latency ou latência do CAS, que é a latência que estamos falando), isto significa que a memória entregará os dados solicitados apenas após cinco pulsos de clock – o que significa que o processador terá de esperar.

Esperas reduzem o desempenho do processador. Se o processador tiver de esperar cinco pulsos de clock para receber a instrução ou dado solicitado da memória, seu desempenho será de apenas 1/5 do desempenho que ele teria caso estivesse usando uma memória capaz de fornecer dados imediatamente. Em outras palavras, quando o processador acessa uma memória DDR2-800 com CL5, o seu desempenho é o mesmo que se ele estivesse acessando uma memória trabalhando a 160 MHz (800 MHz / 5). No mundo real o desempenho das memórias não é tão ruim assim pois elas trabalham em um modo chamado burst (rajada), onde a partir do segundo dado em diante as entregas passam a ser imediatas, desde que os dados estejam armazenados em endereços contíguos (normalmente as instruções de um programa são armazenadas em endereços seqüenciais). Isto é expresso como “x-1-1-1” (por exemplo, “5-1-1-1” para a memória do nosso exemplo), significando que o primeiro dado é entregue após cinco pulsos de clock mas do segundo em diante os dados podem ser entregues em apenas um pulso de clock – desde que os dados estejam armazenados em endereços contíguos, como dissemos.

RAM Dinâmica vs. RAM Estática

Existem dois tipos de memória RAM: dinâmica (DRAM) e estática (SRAM). A memória RAM usada no micro é dinâmica. Neste tipo de memória cada bit de dados é armazenado dentro do chip de memória em um pequeno capacitor. Capacitores são componentes muito pequenos, o que significa que milhões deles podem ser fabricados em uma pequena área – isto é chamado de “alta densidade”. Por outro lado, os capacitores perdem suas cargas elétricas depois de um determinado tempo e por isso as memórias dinâmicas precisam ser recarregadas, processo esse conhecido como refresh, que deve ser feito periodicamente. Durante os períodos de recarga os dados não podem ser lidos os escritos. A memória dinâmica também é muito mais barata do que a memória estática e consome muito menos. Mas, como vimos, os dados na memória RAM dinâmica não estão disponíveis imediatamente e ela não trabalha na mesma velocidade do processador.

A memória estática, por outro lado, pode trabalhar na mesma velocidade do processador, porque cada bit de dado é armazenado em um circuito chamado flip-flop, que também pode fornecer dados com latência zero ou com uma latência muito pequena, porque os flip-flops não necessitam de períodos de refresh. O problema é que os flip-flops necessitam de vários transistores para serem construídos, ou seja, eles são muito maiores do que um único capacitor. Isto significa que na mesma área onde em uma memória estática existe apenas um flip-flop, na memória dinâmica existem centenas de capacitores. Por essa razão as memórias estáticas oferecem uma menor densidade – isto é, os chips têm capacidades menores. Os outros dois problemas com a memória estática são que ela é mais cara e consome mais energia – e consequentemente esquenta mais.

Na tabela abaixo nós resumimos as principais diferenças entre a RAM dinâmica (DRAM) e a RAM estática (SRAM).

Característica

RAM Dinâmica (DRAM)

RAM Estática (SRAM)

Circuito de armazenamento

Capacitor

Flip-flop

Taxa de transferência

Menor do que a do processador

A mesma do processador

Latência

Alta

Baixa

Densidade

Alta

Baixa

Consumo de energia

Baixo

Alto

Custo

Baixo

Alto

Apesar de a RAM estática ser mais rápida do que a RAM dinâmica, suas desvantagens impedem que elas sejam usadas como memória RAM principal da máquina.

A solução encontrada para diminuir o impacto de se usar uma memória RAM mais lenta do que o processador foi usar uma pequena quantidade de memória estática entre o processador e a memória RAM. Esta técnica é chamada cache de memória, e atualmente esta pequena quantidade de memória está localizada dentro do processador.

O cache de memória copia os dados acessados recentemente da memória RAM para a memória estática e tenta adivinhar qual dado o processador poderá precisar, carregando-o para a memória estática antes que o processador precise dele. O objetivo é fazer com que o processador acesse o cache de memória em vez de acessar a memória RAM diretamente, já que ele pega dados do cache de memória imediatamente ou com uma latência muito pequena, enquanto que ele tem que esperar quando acessa dados localizados na memória RAM. Quanto mais o processador acessar o cache de memória em vez da memória RAM, mais rápido o micro será. Nós explicaremos exatamente como o cache de memória funciona mais adiante.

A propósito, aqui estamos usando os termos “dados” e “instruções” como sinônimos, já que o que está armazenado em cada endereço de memória não faz qualquer diferença para a memória.

História do Cache de Memória nos PCs

Esta seção é apenas para aqueles interessados nos aspectos históricos do cache de memória. Se você não se interessa por esse assunto sinta-se à vontade para pular para a próxima página.

O cache de memória foi usado pela primeira vez em PCs na época do 386 DX. Apesar deste processador não ter um cache de memória embutido, seu circuito de apoio – ou seja, o chipset – tinha um controlador de memória cache. Portanto, o cache de memória nessa época era externo ao processador e era opcional, ou seja, o fabricante da placa-mãe poderia ou não incluir o cache de memória em suas placas. Se você tivesse uma placa-mãe sem cache de memória seu micro seria muito mais lento do que um que tivesse esse circuito. A quantidade de memória cache disponível também variava dependendo do modelo da placa-mãe e os valores típicos para essa época eram de 64 KB e 128 KB. Nessa época o controlador de memória cache usava uma arquitetura chamada “write-through” (escrita direta), onde para as operações de escrita – ou seja, quando o processador precisa armazenar dados na memória – o controlador de cache de memória atualizava a memória RAM imediatamente.

Com o processador 486 DX a Intel incluiu uma pequena quantidade (8 KB) de memória cache dentro do processador. Este cache de memória interno foi chamado L1 (nível 1) ou “interno”, enquanto que o cache de memória externo era chamado L2 (nível 2) ou “externo”. A quantidade e a existência do cache de memória externo dependia do modelo da placa-mãe. As quantidades típicas para a época eram de 128 KB e 256 KB. Os últimos modelos do 486 passaram a usar a arquitetura do cache chamada “write back” (contra-escrita), que é usada até os dias atuais, onde para as operações de escrita a memória RAM não é atualizada imediatamente, o processador armazena os dados no cache de memória e o controlador de memória atualiza a memória RAM apenas quando ocorrer um erro do cache (quando o processador precisa de um determinado dado e ele não está no cache de memória e o processador precisa buscá-lo na lenta memória RAM dizemos que houve um erro do cache).

Com o primeiro processador Pentium a Intel criou dois circuitos de memória cache  separados dentro do processador: um para instruções e outro para dados (na época cada um tinha 8 KB). Esta arquitetura ainda é usada até hoje, e por isso que vemos o cache de memória L1 ser referenciado como 64 KB + 64 KB, por exemplo – isto porque existe um cache L1 de 64 KB para instruções e outro cache L1 de 64 KB para dados. Claro que explicaremos mais adiante qual é a diferença entre os dois. Na época o cache de memória L2 continuava localizado na placa-mãe e sua quantidade dependia do modelo da placa-mãe. Claro que ter um micro sem cache de memória era algo insano. Valores típicos para a época eram 256 KB e 512 KB.

No lado da AMD, os processadores K5, K6 e K6-2 usavam esta mesma arquitetura, com o K6-III tendo um terceiro cache de memória (L3, nível 3).

O problema com o cache de memória L2 sendo acessado externamente é que ele era acessado a um clock menor do que o processador, pois a partir do processador 486DX2 os processadores passaram a usar um clock interno diferente do seu clock externo. Por exemplo, enquanto um Pentium-200 funcionava internamente a 200 MHz, ele acessava seu cache de memória L2 a 66 MHz.

Com a introdução da arquitetura P6 da Intel o cache de memória foi movido da placa-mãe para dentro do processador – o que permitiu ao processador acessá-lo com seu clock interno –, exceto no Pentium II, onde o cache de memória não estava localizado dentro do processador, mas na mesma placa de circuito impresso onde o processador estava soldado (esta placa de circuito impresso estava localizada dentro de um cartucho), trabalhando com a metade do clock interno do processador, e no Celeron-266 e Celeron-300, que não tinham cache de memória (e por isso estes são os processadores com o pior desempenho na história dos PCs).

Esta mesma arquitetura é usada até hoje: tanto o cache de memória L1 quanto o cache de memória L2 estão localizados dentro do processador sendo acessados com o clock interno do processador. Dessa forma, quantidade de memória cache que você pode ter em seu micro dependerá do modelo do seu processador; não existe uma maneira de aumentar a quantidade de memória cache sem trocar o processador.

O Cache de Memória

Na Figura 2 você pode ver um diagrama em blocos básico de um processador de núcleo único. É claro que o diagrama em blocos varia dependendo do processador e você pode ler nossos tutoriais para cada linha de processadores para dar uma olhada em seus diagramas em blocos (Por Dentro da Arquitetura do Pentium 4, Por Dentro da Microarquitetura Core e Por Dentro da Arquitetura AMD64).


clique para ampliar
Figura 2: Diagrama em bloco básico de um processador.

A linha pontilhada na Figura 2 representa o corpo do processador, já que a memória RAM está localizada fora do processador. O caminho de dados entre a memória RAM e processador tem geralmente largura de 64 bits (ou de 128 bits, quando a configuração de dois canais – “dual channel” – é usada), rodando ao clock da memória ou ao clock externo do processador (ou clock do barramento da memória, no caso dos processadores da AMD), o que for mais baixo. Nós já mostramos como calcular a taxa de transferência da memória na primeira página deste tutorial.

Todos os circuitos dentro da caixa pontilhada rodam no clock interno do processador. Dependendo do processador, algumas de suas partes internas podem até mesmo rodar a uma taxa de clock mais alta. Além disso, o caminho de dados entre as unidades do processador pode ser mais largo, isto é, transferir mais bits por pulso de clock do que 64 ou 128. Por exemplo, o caminho de dados entre a memória cache L2 e o cache L1 de instruções em processadores modernos tem normalmente largura de 256 bits. Quanto maior o número de bits transferidos por pulso de clock, mais rápida a transferência será feita (em outras palavras, a taxa de transferência será mais alta).

Em resumo, todos os processadores modernos têm três caches de memória: o L2, que é o maior e pode ser encontrado entre a memória RAM e o cache L1 de instruções, que armazena tanto dados quanto instruções; o cache L1 de instruções, que é usado para armazenar instruções que serão executadas pelo o processador; e o cache L1 de dados, que é usado para armazenar dados que serão escritos de volta na memória.

L1 e L2 significam “nível 1” (Level 1) e “nível 2” (“Level 2”), respectivamente, e referem-se à distância em que se encontram do núcleo do processador (unidade de execução). Uma dúvida comum é porque ter três memórias cache distintas (cache L1 de dados, cache L1 de instruções e L2).

Fazer com que a latência das memórias estáticas seja igual a zero é um enorme desafio, especialmente com os processadores trabalhando com clocks muito altos. Como fabricar memórias estáticas com latência igual a zero é muito difícil, o fabricante usa este tipo de memória apenas no cache de memória L1. O cache de memória L2 usa uma RAM estática que não é tão rápida quanto à usada no cache L1, já que ela tem alguma latência, o que faz com que o seu acesso seja um pouco mais lento do que o acesso ao do cache de memória L1.

Preste atenção na Figura 2 e você verá que o cache L1 de instruções funciona como um cache de entrada, enquanto que o cache L1 de dados funciona como um cache de saída. O cache L1 de instruções – que é normalmente menor do que o cache L2 – é particularmente eficiente quando o programa iniciar um laço de repetição (loop), já que as instruções necessárias já estarão próximas da unidade de busca.

Isto é raramente mencionado, mas o cache L1 de instruções é também usado para armazenar outros dados além das instruções a serem decodificadas. Dependendo do processador ele pode ser ainda usado para armazenar alguns dados de pré-decodificação e informações de desvio (em resumo, dados de controle que aumentarão a velocidade do processo de decodificação) e às vezes o cache L1 de instruções é maior do que o anunciado, pois o fabricante não adiciona o espaço extra disponível para o armazenamento dessas informações adicionais.

Na página de especificações de um processador o cache L1 pode ser encontrado com diferentes tipos de representação. Alguns fabricantes listam as memórias cache L1 separadamente (algumas vezes chamando o cache de instrução de “I” e o cache de dados de “D”), alguns acrescentam a soma dos dois e escrevem “separados” – logo “128 KB, separados” significa cache de instruções de 64 KB e cache de dados de 64 KB –, e alguns simplesmente somam os dois e você tem que adivinhar que o número é o total e que você deve dividi-lo por dois para saber a capacidade de cada cache. A exceção, entretanto, fica por conta dos processadores baseados na microarquitetura Netburst, como os processadores Pentium 4, Pentium D e o Xeon e o Celeron baseados no Pentium 4.

Os processadores baseados na microarquitetura NetBurst não possuem cache L1 de instruções. Em vez disto eles possuem um cache de rastreamento de execução, que é um cache localizado entre a unidade de decodificação e a unidade de execução. Portanto, o cache L1 de instruções está lá, mas com nome e lugar diferentes. Estamos falando isso porque esse é um erro muito comum, pensar que processadores Pentium 4 não possuem cache L1 de instruções. Quando comparam o Pentium 4 com outros processadores, algumas pessoas acham que seu cache L1 é muito menor, porque estão contando apenas o cache de dados L1 de 8 KB. O cache de rastreamento de execução dos processadores baseados na microarquitetura NeBurst é de 150 KB e deve ser levado em conta, é claro.

Cache de Memória L2 nos Processadores Multi-Núcleos

Nos processadores com mais de um núcleo a arquitetura do cache L2 varia muito, dependendo do processador.

Nos processadores Pentium D e nos processadores AMD de dois núcleos baseados na arquitetura K8, cada núcleo do processador tem seu próprio cache de memória L2. Portanto cada núcleo trabalha como se fosse um processador independente.

Nos processadores de dois núcleos baseados nas microarquiteturas Core e Pentium M, existe apenas o cache de memória L2, que é compartilhado entre os dois núcleos.

A Intel afirma que a arquitetura compartilhada é melhor, pois na abordagem com cache separado em um dado momento um núcleo pode estar com o seu cache “cheio” enquanto que o outro núcleo pode ter partes não usadas do seu cache L2. Quando isso acontece, o primeiro núcleo precisa buscar dados na memória RAM, apesar de haver espaço vazio no cache de memória L2 do segundo núcleo que poderia ser usado para armazenar dados e evitar que o primeiro núcleo acesse a memória RAM. Portanto, em um processador Core 2 Duo com 4 MB de cache de memória L2, um núcleo pode estar usando 3,5 MB enquanto que o outro pode estar usando 512 KB (0,5 MB), ao contrário da divisão fixa de 50%-50% usada em outros processadores de dois núcleos.

Por outro lado, os atuais processadores de quatro núcleos da Intel, como o Core 2 Extreme QX e o Core 2 Quad, usam dois chips de dois núcleos, o que significa que este compartilhamento ocorre apenas entre os núcleos 1-2 e 3-4. No futuro a Intel planeja lançar processadores de quatro núcleos usando um único chip. Quanto isso acontecer o cache L2 será compartilhado entre os quatro núcleos.

Na Figura 3 você pode ver uma comparação entre essas três soluções de cache de memória L2.


clique para ampliar
Figura 3: Comparação entre as atuais soluções de cache de memória L2 presentes nos processadores de núcleos múltiplos.

Processadores da AMD baseados na arquitetura K10 terão um cache de memória L3 compartilhado dentro do processador. Isto é mostrado na Figura 4. O tamanho desse cache dependerá do modelo do processador, da mesma forma que acontece com o tamanho do cache L2.


clique para ampliar
Figura 4: Arquitetura K10.

Como o Cache de Memória Funciona

O cache de memória funciona da seguinte forma. A unidade de busca do processador procura pela a próxima instrução a ser executada no cache L1 de instruções. Se ela não estiver lá, o processador procurará por ela no cache L2. Por fim, se a instrução não estiver no cache L2, o processador terá que buscá-la na memória RAM.

Chamamos de “acerto” (“hit”) quando o processador carrega uma informação requisitada do cache, e de “erro” (“miss”) quando a informação requisitada pelo processador não está no cache de memória e ele precisa acessar a memória RAM do micro.

Claro que quando você liga o micro os caches estão vazios, assim o processar tem de acessar a memória RAM – este é um erro do cache inevitável. Mas após a primeira instrução ter sido carregada, o show começa.

Quando o processador carrega uma instrução de uma certa posição da memória, um circuito chamado controlador de cache carrega para o cache de memória um pequeno bloco de dados abaixo da posição atual que o processador acabou de carregar. Como os programas normalmente seguem um fluxo seqüencial, a próxima posição de memória que o processador precisará provavelmente será a posição de memória imediatamente inferior a qual o processador acabou de carregar. Como o controlador de memória já carregou alguns dados abaixo da primeira posição de memória lida pelo o processador, o próximo dado provavelmente já estará dentro do cache de memória. Portanto o processador não precisará buscar o dado na memória RAM: o dado já foi carregado para o cache de memória embutido no processador e pode ser acessado com o clock interno do processador.

Esta quantidade de dados é chamada linha e é normalmente de 64 bytes (mais sobre esse assunto na próxima página).

Além de carregar esta pequena quantidade de dados, o controlador de memória está sempre tentando adivinhar qual será o próximo dado que o processador precisará. Um circuito chamado pré-busca, por exemplo, carrega mais dados localizados após esses primeiros 64 bytes da RAM dentro do cache de memória. Se o programa continuar carregar instruções e dados de posições de memória seqüenciais, as instruções e dados que o processador precisará já estarão localizadas dentro do cache de memória.

Portanto nós podemos resumir como o cache de memória funciona da seguinte forma:

  1. O processador solicita a instrução/dado armazenado no endereço “a”.
  2. Como o conteúdo do endereço “a” não está no cache de memória, o processador precisa buscá-lo diretamente da memória RAM.
  3. O controlador de cache carrega uma linha (tipicamente de 64 bytes) começando do endereço “a” para dentro do cache de memória. Isto é, mais dados do que o processador solicitou, portanto se o processador continuar executado o programa sequencialmente (isto é, solicitando o endereço a+1) a próxima instrução/dado que o processador precisará já estará localizada no cache de memória.
  4. Um circuito chamado pré-busca carrega mais dados localizados após esta linha, ou seja, carrega o conteúdo do endereço a+64 para dentro do cache. Para dar a você um exemplo real, os processadores Pentium 4 têm um circuito de pré-busca de 256 bytes, o que significa que ele carrega os próximos 256 bytes após a linha recém carregada para dentro do cache.

Se os programas sempre forem executados sequencialmente o processador nunca precisará buscar dados diretamente da memória RAM – exceto para carregar a primeira instrução – já que as instruções e dados solicitados pelo o processador já estariam dentro do cache de memória antes de o processador solicitar por eles.

Porém os programas não são executados dessa forma, de tempos em tempos eles pulam para outra posição de memória. O principal desafio do controlador de cache é tentar adivinhar para quais endereços o processador pulará, carregando o conteúdo desses endereços para o cache de memória antes que o processador os solicite, de modo a evitar que o processador acesse a memória RAM, que é lenta. Esta tarefa é chamada previsão de desvio e todos os processadores modernos têm esse recurso.

Os processadores modernos têm uma taxa de acerto de pelo menos 80%, o que significa que pelo menos em 80% do tempo o processador não acessa a memória RAM diretamente, mas sim o cache de memória.

Organização do Cache de Memória

O cache de memória é divido internamente em linhas, cada uma podendo guardar de 16 a 128 bytes, dependendo do processador. Na maioria dos processadores atuais o cache de memória está organizado em linhas de 64 bytes (512 bits), portanto consideraremos um cache de memória usando linhas de 64 bytes em nossos exemplos dados neste tutorial. Na última página apresentaremos as especificações dos caches de memória dos principais processadores encontrados no mercado atualmente.

Portanto, um cache de memória L2 de 512 KB é dividido em 8.192 linhas. Lembre-se que 1 KB é igual a 2^10 ou 1.024 bytes e não 1.000 bytes. A conta é a seguinte: 524.288 / 64 = 8.192. Nós consideraremos um processador de um único núcleo com 512 KB de memória cache L2 em nossos exemplos. Na Figura 5 ilustramos esta organização interna deste cache de memória.

Figura 5: Como um cache de memória L2 de 512 KB é organizado.

O cache de memória pode funcionar em três diferentes organizações: cache com mapeamento direto, cache completamente associativo e cache associativo por grupos (também conhecido como cache associativo por grupos de n-vias). O cache associativo por grupos é a configuração mais usada atualmente, mas vamos dar uma olhada em como essas três configurações funcionam.

Cache com Mapeamento Direto

O cache com mapeamento direto é a maneira mais simples de se criar um cache de memória. Nesta configuração a memória RAM é dividida no mesmo número de linhas que existem dentro do cache de memória. Se tivermos um micro com 1 GB de memória RAM, esse 1 GB será dividido em 8.192 blocos (assumindo que o cache de memória use a configuração que descrevemos acima), cada um com 128 KB (1.073.741.824 / 8.192 = 131.072 – lembre-se que 1 GB é igual a 2^30 bytes, 1 MB é igual a 2^20 bytes e 1 KB é igual a 2^10 bytes). Se o micro tivesse 512 MB a memória também seria dividida em 8.192 blocos, mas desta vez cada bloco teria 64 KB. E assim por diante. Nós ilustramos essa organização na Figura 6.


clique para ampliar
Figura 6: Como o cache com mapeamento direto funciona.

A principal vantagem do mapeamento direto é que essa é a configuração mais fácil de ser implementada.

Quando o processador solicita por um dado endereço da memória RAM (por exemplo, o endereço 1.000), o controlador de cache carregará uma linha (64 bytes) da memória RAM e armazenará esta linha no cache de memória (isto é, endereço 1.000 até 1.063, assumindo que estamos usando um esquema de endereçamento de 8 bits só para ajudar em nossos exemplos). Portanto se o processador solicitar novamente o conteúdo deste endereço ou de alguns endereços próximos desse (ou seja, qualquer endereço na faixa de 1.000 a 1.063) eles já estarão dentro do cache.

O problema é que se o processador precisar de dois endereços que estão mapeados na mesma linha do cache, um erro do cache acontecerá (este problema é chamado colisão ou conflito). Continuando nosso exemplo, se o processador solicitar o endereço 1.000 e então solicitar o endereço 2.000, um erro do cache acontecerá porque esses dois endereços estão dentro do mesmo bloco (os primeiros 128 KB da memória RAM), e o que estava dentro do cache era uma linha começando com o endereço 1.000. Portanto o controlador de cache carregará a linha do endereço 2.000 e armazenará ela na primeira linha do cache de memória, limpando o conteúdo antigo, em nosso caso a linha de endereço 1.000.

O problema continua. Se o processador tem de executar um laço de repetição (loop) maior do que 64 bytes, haverá um erro do cache durante o tempo de duração do loop.

Por exemplo, se o loop for do endereço 1.000 até o endereço 1.100, o processador terá de carregar todas as instruções diretamente da memória RAM enquanto o loop durar. Isto acontecerá porque o cache terá o conteúdo do endereço 1.000 até 1.063 e quando o processador solicitar o conteúdo do endereço 1.100 ele terá buscá-lo na memória RAM, e o controlador de cache carregará os endereços 1.100 até 1.163. Quando o processador solicitar o endereço 1.000 novamente ele terá que voltar na memória RAM, já que o cache não tem mais o conteúdo do endereço 1.000. Se este loop for executado 1.000 vezes, o processador terá que ir à memória RAM 1.000 vezes.

É por isso que o cache com mapeamento direto é a configuração de cache menos eficiente e não é mais usada – pelo menos nos PCs.

Cache Completamente Associativo

Na configuração completamente associativa, por outro lado, não existe uma ligação fixa entre as linhas do cache de memória e as localizações da memória RAM. O controlador de cache pode armazenar qualquer endereço. Portanto o problema descrito acima não acontece. Esta configuração é a mais eficiente (ou seja, apresenta uma maior taxa de acertos).

Por outro lado, o circuito de controle é muito mais complicado, já que precisa monitorar quais localizações estão carregadas dentro do cache de memória. É por isso que uma solução hibrida – chamada cache associativo por grupos – é mais usada atualmente.

Cache Associativo por Grupos de n-vias

Nesta configuração o cache de memória é dividido em vários blocos (grupos) contendo “n” linhas cada.

Dessa forma em um cache associativo por grupos de 4 vias o cache de memória terá 2.048 blocos contendo quatro linhas cada (8.192 linhas / 4), em cache associativo por grupos de 2 vias o cache de memória terá 4.096 blocos contendo 2 linhas cada e um cache associativo por grupos de 16 vias terá 512 blocos contendo 16 linhas cada. Aqui nós estamos continuando com o nosso exemplo de um cache L2 de 512 KB dividido em 8.192 linhas de 64 bytes. Dependendo do processador o número de blocos será diferente, é claro.

Figura 7: Cache de memória L2 de 512 KB configurado como Associativo por grupos de 4 vias.

A memória RAM é dividia no mesmo número de blocos disponível no cache de memória. Continuando o exemplo do cache de 512 KB Associativo por grupos de 4 vias, a memória RAM seria dividida em 2.048 blocos, o mesmo número de blocos disponível dentro do cache de memória. Cada bloco da memória será vinculado a um conjunto de linhas dentro do cache, da mesma forma que no cache com mapeamento direto. Com 1 GB de memória RAM, a memória seria dividida em 2.048 blocos com 512 KB cada, veja na Figura 8.


clique para ampliar
Figura 8: 512 KB de cache de memória L2 configurado como Associativo por grupos de 4 vias.

Como você ver o mapeamento é similar ao que acontece com o cache com mapeamento direto, a diferença é que para cada bloco de memória existe agora mais de uma linha disponível no cache de memória. Cada linha pode armazenar o conteúdo de qualquer endereço dentro do bloco mapeado. Em um cache Associativo por grupos de 4 vias cada grupo no cache de memória pode armazenar até quatro linhas do mesmo bloco de memória.

Com esta abordagem os problemas apresentados pelo cache com mapeamento direto são resolvidos (os problemas de colisão e de loop descritos na página anterior). Ao mesmo tempo, o cache associativo por grupo é mais fácil de ser implementado do que o cache completamente associativo, já que seu circuito lógico é mais simples. Por causa disso é que esta é atualmente a configuração de cache mais comum, apesar de oferecer um desempenho menor se comparado com o cache completamente associativo.

É claro que ainda há um número limitado de linhas disponíveis em cada grupo do cache de memória para cada bloco de memória – quatro em uma configuração de 4 vias. Após essas linhas terem sido ocupadas, o controlador de cache terá que liberar uma deles para armazenar a próxima instrução carregada do mesmo bloco de memória.

Quando nós aumentamos o número de vias de um cache associativo por grupo – por exemplo, de 4 vias para uma configuração de 8 vias –, nós temos mais linhas disponíveis em cada grupo, mas se nós mantivermos a mesma quantidade de cache de memória o tamanho de cada bloco da memória também é aumentado. Continuando com nosso exemplo, trocando a configuração de 4 vias para uma de 8 vias faria nosso 1 GB de memória RAM ser dividido em 1.024 blocos de 1 MB. Portanto este aumento na configuração aumentaria o número de linhas disponíveis em cada grupo, mas agora cada grupo estaria responsável por um bloco de memória maior.

Existe muita discussão acadêmica a respeito de qual é o equilíbrio perfeito entre o número de grupos e o tamanho do bloco da memória e não há uma resposta definitiva para essa discussão – a Intel e a AMD usam configurações diferentes, como você verá na próxima página.

Portanto o que acontece se tivermos um cache de memória maior? Ainda usando o exemplo acima, se nós aumentássemos o cache de memória L2 de 512 KB para 1 MB (a única maneira de fazer isso seria substituindo o processador), o que aconteceria é que nós teríamos 16.384 linhas de 64 bytes em nosso cache de memória, o que nos daria 4.096 grupos com quatro linhas cada. Nossa memória RAM de 1 GB seria dividida em 4.096 blocos de 256 KB. Portanto, basicamente o que acontece é que o tamanho de cada bloco da memória diminui, aumentando as chances de o dado solicitado estar dentro do cache de memória – em outras palavras, aumentando o tamanho do cache diminuimos o taxa de erro do cache.

Porém, aumentar o tamanho do cache de memória não é algo que garante um aumento de desempenho. Aumentar o tamanho do cache de memória garante que mais dados estarão no cache, mas a questão toda é se o processador está usando estes dados adicionais ou não. Por exemplo, imagine um processador com um único núcleo com 4 MB de cache L2. Se o processador está usando intensamente 1 MB do cache mas não com tanta intensidade os outros 3 MB (ou seja, as instruções mais acessadas estão no 1 MB e as instruções armazenadas nos outros 3 MB não estão sendo solicitadas tanto assim), é possível que este processador tenha um desempenho similar ao de um processador idêntico com 2 MB ou até mesmo com 1 MB de cache L2.

Configuração do Cache de Memória nos Processadores Atuais

Abaixo nós apresentamos uma tabela de referência contendo as principais especificações para os principais processadores disponíveis no mercado hoje.

Processador

Cache L1 de Instruções

Cache L1 de Dados

Cache L2

Athlon 64

  • 64 KB
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2
  • Caminho de dados de 128 bits com a unidade de busca
  • 64 KB
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2

 

  • 512 KB ou 1 MB
  • Associativo por grupos de 16 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L1 de dados
  • Caminho de dados de 128 bits com o cache L1 de instruções

Athlon 64 FX

  • 64 KB por núcleo
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2
  • Caminho de dados de 128 bits com a unidade de busca
  • 64 KB
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2

 

  • 1 MB por núcleo
  • Associativo por grupos de 16 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L1 de dados
  • Caminho de dados de 128 bits com o cache L1 de instruções

Athlon 64 X2

  • 64 KB por núcleo
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2
  • Caminho de dados de 128 bits com a unidade de busca
  • 64 KB
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2

 

  • 512 KB ou 1 MB por núcleo
  • Associativo por grupos de 16 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L1 de dados
  • Caminho de dados de 128 bits com o cache L1 de instruções

Sempron (soquetes 754 e AM2)

  • 64 KB por núcleo
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2
  • Caminho de dados de 128 bits com a unidade de busca
  • 64 KB
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2

 

  • 128 KB ou 256 KB
  • Associativo por grupos de 16 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L1 de dados
  • Caminho de dados de 128 bits com o cache L1 de instruções

Opteron

  • 64 KB por núcleo
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2
  • Caminho de dados de 128 bits com a unidade de busca
  • 64 KB por núcleo
  • Associativo por grupos de 2 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L2

 

  • 1 MB por núcleo
  • Associativo por grupos de 16 vias
  • Linhas de 64 bytes
  • Caminho de dados de 128 bits com o cache L1 de dados
  • Caminho de dados de 128 bits com o cache L1 de instruções

Pentium 4

N/D *

  • 8 KB
  • Associativo por grupos de 4 vias
  • Linhas de 64 bytes
  • Caminho de dados de 256 bits com o cache L2

 

  • 256 KB, 512 MB ou 1 MB
  • Associativo por grupos de 8 vias
  • Linhas de 128 bytes
  • Caminho de dados de 64 bits com a unidade de busca
  • Caminho de dados de 256 bits com o cache L1 de dados

Pentium D

N/D *

  • 16 KB
  • Associativo por grupos de 4 vias
  • Linhas de 64 bytes
  • Caminho de dados de 256 bits com o cache L2

 

  • 1 MB ou 2 MB por núcleo
  • Associativo por grupos de 8 vias
  • Linhas de 128 bytes
  • Caminho de dados de 64 bits com a unidade de busca
  • Caminho de dados de 256 bits com o cache L1 de dados

Core 2 Duo

  • 32 KB
  • Linha de dados de 64 bytes
  • Caminho de dados de 256 bits com a unidade de busca
  • 32 KB
  • Linha de dados de 64 bytes
  • Caminho de dados de 256 bits com o cache L2
  • 2 MB ou 4 MB
  • Associativo por grupos de 8 vias
  • Linhas de 64 bytes
  • Caminho de dados de 256 bits com o cache L1 de dados

Pentium Dual Core

  • 32 KB
  • Linha de dados de 64 bytes
  • Caminho de dados de 256 bits com a unidade de busca
  • 32 KB
  • Linha de dados de 64 bytes
  • Caminho de dados de 256 bits com o cache L2
  • 1 MB
  • Associativo por grupos de 8 vias
  • Linhas de 64 bytes
  • Caminho de dados de 256 bits com o cache L1 de dados

* Existe um cache de rastreamento de execução de 150 KB nesses processadores. Esse cache está localizado entre o decodificador de instruções e a unidade de execução. Portanto a unidade de busca pega dados diretamente do cache de memória L2.

Nós não incluímos os processadores Xeon e Celeron na tabela acima porque existem muitos modelos diferentes do Xeon e do Celeron baseados em arquiteturas diferentes. Os processadores Celeron e Xeon baseados na microarquitetura Netburst (isto é, baseado no Pentium 4) têm as mesmas especificações do Pentium 4 mas com um cache de memória L2 com tamanho diferente, enquanto que o Celeron e o Xeon baseados na microarquitetura Core (isto é, baseado no Core 2 Duo) têm as mesmas especificações do Core 2 Duo mas com um tamanho de cache L2 diferente.

Originalmente em http://www.clubedohardware.com.br/artigos/1410

© 1996-2008, Clube do Hardware. Todos os direitos reservados.

É expressamente proibida a reprodução total ou parcial do conteúdo deste site e dos textos disponíveis, seja através de mídia eletrônica, impressa, ou qualquer outra forma de distribuição. Os infratores serão indiciados e punidos com base na lei nº 9.610 de 19/02/1998.

Não nos responsabilizamos por danos materiais e/ou morais de qualquer espécie promovidos pelo uso das informações contidas no Clube do Hardware.