Edit page

Memória Virtual

Usando a memória principal como uma "cache" para o armazenamento secundário (no disco), esta tem que ser gerida tanto pelo hardware do CPU como pelo sistema operativo (OS). Assim, cada programa é compilado para o seu próprio espaço de endereçamento, um espaço de endereçamento virtual. Nos programas que partilham a memória principal, cada um tem direito a um espaço de endereçamento físico privado que é frequentemente usado para código e dados, assim como é protegido dos outros programas. O CPU traduz o endereço virtual para um enderço físico, tendo, por isso, a VM um "bloco" que se chama página e em vez de dizermos que houve um "miss" dizemos que houve uma page fault.

Quando dois programas partilham memória física, isto significa que o espaço de endereçamento de um programa está divido em páginas (todas de um tamanho fixo) ou em segmentos (de tamanho variável). O início da localização de cada página, quer seja na memória principal ou secundária, é contido na tabela de página do programa.

Memória virtual

Tradução do Endereço

O endereço virtual é traduzido num endereço físico através de uma combinação de hardware e software. Desta forma, cada pedido de memória precisa de, primeiro que tudo, um espaço físico. Quando há uma miss na memória vitual, isto é, quando a página não está na memória física, é o que chamamos de page fault.

Tradução de endereço

Sempre que a cache acomoda um subcojunto de posições da memória principal, a memória principal acomoda um subconjunto de posições da memória virtual. Cada bloco corresponde a uma página. A dimensão é geralmente bastante elevada de modo a aumentar a eficiência quando o disco é acedido, e também reduz a dimensão da tabela de tradução; porém, quanto maior for a página, maior é a potencial perda de memória (em média, 50% da dimensão da página); valores típicos de página são os 4 ou 8 Kbytes.

Uma página pode ser posicionada em qualquer espaço de memória visto a memória principal ter associatividade total.

Tradução usando tabela de página

Tabelas de Páginas

As tabelas de páginas guardam o posicionamento da informação num array de entradas todas indexadas pelo número da página virtual. A tabela de páginas regista o endereço de memória física para onde aponta a página do endereço virtual além de outros bits de estado (dity, referenced, ...); caso contrário, o PTE pode referir outra localização em troca de espaço no disco.

Trocas e Escritas

Tal como já tinhamos visto em memória física, ao fazermos uma troca em memória virtual, de modo a reduzirmos o número de page faults é preferível usar o método LRU. Assim, temos que ter um reference bit na PTE que está a 1 quando temos acesso à página e é periodicamente limpo a 0 pelo OS. Se o reference bit está a zero quer dizer que já não é usado há algum tempo.

A escrita em disco demora milhões de ciclos, visto que vamos fazendo um bloco de cada vez e não localizações individuais, o que torna o write-through imprático. Por isso temos que usar o write-back sendo que o dirty bit é definido quando a página é escrita.

Tamanho das Tabelas de Página

Um problema comum na paginação de sistemas é que a dimensão de uma tabela de página não é obrigada a traduzir os endereços: apenas precisa de alocar numa região contida a memória física. Por exemplo, se temos um espaço virtual com 2322^{32} bytes e páginas com 4 kbytes, ou seja 2122^{12} bytes, temos uma tabela com 2202^{20} entradas visto que 3212=2032-12=20, ou seja temos 1 milhão entradas!

Hierarquia das Tabelas de Página

Contudo, a questão vem: como é que podemos hierarquizar as nossas tabelas de páginas? Uma solução comum para este problema é implementar a tradução com a hierarquia da tradução das tabelas.

Hierarquia

Exemplos

Para mais exemplos de cálculos com hierarquia de memória é recomendada a realização da 5ª ficha das aulas práticas ou ver a sua resolução.

Tabelas Invertidas

A tradução de endereços é baseada em hash tables. Uma qualquer função hash H(x) é aplicada ao endereço virtual de modo a encontrar uma fila particular de descriptores composta pelos pares página virtual - página física , que correspondem a endereços virtuais dando origem ao mesmo valor da função hash H(x) em termos de colisões. Assim, o endereço físico necessário pode, ou não, estar presente nessa mesma fila de descriptores.

Tabela invertida

Tabela invertida

Sabemos, ainda, que o tamanho da tabela de página invertida é proporcional ao tamanho do espaço de endereçamento físico.

Assim, é necessária memória extra para aceder a tradução de VA para PA. Isto faz com que os acessos à memória sejam ainda mais caros, e a maneira de resolver o problema de hardware é através de um Translation Lookaside Buffer isto é, uma TLB, que corresponde a uma cache mais pequena que acompanha os endereços acedidos de modo a evitar ter que recorrer à tabela de página para os encontrar.

Translation Lookaside Buffer ou TLB

TLB

