Qual técnica de mapeamento de cache é usada no processador Intel Core i7?

Eu aprendi sobre diferentes técnicas de mapeamento de cache como mapeamento direto, mapeamento associado e técnica de mapeamento associativo de conjunto e também aprendi as compensações. Mas estou curioso sobre o que é usado atualmente no processador Intel Core i7 ou AMD. E como as técnicas são evoluídas. E quais são as coisas que precisam ser melhoradas?

Os caches de mapeamento direto basicamente nunca são usados ​​em CPUs modernas de alto desempenho . A economia de energia é compensada pela grande vantagem na taxa de acertos para um cache associativo de conjuntos do mesmo tamanho, com apenas um pouco mais de complexidade na lógica de controle. Os orçamentos dos transistores são muito grandes hoje em dia.

É muito comum o software ter pelo menos dois arrays que são um múltiplo de 4k distantes um do outro, o que criaria falhas de conflito em um cache de mapeamento direto. (Ajustar o código com mais de dois arrays pode envolver distorcê-los para reduzir as falhas de conflito, se um loop precisar fazer uma iteração em todos eles de uma só vez)

As CPUs modernas são tão rápidas que a latência de DRAM é superior a 200 ciclos de clock, que é muito grande, mesmo para CPUs de execução fora de ordem poderosas para se esconder muito bem em um cache de falta.


Caches de vários níveis são essenciais (e usados ​​em todos os CPUs de alto desempenho) para fornecer baixa latência (~ 4 ciclos) / alta taxa de transferência para os dados mais quentes (por exemplo, até 2 cargas e 1 loja por clock , com 128, 256 ou até mesmo o caminho de 512 bits entre o cache L1D e as unidades de execução de carregamento / armazenamento vetoriais), embora ainda seja grande o suficiente para armazenar em cache um conjunto de trabalho de tamanho razoável. É fisicamente impossível construir um cache muito grande / muito rápido / altamente associativo que tenha desempenho, bem como caches de vários níveis atuais para cargas de trabalho típicas; atrasos na velocidade da luz quando os dados têm que viajar fisicamente longe são um problema. O custo de energia também seria proibitivo. (Na verdade, a densidade de energia / potência é um importante fator limitante para CPUs modernas, consulte Microprocessadores Modernos: Um Guia de 90 Minutos!. )

Todos os níveis de cache (exceto o cache uop) são fisicamente indexados / fisicamente marcados em todas as CPUs do x86 que eu conheço. Caches L1D na maioria dos projetos levam seus bits de índice abaixo do deslocamento da página e, portanto, também são VIPT, permitindo que a pesquisa TLB aconteça em paralelo com a busca de tag, mas sem nenhum problema de alias. Assim, os caches não precisam ser liberados em interruptores de contexto nem nada. (Veja esta resposta para mais informações sobre caches multi-nível em geral e o truque de velocidade VIPT, e alguns parâmetros de cache de alguns processadores x86 reais.)


Os caches L1D / L1I e L2 privados (por núcleo) são caches tradicionais de associação associativa , geralmente de 8 ou 4 vias para caches pequenos / rápidos. O tamanho da linha de cache é de 64 bytes em todas as CPUs modernas x86. Os caches de dados são write-back. (Exceto na família AMD Bulldozer, em que L1D é write-through com um pequeno buffer de combinação de gravação 4kiB.)

http://www.7-cpu.com/ tem bons números de organização / latência de cache, largura de banda e números de organização / desempenho de TLB, para várias microarquiteturas, incluindo muitos x86, como o Haswell .

O cache decodificado “L0” na família Intel Sandybridge é definido como associativo e praticamente endereçado . Até 3 blocos de até 6 uops podem armazenar em cache os resultados de decodificação de instruções em um bloco de 32 bytes de código de máquina. Relacionado: Alinhamento de ramificação for loops envolvendo instruções codificadas em CPUs da família Intel SnB . (O cache uop é um grande avanço para as instruções x86: x86 com tamanho variável e difícil de decodificar rápido / em paralelo, portanto, armazenar em cache os resultados de decodificação internos, bem como o código de máquina (L1I $), tem vantagens significativas de potência e throughput. decodificadores ainda são necessários, porque o cache uop não é grande, é mais eficaz em loops (incluindo loops médios a grandes) evita o erro Pentium4 (ou limitação baseada no tamanho do transitor no momento) de ter decodificadores fracos e confiar em o cache de rastreamento.)


Modern Intel (e AMD, eu assumo) L3 aka LLC também conhecido como caches de último nível usam uma function de indexação que não é apenas um intervalo de bits de endereço . É uma function hash que distribui melhor as coisas para reduzir as colisões de passos fixos. De acordo com a Intel, meu cache deve ser 24-way associativo embora seu 12-way, como é isso? .


A partir do Nehalem , a Intel usou um grande cache L3 compartilhado, que filtra o tráfego de coerência entre os núcleos . ou seja, quando um núcleo lê dados que estão no estado Modificado em L1d de outro núcleo, os tags L3 dizem qual núcleo, portanto, um RFO (Read For Ownership) pode ser enviado apenas para esse núcleo, em vez de transmissão. Como os caches modernos da CPU Intel L3 são organizados? . A propriedade de inclusividade é importante, porque significa que nenhum cache privado L2 ou L1 pode ter uma cópia de uma linha de cache sem que L3 saiba disso. Se estiver no estado Exclusivo ou Modificado em um cache particular, o L3 terá dados inválidos para essa linha, mas as tags ainda dirão qual núcleo pode ter uma cópia. Os núcleos que definitivamente não têm uma cópia não precisam receber uma mensagem sobre isso, economizando energia e largura de banda nos links internos entre os núcleos e o L3. Veja por que a coerência do cache on-chip está aqui para mais detalhes sobre a coerência do cache on-chip no Intel “i7” (ou seja, famílias Nehalem e Sandybridge, que são arquiteturas diferentes, mas usam a mesma hierarquia de cache).

