Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OC] Fix virtual memory content #876

Merged
merged 3 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 24 additions & 16 deletions content/oc/0004-memoria-caches.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ pequena de espaço de memória a qualquer momento durante a execução.
| mais caro | mais barato |
| estático, o conteúdo fica para "sempre" enquanto estiver ligado | dinâmico, precisa de ser "refrescado" regularmente (a cada 8 ms); consome 1% a 2% dos ciclos ativos da DRAM |

Para além disso, os endereços da DRAM são [divídido em 2 metades](color:pink), linha e coluna:
Para além disso, os endereços da DRAM são [dividido em 2 metades](color:pink), linha e coluna:

- [RAS (_Row Access Strobe_)](color:orange) que aciona o decodificador de linha;
- [CAS (_Columm Access Strobe_)](color:green) que aciona o selecionador de coluna.
- [CAS (_Column Access Strobe_)](color:green) que aciona o selecionador de coluna.

### Como Funciona a Hierarquia de Memória?

Expand Down Expand Up @@ -130,7 +130,7 @@ Se tentarmos aceder a dados e estes estiverem disponíveis no nível mais alto d
temos um [**_hit_**](color:green), caso contrário teremos um [**_miss_**](color:red)
e teremos de ir buscar os dados a um nível inferior.

Podemos ainda calcular o [**_hit rate_**](color:purple) de multiplos acessos através da seguinte fórmula:
Podemos ainda calcular o [**_hit rate_**](color:purple) de múltiplos acessos através da seguinte fórmula:

$$
\op{\text{Hit Rate}}
Expand Down Expand Up @@ -305,6 +305,14 @@ Existem três tipos de [cache misses](color:pink):
são mapeados para o mesmo set ou _block frame_, num set de associatividade ou até mesmo
em posicionamento de blocos em mapeamento direto.

### Cache Design Trade-offs

| Alteração | Efeito na _miss rate_ | Efeito negativo de _performance_ |
| :---------------------------------- | :-------------------------------- | :---------------------------------------------------------------------------------------- |
| Aumento do tamanho da cache | Diminuição de _capacity misses_ | Aumento do tempo de acesso |
| Aumento da associatividade da cache | Diminuição de _conflict misses_ | Aumento do tempo de acesso |
| Aumento do _block size_ | Diminuição de _compulsory misses_ | Aumento do _miss penalty_. Para blocos muito grandes, pode aumentar também a _miss rate_. |

## _Write-Policies_

Uma [_write policy_ da cache](color:pink) refere-se a um comportamento da cache
Expand All @@ -316,7 +324,7 @@ policies_.
### _Write-through_

Quando nos deparamos com um _data-write hit_ podemos somente atualizar o bloco da
cache, mas isto implicaria que a cache e a memória se tornassem insconsistentes. Temos,
cache, mas isto implicaria que a cache e a memória se tornassem inconsistentes. Temos,
por isso, que introduzir a política [_write-through_](color:pink): esta, sendo a mais
fácil de implementar, basicamente atualiza os dados tanto em cache como em memória ao
mesmo tempo. É usada quando não há escritas muito frequentes na cache e ajuda com a
Expand Down Expand Up @@ -377,7 +385,7 @@ diferentes:
## Medir a Performance da Cache

Para conseguirmos perceber se uma cache está a funcionar bem ou não, temos que saber
os termos involvidos nestes cálculos:
os termos envolvidos nestes cálculos:

- [Bloco ou linha](color:yellow): a unidade mínima de informação que está presente, ou
não, na cache;
Expand All @@ -393,7 +401,7 @@ os termos involvidos nestes cálculos:

Assim, como já sabíamos, os componentes do tempo do CPU são os [ciclos de execução do programa](color:purple),
que includem o tempo de _cache-hit_ e os [ciclos de atraso de memória](color:purple)
que provêm maioritariamente de _cache misses_. Assumindo que o sucesso de cache incui a
que provêm maioritariamente de _cache misses_. Assumindo que o sucesso de cache inclui a
parte normal dos ciclos de execução do programa, então podemos calcular o tempo de CPU
através da seguinte fórmula:

