Modelo | Dispositivo de armazenamento de informações , componente de software , hardware de computador |
---|
Um cache ou memória cache é, na computação , uma memória que armazena temporariamente cópias de dados de uma fonte, a fim de diminuir o tempo de um acesso subsequente (em leitura) de um hardware de computador (em geral, um processador).) esses dados. O princípio do cache também pode ser usado na escrita e, portanto, existe em três modos possíveis: write-through , write-back e write-around .
A memória cache, mais rápida e próxima do equipamento informático que solicita os dados, é menor - pelo seu desempenho e, portanto, pelo seu custo - do que a memória para a qual atua como intermediária. Comercialmente, a noção de cache apareceu no mainframe IBM 360/85 em 1968.
Os mecanismos de memória cache podem ser colocados entre todos os produtores e consumidores de dados operando de forma assíncrona, por exemplo, processador e memória de acesso aleatório , rede e espaço de aplicativo, disco rígido e memória de acesso aleatório, etc.
Tecnicamente, é vantajoso gerenciar separadamente os dados não modificáveis (ilustrações de um site remoto, seção do código do programa) e aqueles que podem ser modificados (formulário, seções de dados, etc.). Por exemplo, os processadores geralmente têm caches separados para código e dados.
Sua velocidade necessária torna a memória cache cara e, por esse motivo, limitada. No caso dos microprocessadores , o tamanho e o desempenho desses caches, externos ou internos, podem influenciar muito a velocidade de processamento do programa. É possível medi-lo pela inibição total ou parcial do cache, ou alterando seu tamanho se for externo.
No caso de caches internos, o espaço usado pelos transistores de cache no wafer determina seu custo de fabricação. A memória cache é tanto mais útil quanto o algoritmo a ser executado requer acessos repetitivos a pequenas áreas da memória:
Quando o processador é capaz de prever aproximadamente suas necessidades futuras de dados, ele pode preencher o cache com antecedência, o que é chamado de pré-busca .
Memória cache é a mesma expressão usada em inglês , ou seja, memória cache , que substituiu "memória-escrava", dada pelo seu inventor Maurice Vincent Wilkes em 1965. A Academia Francesa sugere, em vez disso, o termo memória cache.
A diferença entre a memória cache e a memória buffer é que a memória cache duplica informações, enquanto o buffer pode expressar a ideia de uma sala de espera, sem necessariamente implicar em duplicação. O cache de buffer ( cache de buffer) do disco ou a cobertura do disco (cache de disco) é tanto um buffer que lida com a informação quanto uma memória cache que copia eletronicamente os dados armazenados no disco em forma magnética.
A principal diferença entre os caches de disco e de memória é que você tem muito pouco tempo no segundo caso para descobrir onde colocar o que está escondendo. Ao ocultar um disco, você pode escolher cuidadosamente onde colocar cada informação com base nas características das páginas. O cache IBM 370 , permitido apenas um ciclo menor para tomar sua decisão, usa arbitrariamente os bits menos significativos do endereço de memória como o endereço do quadro de página associado. Cabe então ao compilador evitar potenciais colisões da melhor maneira possível.
Veja Algoritmo LRU .
O cache contém uma cópia dos dados originais quando é caro (em termos de tempo de acesso) recuperar ou calcular em relação ao tempo de acesso ao cache. Depois que os dados são armazenados no cache, eles são acessados diretamente por meio do cache, em vez de recuperá-los ou recalculá-los, o que diminui o tempo médio de acesso.
O processo funciona da seguinte maneira:
Se as memórias cache permitem aumentar os desempenhos, isso se deve em parte a dois princípios que foram descobertos a partir de estudos sobre o comportamento dos programas de computador:
Em relação ao cálculo da matriz , o cache introduz, por outro lado, fortes assimetrias dependendo se a matriz é acessada por linhas ou colunas, dissimetrias tanto mais importantes quanto a matriz é grande. Um relatório CNUCE menciona uma diferença de desempenho de um fator de 8 a 10 para matrizes cuja menor dimensão é 50.
Existe uma área de cache:
Em microprocessadores, vários níveis de caches são diferenciados, geralmente três em número:
Estas últimas tampas podem ser localizadas dentro ou fora do microprocessador.
É muito rápido, mas também muito caro. Freqüentemente, isso é SRAM .
A presença de memória cache permite acelerar a execução de um programa. Portanto, quanto maior o tamanho da memória cache, maior pode ser o tamanho dos programas acelerados. No entanto, há um limite além do qual aumentar o tamanho do cache não é mais útil. De fato, nos códigos, existem conexões que não podem ser previstas pelos processadores. A cada conexão, a parte do código pode chamar uma área de memória diferente. É por isso que o “horizonte” além do qual o microprocessador não consegue ver se precisará de certos dados limita a eficácia do cache. O tamanho do cache é um elemento frequentemente usado pelos fabricantes para variar o desempenho de um produto sem alterar outro hardware. Por exemplo, para microprocessadores, existem séries restritas (com um tamanho de memória cache deliberadamente reduzido), como o Duron na AMD ou Celeron na Intel , e séries de ponta com uma grande memória cache, como os processadores Opteron na AMD ou Pentium 4EE da Intel. Em outras palavras, o tamanho da memória cache resulta de um compromisso de custo / desempenho.
Na programação, para aproveitar a aceleração fornecida por essa memória muito rápida, as partes do programa devem caber o máximo possível nessa memória cache. Como varia de acordo com os processadores, essa função de otimização costuma ser dedicada ao compilador. Dito isso, um programador experiente pode escrever seu código de uma forma que otimize o uso do cache.
Este é o caso de loops muito curtos que cabem inteiramente em caches de dados e instruções, por exemplo, o seguinte cálculo (escrito em linguagem C ):
long i; double s; s = 0.0; for (i = 1; i < 50000000; i++) s += 1.0 / i;Existem três tipos de falhas de cache em sistemas de processador único e quatro em ambientes de vários processadores. Isto é :
Como a memória cache não pode conter toda a memória principal, um método deve ser definido indicando em qual endereço da memória cache uma linha da memória principal deve ser escrita. Este método é denominado mapeamento. Existem três tipos de mapeamento que são comuns em caches hoje:
Cada linha da memória de nível superior pode ser gravada em qualquer endereço do cache. Este método requer muita lógica porque dá acesso a muitas possibilidades. Isso explica porque a associatividade total é usada apenas em caches pequenos (normalmente na ordem de alguns kibibytes ). Isso fornece o seguinte detalhamento do endereço:
Correspondência predefinida de cache ( cache mapeado diretamente )Cada linha da memória principal só pode ser gravada em um único endereço da memória cache, por exemplo associado ao módulo de seu endereço. Isso cria muitas falhas de cache se o programa acessar dados em conflito nos mesmos endereços de cache. A seleção da linha onde os dados serão gravados geralmente é obtida por: Linha = endereço do Mod Número de linhas .
Uma linha de cache é compartilhada por muitos endereços na memória de nível superior. Portanto, precisamos saber quais dados estão atualmente no cache. Essas informações são fornecidas pela tag , que são informações adicionais armazenadas no cache. O índice corresponde à linha onde os dados são registrados. Além disso, o controlador de cache precisa saber se um determinado endereço contém dados ou não. Um bit adicional (denominado bit de validade) é carregado com essas informações.
Por exemplo, considere um endereço de 32 bits fornecendo acesso à memória endereçável por byte, um tamanho de linha de 256 bits e um cache de kibibyte de 2 s . A memória cache, portanto, contém 2 s + 13 bits (1 kiB = 2 10 bytes e 1 byte = 2 3 bits). Sabendo que uma linha tem 256 bits ou 2 8 bits, deduzimos que há 2 s + 5 linhas armazenáveis na memória cache. Portanto, o índice é s + 5 bits.
O endereço de 32 bits permite o acesso a uma memória de 232 bytes ou 235 bits. Sendo o índice de s + 5 bits, é necessário distinguir 2 elementos de 22 s da memória principal por linha de cache. O tag é, portanto, bits de 22 s.
Além disso, uma linha tem um tamanho de 256 bits ou 32 bytes. Sendo a memória endereçável por byte, isso implica um deslocamento de 5 bits. O deslocamento é o deslocamento dentro de uma linha para acessar um byte específico. Esses cálculos fornecem a seguinte divisão de endereço para um cache mapeado diretamente:
O mapeamento direto é uma estratégia simples, mas ineficiente, porque cria muitas falhas de cache conflitantes. Uma solução é permitir que um endereço de memória principal seja armazenado em um número limitado de endereços de memória cache. Esta solução é apresentada na próxima seção.
Cache associativo de conjunto N-wayÉ um meio-termo entre o "mapeamento" direto e completamente associativo, tentando combinar a simplicidade de um e a eficácia do outro.
O cache é dividido em conjuntos ( conjuntos ) de N linhas de cache. Um conjunto é representado na figura anexa pela união dos retângulos vermelhos. Uma linha da memória de nível superior é atribuída a um conjunto e, conseqüentemente, pode ser escrita em qualquer um dos canais, ou seja, das N linhas do conjunto. Isso evita muitas falhas de cache conflitantes. Dentro de um conjunto, o mapeamento é Direct Mapped, enquanto o mapeamento de N Sets é Full Associative. Em geral, a seleção do conjunto é realizada por: Set = Mod endereço de memória ( Número de conjuntos ).
Vamos pegar o exemplo da seção anterior (memória cache kibibyte ), mas composto de canais. O número de canais é de fato sempre uma potência de 2 para obter uma divisão simples do endereço de memória. A memória cache, portanto, contém bits por canal. Sabendo que uma linha representa 256 bits, existem, portanto, entradas por conjunto. O índice é, portanto, s-n + 5 bits.
As memórias consideradas aqui são endereçáveis por byte. Portanto, os endereços de 32 bits fornecem acesso à memória de bits, que é o equivalente a linhas de memória cache. Portanto, cada conjunto do cache contém linhas separadas. A tag é, portanto, 22-s + n bits. A divisão do endereço é então:
Para funcionar, um processador precisa de dados e instruções. Existem, portanto, duas soluções para a implementação de memórias cache:
A separação de dados e instruções permite, em particular, aumentar a frequência de operação do processador, que pode assim acessar simultaneamente um dado e uma instrução. Esta situação é particularmente comum para Carregar / Armazenar. Isso explica por que o cache unificado costuma ser o elo mais fraco do sistema. Além disso, em um cache unificado, uma lógica adicional que prioriza dados ou instruções deve ser introduzida, o que não é o caso com caches separados.
Onde sabemos que as instruções não podem ser modificadas pelo programa (o que é parte das boas práticas), poderíamos, em teoria, dispensar a parte suja . No entanto, os programas que exigem alto desempenho (drivers de dispositivo rápidos, por exemplo) às vezes tomam liberdades a esse respeito, o que requer cautela. No máximo, sabemos que as instruções - ao contrário dos dados - raramente ou muito raramente serão modificadas, e podemos otimizar os circuitos de acordo.
Se as mudanças instruções pelo programa, caches separados introduzir um problema de consistência de cache de instruções: o programa deve invalidar-se as entradas correspondentes no cache de instruções para levá-los a atualizar para a frente para executar as instruções modificadas, caso contrário, uma versão anterior dessas instruções pode ser captado e executado pelo processador (ou alguma mistura imprevisível de instruções novas e antigas).
Em 2011, a solução mais comum é a separação de caches, pois permite, entre outras coisas, aplicar otimizações específicas a cada cache de acordo com o seu tipo de acesso.
Quando uma parte dos dados está no cache, o sistema tem duas cópias: uma na memória de nível superior (digamos, memória principal) e uma na memória cache. Quando os dados são modificados localmente, existem várias políticas de atualização:
Write Through ( write-through ) os dados são gravados no cache e na memória principal. A memória principal e o cache têm o mesmo valor em todos os momentos, simplificando muitos protocolos de consistência; Writeback ( write-back ) a informação só é gravada na memória principal quando a linha desaparece do cache (invalidada por outros processadores, despejada para gravar outra linha ...). Essa técnica é a mais difundida porque permite evitar muitas gravações desnecessárias na memória. Para não ter que escrever informações que não foram modificadas (e assim evitar bagunçar desnecessariamente o barramento), cada linha da memória cache é fornecida com um bit indicando a modificação (bit sujo ). Quando a linha é modificada no cache, este bit é colocado em 1, indicando que os dados terão que ser regravados na memória principal. O write-back requer, naturalmente, precauções especiais quando usado para mídia removível ("Remova o volume com segurança" com a limpeza do cache).Algoritmo de escrita
Algoritmo de write-back
Os caches associativos e totalmente associativos de canal N envolvem o mapeamento de diferentes linhas de memória de nível superior para o mesmo conjunto. Portanto, quando o conjunto de linhas do cache, onde uma linha de memória superior pode ser mapeada, for preenchido, designe a linha que será excluída em favor da linha recém-escrita. O objetivo do algoritmo de substituição de linha de cache é escolher essa linha de maneira ideal. Esses algoritmos devem ser implementados em hardware para caches de baixo nível, a fim de ser o mais rápido possível e não diminuir a velocidade do processador. No entanto, eles podem ser implementados em software para caches de nível superior.
A maioria dos algoritmos é baseada no princípio da localidade em uma tentativa de prever o futuro a partir do passado. Alguns dos algoritmos de substituição de linha de cache mais populares são:
Além desses sistemas de hardware para gerenciar um cache, o termo memória cache também é usado por abuso de linguagem para designar qualquer mecanismo implementado no software a fim de permitir a rápida reutilização de dados já transferidos anteriormente.
Por exemplo, qualquer sistema operacional moderno possui, na interface entre os sistemas de arquivos e os drivers responsáveis pelo armazenamento em massa, uma subentidade cujo objetivo é manter os dados lidos ou gravados recentemente na RAM; isso ajuda a evitar E / S desnecessária com armazenamento em massa, já que geralmente são mais lentos do que aqueles com RAM.
O princípio é o seguinte:
A consistência é garantida se qualquer transferência for associada a uma marcação dos dados na memória. Um algoritmo que usa critérios de idade e reutilização de dados escolhe qual terá prioridade para permanecer no cache quando se aproxima da saturação. Para o uso aleatório, que é sempre pelo menos o caso para diretórios , este algoritmo considera que o que tem sido muito usado recentemente tem maior probabilidade de ser usado em um futuro próximo (ver: Lei 80/20 ).