1
Fork 0
mirror of https://github.com/Steffo99/unisteffo.git synced 2024-12-01 12:24:19 +00:00
triennale-appunti-steffo/public/materials/year1/architettura/9_memorie.md

134 lines
5 KiB
Markdown
Raw Normal View History

2022-02-03 01:08:09 +00:00
# Memorie
La _memoria_ di un calcolatore solitamente è composta da molteplici strati, realizzati per velocizzare gli accessi.
Ogni strato offre lettura più veloce, ma è più costoso da realizzare e ha consumi più alti.
In ordine di velocità, sono:
- Registers
- Cache L1
- Cache L2
- Cache L`X`
- Random Access Memory
- Solid State Drive
- Hard Disk Drive
## Cache
### Cache L1
Piccola, ma miss penalty bassa
### Cache L2
Molto grande, ma miss penalty alta
### Direct mapping
Una cache _direct mapped_ associa a ogni indirizzo di RAM un **indice** uguale agli **N bit meno significativi** dell'indirizzo dell'inferiore, e un **tag** uguale agli **N bit più significativi**.
Se durante un accesso _il tag di un blocco è diverso dal tag dell'indirizzo a cui vogliamo accedere_, si ha un cache miss.
> Il dato di cui abbiamo bisogno è contenuto nell'indirizzo `0x0ABC` della RAM.
> Il suo indice sarà `0xBC`, e il suo tag sarà `0x0A`.
> Essendo la cache vuota all'inizio, viene immediatamente caricato.
>
> Voglio poi accedere all'indirizzo `0x0BBC` della RAM.
> Controlliamo il blocco con indice `0xBC`: il suo tag è `0x0A`, ma noi stiamo cercando `0x0B`! Si ha quindi un cache miss, e devo andare a prendere dalla memoria il dato che sto cercando e scriverlo sulla RAM.
Inoltre, in ogni blocco di memoria della cache è presente **un bit di validità**, che rappresenta se il dato in cache è stato inizializzato o no: parte da `0` e viene impostato a `1` quando viene caricato dalla RAM un dato nel relativo blocco.
> Un esempio potrebbe essere un processore con blocchi di memoria da 32 bit e indirizzi a 64 bit: la cache, contenente 1024 blocchi di memoria, avrà index a 12 bit, e di conseguenza il tag sarà grande 52 bit.
#### Dimensione blocchi
Fare blocchi grandi o fare blocchi piccoli ha significative differenze sulla velocità della cache:
Avere blocchi più grandi significa che ci saranno meno blocchi in tutta la cache, quindi:
```diff
+ Riduce il miss rate per il principio di località spaziale
- Avendo una quantità minore di blocchi, aumenta la possibilità di conflitto
- La miss penalty è più alta
# La miss penalty è compensabile con tecniche come early restart o critical-word-first
```
Con blocchi più piccoli, invece
```diff
+ Miss penalty minore
+ Più blocchi significa meno conflitti
- E' possibile che abbia bisogno di fare più di una richiesta alla cache, rallentandola significativamente
```
#### Scrittura tramite cache
Quando scrivo in memoria un dato presente nella cache, l'informazione presente nella cache diventa errata.
Si può risolvere questo problema con una politica di riscrittura:
- Write-through
- Write-back
##### Write-through
_Quando **viene scritto** su dato in cache_, aggiorna tutte le memorie che lo contengono.
```diff
+ Non necessita di ulteriore memoria di cache
+ Caricare dati è veloce
+ Se si verifica un write miss non ha per forza bisogno di portare in cache il dato da scrivere
- I write richiedono molto più tempo, soprattutto se ripetuti
```
##### Write-back
Scrivi la modifica di dato solo nella cache, e _marca il blocco come **dirty**_.
Quando un blocco dirty viene **sovrascritto**, aggiorna le memorie che lo contengono.
```diff
+ I write richiedono poco tempo, anche se ripetuti
- Caricare dati dalla RAM è più lento
- Necessita di memoria da dedicare al dirty bit
- Devo fetchare obbligatoriamente i dati da sovrascrivere
```
##### Miglioramenti alle policy
E' possibile utilizzare un **write buffer** invece che fare attendere il tempo di scrittura alla CPU. I dati saranno scritti successivamente, ma prima che questi vengano utilizzati.
```diff
+ Il processore non ha bisogno di fermarsi per le write
- Il buffer potrebbe riempirsi, neganode i vantaggi
- Il buffer utilizza memoria che forse sarebbe stata più utile come cache
```
### Fully associative
Ogni dato può essere messo in qualunque indirizzo della cache.
Richiede che l'indirizzo di origine venga salvato assieme al dato, e tanti comparatori.
### Set associative
Divido tutti i blocchi di cache in vie.
Ogni via può contenere `n` dati.
Un set è l'insieme dei dati che hanno lo stesso index ma sono in vie diverse.
Ogni dato può essere messo in qualunque indirizzo del set a cui appartiene.
Identifico il numero di set di appartenenza facendo `indirizzo % numerodiset`.
Una cache `1`-way Set Associative è una cache Direct Mapped, mentre una cache `numeroentries`-way Set Associative è una cache Fully Associative.
Quando non c'è spazio in un set, rimpiazzo un dato secondo la politica **Least Recently Used**, rimuovendo il dato usato meno recentemente. Posso usare anche la politica **Random**, se ho un'alta associatività.
#### Performance
Più una cache è associativa, più il miss rate sarà ridotto, ma l'associatività richiede un maggior numero di comparatori e potenzialmente più ritardi nella restituzione del dato.
Inoltre, la percentuale di miss non diminuisce linearmente con il numero di vie: dopo un certo numero di vie, i guadagni sono molto ridotti.