Expand Down Expand Up @@ -431,7 +439,7 @@ como um _miss penalty_ de 100 ciclos, uma [base CPI](color:yellow), ou seja, cac
ideal, igual a 2, e [loads e stores](color:purple) que ocupam 36% das instruções.

A primeira coisa que pretendemos calcular são os _miss cycles_ por instrução, que, como
vimos aicma, são dados pelo _miss rate_ e o _miss penalty_. Temos, por isso:
vimos acima, são dados pelo _miss rate_ e o _miss penalty_. Temos, por isso:

$$
\text{miss cycle} = \text{miss rate} \times \text{miss penalty}
Expand All @@ -456,11 +464,11 @@ Por isso. o CPU ideal é $$5.44/2=2.72$$ vezes mais rápido

### Ideias a Reter

Desta forma, concluimos que quando a performance do CPU aumenta, o _miss penalty_
Desta forma, concluímos que quando a performance do CPU aumenta, o _miss penalty_
[diminui](color:purple); uma diminuição baseada no CPI implica uma maior [proporção de tempo](color:purple)
gasto em atrasos na memória; e, um aumento de _clock rate_ significa que os atrasos de
memória contam para mais [ciclos de CPU](color:purple). Não podemos, evidentemente
negligenciar o comportamneto da cache quando estamos a avaliar a perfomance do sistema.
negligenciar o comportamento da cache quando estamos a avaliar a performance do sistema.

## Reduzir os _Miss Rates_ na Cache