Tal como em qualquer outra cache, a TLB pode ser organizada de modo a ser totalmente associativa, ou diretamente mapeada. O tempo de acesso à TLB é extremamente menor que o tempo de acesso à cache visto que as TLBs são muito menores e são desenhadas para ser rápidas!

TLB

Assim, quando ocorre um TLB miss, é necessário reconhecer como miss antes que o registo do destino seja sobrescrito, dando origem a uma exceção. Assim o handler copia o PTE da memória para a TLB, reiniciando a instrução e, caso a página não esteja presente, irá ocorrer uma page fault.

No caso de uma page fault, é utilizado um endereço de memória virtual falhado para encontra o PTE, localiza a página do disco, escolhe a página que pretende repôr (caso seja dirty escreve no disco primeiro), a página é lida para memória e a tabela de página é atualizada fazendo com que o processo possa funcionar novamente, e por isso, a instrução que falha é reiniciada.

Exemplo

Interação entre a TLB e a Cache

Interação

Se a tag da cache usa um endereço de memória, é necessário traduzir antes de ir procurar a cache. Uma alternativa é usar uma tag de endereço de memória virtual, contudo, tal pode ser complicado graças a aliasing, isto é, diferentes endereços virtuais para endereços físicos partilhados.

Mas, porque é que a cache não é virtualmente endereçada? Uma cache virtualmente endereçada apenas necessitaria da tradução de endereços em caso de haver cache miss. Porém, dois programas que estão a partilhar memória têm que ter dois endereços de memória virtual diferentes para o mesmo endereço físico (aliasing), desta forma, tem que haver duas cópias dos dados partilhados na cache e em duas entradas na TLB o que podem dar origem a problemas de coerência. Para isto, é necessário atualizar todas as entradas da cache com o mesmo endereço físico ou a memória torna-se inconsistente.

Redução do Tempo de Tradução

Sabendo que a interpretação de endereços virtuais pela TLB é representada da seguinte forma:

Virtual page index Virtual offset

E que a interpretação dos endereços físicos pela cache é representada da seguinte forma:

Tag Index Offset

Como é que podemos paralelizar o acesso? O campo do offset do endereço virtual não participa no processo de tradução dos endereços, assim, se o offset do endereço virtual é maior ou igual ao index mais o offset, o campo do index da cache está incluido no offset do endereço virtual. Por isso, a cache pode ser lida em paralelo com o teste da TLB.

Este acesso paralelo pode originar uma sobreposição entre o acesso à cache e o acesso à TLB, visto que funciona em bits de ordem superior do VA que são usados para aceder à TLB enquanto os bits de ordem inferior são usados como index para a cache.

Paralelo

Paralelo

Por isso, um dos seguintes cenários pode ocorrer:

  • Hit tanto na TLB como na cache: tempo de acesso parecido ao tempo de acesso à cache;
  • Hit na TLB mas miss na cache: tempo de acesso parecido ao acesso à memória principal e o cache miss;
  • Miss na TLB: é necessário esperar pela tradução, pela hierarquia ou pela tabela invertida, assim como não existe um ganho muito elevado no acesso à cache.

Proteção de Memória

Como é evidente, diferentes tarefas podem partilhar partes dos seus espaços de endereçamento virtual, mas é necessário proteger contra acessos errantes. Para tal, precisamos de ajuda do sistema operativo.

Existe suporte de hardware para proteção do OS, pelo que temos um modo supervisor privilegiado, isto é, o kernel mode, instruções privilegiadas, tabelas de páginas e outros estados de informação que só podem ser acedidos com o modo supervisor e uma chamada de exceção do sistema.

Hierarquia de Memória

Se tivermos a ver em termos de panorama geral, os princípios comuns aplicam-se a todos os níveis da hierarquia de memória, baseado nas noções de caching. Assim, a cada nível de hierarquia temos:

  • Block placement: determinado pela associatividade; é mapeado diretamente (só tem uma escolha de posicionamento), tem uma associatividade com um set de n sentidos (tem n escolhas dentro de um set), ou é totalmente associativo (pode ir para qualquer localização). Quanto maior for a associatividade, menor é o miss rate, aumenta a complexidade, custo e tempo de acesso.

  • Finding a block: tem caches hardware que reduzem a comparação de modo a reduzir o custo assim como memória virtual numa tabela de procura de associatividade total fazível e tem um miss rate reduzido.

  • Replacement on a miss: escolha de entrada para substituir em caso de miss que pode ser através da política LRU ou aleatório; em termos de memória virtual o LRU tem uma aproximação com o suporte de hardware.

  • Write Policy: como já tínhamos visto anteriormente, podemos ter write-throughs que atualizam tanto os níveis superiores como inferiores e simplificam a troca mas precisam de um buffer de escrita; ou write-backs que apenas atualizam os níveis superior e só atualizam os inferiores quando o bloco é resposto, ou seja, é necessário manter mais estado. Assim, em termos de memória virtual, só o write-back é fazível, visto que existe uma latência de escrita no disco.