1 / 44

Hierarquia de Memória

Hierarquia de Memória. Bruno C. Bourbon Jarbas J. de O. Júnior {bcb, jjoj} @ cin.ufpe.br. Roteiro. Motivação Introdução Organização da Cache Alinhamento do bloco da Cache Prefetching (pré-busca) Intercâmbio de laços Bloqueamento (Blocking) Garbage Collection e hierarquia de memória

july
Download Presentation

Hierarquia de Memória

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Hierarquia de Memória Bruno C. Bourbon Jarbas J. de O. Júnior {bcb, jjoj} @ cin.ufpe.br

  2. Roteiro • Motivação • Introdução • Organização da Cache • Alinhamento do bloco da Cache • Prefetching (pré-busca) • Intercâmbio de laços • Bloqueamento (Blocking) • Garbage Collection e hierarquia de memória • Conclusões • Referências

  3. Motivação • No últimos vinte anos: • Velocidade da CPU aumentou 60% / ano • Velocidade da Memória apenas 10% / ano • A laguna pode ser preenchida com memória cache • A cache é sub-utilizada • Aproveitamento mínimo das grandes caches • Uso ineficiente = baixa performace • Como aumentar o uso? Conscientização da cache

  4. Mais Motivos • Paralelismo da instruções: • Instruções SIMD consomem dados de 2 a 8 vezes mais que uma instrução normal • Lei de Probesting: • “Melhorias das tecnologias de compiladores dobra o desempenho dos computadores a cada 18 anos.” • Corolário: “Não espere que o compilador faça o serviço por você.” • Lei de Moore: • Consoles não a acompanham • Hardware fixo • Títulos de 2ª e 3ª gerações tem que melhor de alguma maneira

  5. Introdução • Precisamos lembrar a arquitetura de memória:

  6. Organização da Cache • Princípio da Localidade • Localidade Temporal: • Num futuro próximo, o programa irá referenciar as instruções e dados referenciados recentemente. • Localidade Espacial: • Num futuro próximo, o programa irá referenciar as instruções e dados que tenham endereços próximos das últimas referências.

  7. Organização da Cache • Mapeamento • Direto • Completamente Associativo • Associativo por conjunto • Leitura • Busca em demanda (Fetch On Demand ou Fetch) • Pré-Busca (Prefetch) • Escrita • Write-Through • Write-Back

  8. Mapeamento Direto • Cada bloco na memória principal é mapeado em uma única linha do cache • Módulo o número de blocos • Endereço é dividido em duas partes: • w bits menos significativos identificam um byte na linha • s bits mais significativos identificam um bloco • Os s bits são divididos em um campo que identifica a linha com r bits e em uma Tag de s-r bits

  9. Mapeamento Direto

  10. Mapeamento Completamente Associativo • Qualquer bloco da memória pode ser levado para qualquer linha do cache • O endereço é dividido em uma Tag que identifica a linha e no identificador do byte

  11. Mapeamento Completamente Associativo

  12. Mapeamento Associativo por Conjunto • A cache é dividida em um número de conjuntos (set) • Cada conjunto tem um certo número de linha (define a associatividade) • Um dado bloco da memória pode ser carregado em qualquer linha de um único conjunto na cache • Módulo número de sets

  13. Mapeamento Associativo por Conjunto

  14. Leitura da Cache (Busca) • Estratégias para busca de palavras ou linhas da memória principal • busca por demanda (fetch) • Pré-busca (prefetch) • Fetch por demanda • Fetch da linha quando ocorre miss • Estratégia mais simples, não exige hardware adicional • Prefetch • Fetch da linha antes que ela seja necessária • p.ex: Prefetch da linha i+1 quando a linha i é inicialmente referenciada

  15. Escrita na Cache • Leitura na cache: não há discrepância entre cache e memória principal • Escrita na cache: cópias da palavra na cache e na memória principal podem ter valores diferentes • Valores deveriam ficar iguais em razão de: • Acessos de E/S feitos através da memória principal • Acessos à memória principal por múltiplos processadores • Tempo médio de acesso à cache é aumentado pela necessidade de atualizações da memória principal • Mecanismos de coerência de escrita • write-through • write-back

  16. Alinhamento de Blocos da Cache • Blocos de Cache tem tipicamente o tamanho de um objeto. • Esperamos que um algoritmo que utilize um campo de um objeto utilize outros campos do mesmo. • Se x ocupa um Múltiplo do limite de B, então ele ocupa dois diferentes blocos da cache. • Se x não ultrapassa o limite um múltiplo de B, então os campos serão acessados em apenas um bloco de cache.

  17. Alinhamento de Blocos da Cache • Alocar objetos seqüencialmente: • Se o próximo objeto não cabe na porção restante do bloco atual, pule para o começo do próximo bloco. • Aloque os objetos de tamanhos T num área de memória, todos alinhados com limite de multiplicidade T (em relação ao tamanho do bloco). • Elimina o cruzamento de blocos (block-crossing), sem desperdiçar espaço entre objetos de tamanho comum.

  18. Alinhamento de Blocos da Cache • Desperdício de espaço: • Espaço vazio no final de cada bloco • Ganho de velocidade: • Se um conjunto S de objetos é frequentemente acessado, o alinhamento pode reduzir o espaço ocupado por S. Ajustando ao um espaço que caiba ele. • Alinhamento pode ser aplicado tanto a dados globais e estáticos como dinâmicos(heap). • Para dados globais e estáticos utiliza-se as diretivas de alocação da linguagem assembler. • Para variáveis dinâmicas(heap) o alocador de memória deverá cuidar disso em tempo de execução.

  19. Alinhamento de Instruções • Instruções ocupa cache assim como dados: • Alinhamento e block-crossing são aplicavéis • Alinhe o inicio de conjuntos de instruções mais usadas no limite de um “múltiplo de B” • Instruções poucos usadas não deve se alinhadas com as mais utilizadas

  20. Prefetching • Um miss na cache custa vários ciclos. • Se for na cache secundária custa ainda mais. • Em alguns casos pode ser previsto a utilização do dado. • O compilador pode utilizar uma instrução de prefetch para antecipar o carregamento de um dado (ou vários).

  21. Prefetching • Se prefetching falhar não afetará a corretude do programa. • Muitas processadores possuem algum tipo de instrução de prefetch • A utilização de reordenação por levar ao efeito de prefetch.

  22. Instruçõesde Prefetch • Algumas processadores na possuem instruções de prefetch, mas possuem instruções de load que não bloqueiam. • Ou seja utilizar um load para levar um dado para cache, mesmo que não seja utilizado naquele momento. • A dica: carrega os dados somente quando múltiplos do tamanho de um bloco

  23. Prefetch para armazenamento • Às vezes podemos prever, em tempo de compilação, quando haverá uma falta de cache (cache miss) em uma instrução . for i <-to N – 1 A[i] <- i ------------------------------------------ for i <- 0 to N – 1 if i mod blocksize = 0 then prefetch A[i + K] A[i] <- i

  24. Prefetch (resumo) • É aplicável quando: • A máquina possui uma instrução de prefetch; • A máquina não reordena as instruções dinamicamente; • O dado em questão é maior que a cache, ou não se espera que esteja na cache.

  25. Intercâmbio de Laços • Considere o seguinte laço: for i <- 0 to N – 1 for j <- 0 to M – 1 for k <- 0 to P – 1 A[i,j,k] <- (B[i,j-1,k]+B[i,j,k]+B[i,j+1,k]) O valor B[i,j+1,k] é reusado na próxima iteração do laço do j (no qual seu “nome” é B[i,j,k])

  26. k = 0 j = 1 i = 0 k = 1 j = 1 i = 0 k = 2 j = 1 i = 0 k = 0 j = 2 i = 0 Falta! Intercâmbio de Laços • for i <- 0 to N – 1 • for j <- 0 to M – 1 • for k <- 0 to P – 1 • A[i,j,k] <- (B[i,j-1,k]+B[i,j,k]+B[i,j+1,k]) j0 j1 j2 j3 ... k0 k1 k2 k3 ...

  27. k = 0 j = 1 i = 0 k = 0 j = 2 i = 0 k = 0 j = 3 i = 0 Intercâmbio de Laços Trocando-se os laços... • for i <- 0 to N – 1 • for k <- 0 to P – 1 • for j <- 0 to M – 1 • A[i,j,k] <- (B[i,j-1,k]+B[i,j,k]+B[i,j+1,k]) j0 j1 j2 j3 ... k0 k1 k2 k3 ...

  28. Intercâmbio de Laços MAS ATENÇÃO! • Para que um intercâmbio de laços seja válido,não pode haver dependência de dados entre as iterações. • É necessário examinar o grafo de dependência de dados do cálculo: • Dizemos que a iteração (j,k) depende da (j’,k’) se: • (j’,k’) calcular valores que são usados por (j,k) (leitura-depois-de-escrita) • (j’,k’) armazena valores que são sobre-escritos por (j,k) (escrita-depois-de-escrita) • Ou (j’,k’) lê valores que são sobre-escritos por (j,k) (escrita-depois-de-leitura)

  29. Bloqueamento • Caso geral • Substituição Escalar • Bloqueamentoem todos os níveis da hierarquia de memória • Desenrolando “as parada” (Unroll and Jam)

  30. Bloqueamento • Considere o seguinte laço para multiplicação de matrizes, C=A.B for i <- 0 to N – 1 for j <- 0 to N – 1 for k <- 0 to N – 1 C[i,j] <- C[i,j] + A[i,k].B[k,j] • Supondo que apenas as matrizes A e B e nada mais coubesse simultaneamente na memória cache, o laço k roda sem faltas, havendo somente uma falta para C[i,j] em cada iteração do laço j.

  31. Bloqueamento for i <- 0 to N – 1 for j <- 0 to N – 1 for k <- 0 to N – 1 C[i,j] <- C[i,j] + A[i,k].B[k,j] j0 j1 j2 j3 ... j0 j1 j2 j3 ... i0 i0 i1 i1 i2 i2 MEM. CACHE i3 i3 ... ... A B

  32. Bloqueamento • E se a cache, for menor que o suficiente para armazenar as duas matrizes simultaneamente? • Mais exatamente: se a cache suportar no máximo 2.c.N elementos (pontos flutuantes), onde 1 < c < N? • Nesse caso, para as referências a B[k,j], haverão sempre faltas.

  33. Linha i1 de A Linha i0 de A Coluna j0 de B Coluna j(2c) de B Coluna j0 de B Coluna j(2c+1) de B Coluna j1 de B Linha i1 Linha i0 Coluna j(2c+2) de B Coluna j2 de B 2.c < N !!! Então sempre ocorrerá falta de B[k,j] depois que a cache encher pela primeira vez Bloqueamento N for i <- 0 to N – 1 for j <- 0 to N – 1 for k <- 0 to N – 1 C[i,j] <- C[i,j] + A[i,k].B[k,j] 0 1 j0 j1 j2 j3 ... j0 j1 j2 j3 ... 2 i0 3 i1 ... i2 i3 MEM. CACHE 2.c ... A B

  34. Bloqueamento for i <- 0 to N – 1 for j <- 0 to N – 1 for k <- 0 to N – 1 C[i,j] <- C[i,j] + A[i,k].B[k,j] • Neste caso, o intercâmbio de laço não resolve, pois se o laço j ficar para fora, os elementos de A sofrerão faltas. E se o laço k ficar para fora, os elementos de C sofrerão faltas!

  35. Bloqueamento • O pulo da gato: • Reusar as linhas da matriz A e as colunas de B enquanto ainda estão na cache. • Para isso podemos calcular o bloco c x c da matriz C a partir de c linhas de A e c colunas de B. Já que nossa memória cache possui tamanho 2.c.N: for i <- i0 to i0 + c - 1 for j <- j0 to j0 + c -1 for k <- 0 to N – 1 C[i,j] <- C[i,j] + A[i,k].B[k,j]

  36. Lin i1 A Lin i0 A Lin i2 A Col j0 B Col j1 B Lin i3 A Linha i0 Col j2 B Linha i1 Linha i2 Linha i3 Col j(2c) B Bloqueamento 2c c c for i <- i0 to i0 + c - 1 for j <- j0 to j0 + c -1 for k <- 0 to N – 1 C[i,j] <- C[i,j] + A[i,k].B[k,j] 0 1 j0 j1 j2 j3 ... j0 j1 j2 j3 ... 2 i0 3 i1 ... i2 i3 MEM. CACHE N ... A B

  37. Bloqueamento • Agora só falta juntar os blocos: for i0 <- 0 to N – 1 by c for j0 <- 0 to N – 1 by c for i <- i0 to min(i0 + c – 1, N – 1) for j <- j0 to min (j0 + c –1, N – 1) for k <- 0 to N – 1 C[i,j] <- C[i,j] + A[i,k].B[k,j]

  38. Bloqueamento • Faltas: • As faltas agora são apenas para carregar na cache as novas colunas e as novas linhas cada vez que se for calcular um novo bloco c x c. • Para carregar as novas c linhas e c colunas ocorrem 2.c.N faltas. E para calcular um bloco c x c são necessárias c.c.N iterações. • Por tanto, o total de faltas por iteração é: 2.c.N / c.c.N = 2/c

  39. Bloqueamento:Substituição escalar • Mesmo que o acesso a C[i,j] quase nunca provoque uma falta na cache, nós poderíamos ainda deixá-la um nível de memória acima: nos registradores. for i <- i0 to i0 + c - 1 for j <- j0 to j0 + c –1 s <- C[i,j] for k <- 0 to N – 1 s <- s + A[i,k].B[k,j] C[i,j] <- s

  40. Bloqueamento:Em todos os níveis da hierarquia • Se quisermos usar d registradores de ponto flutuante, podemos reescrever o código do cálculo do bloco c x c como: for i <- i0 to i0 + c – 1 for k0 <- 0 to N – 1 byd for k <- k0 to k0 + d – 1 T[k-k0] <- A[i,k] for j <- j0 to j0 + c –1 s <- C[i,k] for k <- k0 to k0 + d – 1 s <- s + T[k-k0].B[k,j] C[i,j] <- s Preenchendo os registradores

  41. Bloqueamento:Desenrolando “as parada” (Unroll and Jam) • Porém, para usar bloqueamento no nível de registradores, precisamos “desenrolar” o laço pois os registradores não podem ser indexados por subscripts. • Assim, supondo d = 3 (3 registadores): for i <- i0 to i0 + c – 1 for k0 <- 0 to N – 1 by3 t0 <- A[i,k0]; t1 <- A[i,k0+1]; t2 <- A[i,k0+2] for j <- j0 to j0 + c –1 C[i,j] <- C[i,j] + t0.B[k0,j] + t1.B[k0+1,j] + t2.B[k0+2,j]

  42. Garbage Collection e Hierarquia de Memória • Sistemas que usam Garbage Collection têm a fama de não usar a memória de forma otimizada. • Porém, pode ser organizado para gerenciar a memória de uma melhor forma: • Gerações • Usar cache secundária para guardar a geração mais jovem • Alocação Seqüencial • Poucos conflitos • Prefetching para Alocação • Agrupando objetos relacionados. • Busca em profundidade • Busca em largura

  43. Conclusão • A otimização do uso da memória cache pode aumentar muito o desempenho de um programa; • As técnicas vistas são úteis tanto para projeto de compiladores como para desenvolvimento de software em geral; • Exemplo concreto da importância do estudo de compiladores por desenvolvedores.

  44. Referências • APPEL, Andrew W., Modern compiler implementation in Java. • ERICSON, Christer, Memory Otimization, GDC 2003 • SILVA, Ivan S., CASSILO, Leonardo. Organização e Arquitetura de Computadores I: Memória. DIMAP – UFRN. • BARROS, Edna N. S., Infra-Estrutura de Hardware: Memória e Hierarquia de Memória. CIn - UFPE

More Related