Expand All @@ -472,7 +480,7 @@ um bloco de memória seja mapeado para qualquer bloco de cache numa [cache total

Por isso mesmo, o compromisso é dividir a cache em **sets** que contêm _n_ formas
([_n-way set associative_](color:pink)). Os blocos de memória mapeiam um _set_ único,
específicado pelo campo de index, e pode ser posto em qualquer sítio desse _set_, é por
especificado pelo campo de index, e pode ser posto em qualquer sítio desse _set_, é por
isso que há _n_ escolhas.

| [Totalmente associativo](color:yellow) | [Associatividade com _n_ sets](color:orange) |
Expand All @@ -494,19 +502,19 @@ encontra presente. Como não se encontra, temos um _miss_ e escrevemos na primei
o valor 0. Já tendo o 0 em cache, seguimos para o 4, vamos à primeira linha e vemos se
está na cache, contudo na cache só está o 0, logo, há um miss. Como estamos a tratar do
número 4, contamos as linhas até chegarmos à linha 4, como só há 4 linhas no total e
começamos a contar do zero, temos que modficar a nossa primeira linha para passar a ter
começamos a contar do zero, temos que modificar a nossa primeira linha para passar a ter
a informação relevante ao 0 para ter informação relevante ao 4. Assim, na nossa
primeira linha agora temos o 4.

Acabando os dois primeiros valores, passamos ao 0, vamos à primeira linha, vemos que já
está preenchida, há _miss_ e temos que voltar a preencher com o 0. Reparamos, por isso,
que temos o mesmo caso que no início do nosso exercício. Ora, como o resto dos valores
são sempre ou 0 ou 4 intrecalando, vamos sempre ter um _miss_ e vamos sempre ter que
são sempre ou 0 ou 4 intercalando, vamos sempre ter um _miss_ e vamos sempre ter que
voltar a preencher a primeira linha com o valor 0 ou 4.

![Exemplo](./assets/0004-exemplo.jpg#dark=3)

Porém, se tivessemos a ver a mesma string mas numa [2 way set associative_cache](color:pink),
Porém, se tivéssemos a ver a mesma string mas numa [2 way set associative_cache](color:pink),
só teríamos _miss_ nos primeiros dois acessos, visto que os nossos valores seriam
guardados na primeira e segunda via da primeira linha, e a partir daí conseguiríamos
aceder aos endereços 0 e 4 com sucesso.
Expand All @@ -530,7 +538,7 @@ dar acesso a novos? Em [mapeamento direto](color:purple) não temos escolha, con
[set de associatividade](color:purple) geralmente vemos primeiro se há alguma
[entrada não válida](color:pink), se não escolhemos a entrada que não está a ser usada
há mais tempo (LRU- _least-recently used_), o que é simples para uma via de 2, é gerível
com facilidade para 4, mas mais do que isso é demasiado díficil; nesses casos
com facilidade para 4, mas mais do que isso é demasiado difícil; nesses casos
funciona mais ou menos da mesma forma mas mais [aleatório](color:pink).

:::tip[Exemplos]
Expand Down Expand Up @@ -652,7 +660,7 @@ Existem várias técnicas para otimização de acesso de dados:
Pré-busca, [_prefetching_](color:blue) em inglês, refere-se ao carregamento de um
recurso antes que seja necessário de modo a diminuir o tempo de espera para esse recurso. Assim, um [_software prefetching_](color:pink) não pode ser feito nem
demasiado cedo, visto que os dados podem ser expulsos antes de serem usados, nem
demasiado tarde pois os dados podem não der trazidos a tempo da sua utilizção. Esta
demasiado tarde pois os dados podem não der trazidos a tempo da sua utilização. Esta
técnica é [_greedy_](color:purple). Da mesma forma, o pré-carregamento, ou
[_preloading_](color:blue) em inglês funciona como um pseudo prefetching, usando um
processamento _hit-under-miss_, isto é o acesso antigo é um _miss_ e, por isso, o
Expand Down Expand Up @@ -691,7 +699,7 @@ no esquema abaixo.
Em 1989, McFarling [reduziu _cache misses_ por 75%](color:pink) em caches de mapeamento
direto de 8 kB e blocos de 4 bytes em software. Para tal, foi necessário
[reorganizar os procedimentos em memória](color:purple) para reduzir os
_conflict misses_, assim como fazer um [perfil](color:purple) de modo a analizar os
_conflict misses_, assim como fazer um [perfil](color:purple) de modo a analisar os
conflitos, usando ferramentas que eles desenvolver. Os dados obtidos foram os seguintes:

- [_Merging arrays_](color:yellow): melhoram a localidade espacial através de um único
Expand Down
80 changes: 29 additions & 51 deletions content/oc/0005-memoria-virtual.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,6 @@ type: content

# Memória Virtual

:::danger[Conteúdo Não Revisto]

O conteúdo abaixo não foi revisto e poderá conter erros.
Agradecem-se [contribuições](https://docs.leic.pt/).

Apenas foi aqui incluído devido à proximidade do MAP45 dia 2022/10/20.

:::

```toc

```
Expand All @@ -32,7 +23,7 @@ sistema operativo (OS). Assim, cada programa é compilado para o seu próprio es
endereçamento, um [espaço de endereçamento virtual](color:purple). 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 e o OS traduzem o endereço virtual para um enderço físico,
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](color:pink) e em vez de
dizermos que houve um _"miss"_ dizemos que houve uma [_page fault_](color:pink).

Expand All @@ -57,24 +48,21 @@ Sempre que a cache acomoda um subcojunto de posições da memória principal, a
principal acomoda um subconjunto de posições da memória virtual. Cada
[bloco corresponde a uma página](color:pink). A [dimensão](color:pink) é 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, maior é a potencial
perda de memória (em média, 50% da dimensão da página); valores típicos são entre 4K
e 8K bytes.
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.

Um bloco pode ser posicionado em qualquer [espaço de memória](color:purple) visto ter
associatividade total.
Uma página pode ser posicionada em qualquer [espaço de memória](color:purple) visto a memória principal ter associatividade total.

![Tradução usando tabela de página](./assets/0005-traducao2.png#dark=3)

## Tabelas de Página
## Tabelas de Páginas

As [tabelas de página](color:pink) guardam o posicionamento da informação num array
te entradas todas indexadas por um número de uma página virtual. A tabela de página
regista os pontos do CPU da tabela de página em [memória física](color:purple). Se
uma página [estiver presente em memória](color:orange), temos o PTE
(_Page Table Entry_) que guarda o número da página física assim como outros bits de
estado (_dirty_, _referenced_, ...); caso contrário, o [PTE](color:pink) pode referir
outra localização em troca de espaço no disco.
As [tabelas de páginas](color:pink) 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](color:pink) pode referir outra localização em troca de espaço no disco.

### Trocas e Escritas

Expand All @@ -94,8 +82,8 @@ quando a página é escrita.
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](color:pink) a memória física. Por exemplo, se temos um espaço virtual
com $2^{32}$ bytes e páginas com 4 bytes, ou seja $2^{12}$, temos uma tabela com
$2^{20}$ entradas visto que $32-12=20$, ou seja temos 4M bytes de entradas!
com $2^{32}$ bytes e páginas com 4 kbytes, ou seja $2^{12}$ bytes, temos uma tabela com
$2^{20}$ entradas visto que $32-12=20$, ou seja temos 1 milhão entradas!

### Hierarquia das Tabelas de Página

Expand All @@ -108,14 +96,14 @@ hierarquia da tradução das tabelas.
:::tip[Exemplos]

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

:::

## Tabelas Invertidas

A tradução de endereços é baseada em [_hash tables_](color:purple). Uma qualquer
função has H(x) é aplicada ao endereço virtual de modo a encontrar uma fila
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](color:pink)
, 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
Expand All @@ -132,26 +120,18 @@ Assim, é necessária [memória extra](color:blue) para aceder a tradução de V
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_](color:pink)
isto é, uma **TLB**, que corresponde a uma cache mais pequena que acompanha os endereços
acedidos de modo a evitar ter que fazer uma tabela de página para os encontrar.
acedidos de modo a evitar ter que recorrer à tabela de página para os encontrar.