O Core2Duo tinha um cache de último nível compartilhado (L2), mas demorava a gerar solicitações de RFO (Read-For-Ownership) em falhas de L2. Portanto, a largura de banda entre os núcleos com um buffer pequeno que se encheckbox no L1d é tão lenta quanto com um buffer grande que não se encheckbox no L2 (ou seja, velocidade de DRAM). Há um intervalo rápido de tamanhos quando o buffer se encheckbox em L2, mas não em L1d, porque o núcleo de gravação despeja seus próprios dados em L2, onde as cargas do outro núcleo podem ser atingidas sem gerar uma solicitação de RFO. (Veja a Figura 3.27: Largura de Banda do Núcleo 2 com 2 Threads em “O que todo programador deve saber sobre memory” de Ulrich Drepper. ( Versão completa aqui ).


O Skylake-AVX512 tem L2 maiores por núcleo (1MiB em vez de 256k) e fatias L3 (LLC) menores por núcleo. Não é mais inclusivo . Ele usa uma rede de malha em vez de um barramento de anel para conectar os núcleos uns aos outros. Veja este artigo da AnandTech (mas tem algumas imprecisões nos detalhes da microarquitetura em outras páginas, veja o comentário que deixei ).

Da visão geral técnica da família escalonável do processador Intel® Xeon®

Devido à natureza não inclusiva da LLC , a ausência de uma linha de cache na LLC não indica que a linha não está presente em caches privados de qualquer um dos núcleos. Portanto, um filtro snoop é usado para rastrear a localização das linhas de cache na L1 ou MLC de núcleos quando não está alocada na LLC. Nas CPUs da geração anterior, a própria LLC compartilhada cuidou dessa tarefa.

Este “filtro snoop” só é útil se não puder ter falsos negativos. Não há problema em enviar uma invalidação ou RFO ( MESI ) para um núcleo que não tenha uma cópia de uma linha. Não é permitido deixar um núcleo manter uma cópia de uma linha quando outro núcleo está solicitando access exclusivo a ela. Por isso, pode ser um rastreador com tags inclusas que saiba quais núcleos podem ter cópias de qual linha, mas que não armazena dados em cache.

Ou talvez o filtro snoop ainda possa ser útil sem include estritamente todas as tags L2 / L1. Eu não sou especialista em protocolos multi-core / multi-socket snoop. Eu acho que o mesmo filtro snoop também pode ajudar a filtrar solicitações snoop entre sockets. (Em Broadwell e anteriormente, apenas Xeons com quatro sockets e mais altos têm um filtro snoop para tráfego entre núcleos; o Broadwell Xeon com soquete duplo e anteriormente não filtram as solicitações de espionagem entre os dois sockets .)


O AMD Ryzen usa caches L3 separadas para clusters de núcleos , portanto, os dados compartilhados entre vários núcleos precisam ser duplicados no L3 para cada cluster. Também importante, as gravações de um núcleo em um cluster levam mais tempo para serem visíveis a um núcleo em outro cluster, com as solicitações de coerência tendo que passar por uma interconexão entre clusters. (Semelhante a entre sockets em um sistema Intel multi-socket, onde cada pacote de CPU tem seu próprio L3.)

Isso nos dá NUCA (Non-Uniform Cache Access), análogo ao habitual NUMA (Non-Uniform Memory Access) que você obtém em um sistema multi-socket onde cada processador possui um controlador de memory embutido, e acessar a memory local é mais rápido do que acessar a memory conectada a outro soquete.


Os sistemas recentes de múltiplos sockets da Intel têm modos snoop configuráveis, portanto, em teoria, você pode ajustar o mecanismo NUMA para funcionar melhor com a carga de trabalho que está sendo executada. Veja a página da Intel sobre Broadwell-Xeon para obter uma tabela + descrição dos modos de rastreamento disponíveis.


Outro avanço / evolução é uma política de substituição adaptativa no L3 no IvyBridge e posteriormente . Isso pode reduzir a poluição quando alguns dados têm localidade temporal, mas outras partes do conjunto de trabalho são muito maiores. (ou seja, o loop de um array gigante com a substituição de LRU padrão removerá tudo, deixando o cache L3 apenas em cache de dados do array que não será tocado novamente em breve. A substituição adaptativa tenta atenuar esse problema.)


Leitura adicional:

  • O que todo programador deve saber sobre memory?
  • Por que o Skylake é muito melhor do que o Broadwell-E para rendimento de memory de thread único? ? (A largura de banda de memory single-thread em CPUs Xeon de muitos núcleos é limitada por max_concurrency / latency, não por largura de banda DRAM).
  • http://users.atw.hu/instlatx64/ para resultados de temporização de desempenho de memory
  • http://www.7-cpu.com/ para números de latência e organização de cache / TLB.
  • http://agner.org/optimize/ para detalhes microarquitetônicos (principalmente sobre o pipeline de execução, não de memory) e guias de otimização asm / C ++.
  • O wiki de marca x86 do Stack Overflow tem uma seção de desempenho, com links para esses e mais.