## _Translation Lookaside Buffer_ ou TLB

![TLB](./assets/0005-TLB.png#dark=3)

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 é tipicamente menor que
o tempo de acesso à cache visto que as TLBs são muito menores!
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](./assets/0005-TLBmem.png#dark=3)

Se uma página é carregada para a memória principal, então o _miss_ na TLB pode ser
tratado, tanto em _hardware_ como em _software_ se carregarmos a [tradução](color:pink)
da informação da tabela de página para a TLB. Sabendo que demora dezenas de ciclos para
econtrar e carregar a tradução da informação para a TLB, quando a página não se
encontra na memória principal, demora milhares de ciclos, e temos, por isso, uma
_true page fault_. É importante referir que os _misses_ são bastante mais comuns que
as _true page faults_.

Assim, quando ocorre um [TLB _miss_](color:pink), é 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
Expand All @@ -170,7 +150,7 @@ por isso, a instrução que falha é reiniciada.
![Interação](./assets/0005-interaction.png#dark=3)

Se a tag da cache usa um endereço de memória, é necessário traduzir antes de ir
procurar a cache. Uma alternatica é usar uma tag de endereço de memória virtual,
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.

Expand All @@ -185,12 +165,12 @@ memória torna-se inconsistente.

### Redução do Tempo de Tradução

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

| Virtual page index | Virtual offset |
| :----------------: | :------------: |

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

| Tag | Index | Offset |
| :-: | :---: | :----: |
Expand Down Expand Up @@ -221,11 +201,11 @@ Por isso, um dos seguintes cenários pode ocorrer:
## Proteção de Memória

Como é evidente, diferentes tarefas podem partilhar partes dos seus espaços de
endereçamento virtual, mas é necessário [proteger contrar acessos errantes](color:pink).
Para tal, precisamos de ajuda do OS.
endereçamento virtual, mas é necessário [proteger contra acessos errantes](color:pink).
Para tal, precisamos de ajuda do sistema operativo.

Visto que o suporte _hardware_ para porteção do OS, temos um modo supervisor
previlegiado, isto é, o [_kernel mode_](color:purple), instruções previlegiadas,
Existe suporte de _hardware_ para proteção do OS, pelo que temos um modo supervisor
privilegiado, isto é, o [_kernel mode_](color:purple), 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.

Expand All @@ -249,12 +229,10 @@ nível de hierarquia temos:
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_](color:pink): como já tinhamos visto anteriormente, podemos ter
_write-throughs_ que atualizam tanto os níveis superiores como inferiorese
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 é
- [_Write Policy_](color:pink): 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.

[_Cache Design Trade-offs_](color:green)
![_Cache Design Trade-offs_](./assets/0005-design.png#dark=3)
Binary file removed content/oc/assets/0005-design.png
Binary file not shown.
Loading