Esercizio 23cache con rimpiazzo di una linea sporca
In questa pagina 5
Testo (esempio di compitino intermedio di Architettura degli Elaboratori, UniPD, a.a. 2010-11, esercizio 8 in alternativa). Sia data la seguente sequenza di indirizzi in lettura (l) o scrittura (s) emessi dalla CPU:
| # | indirizzo (binario) | l/s | byte scritto (hex) |
|---|---|---|---|
| 1 | 0001 0000 0000 |
l | |
| 2 | 0001 0000 1000 |
l | |
| 3 | 0001 0000 1100 |
s | FF |
| 4 | 0001 0000 1101 |
s | AD |
| 5 | 0001 0001 0000 |
l | |
| 6 | 0001 0001 0000 |
s | 1B |
| 7 | 0001 0001 0100 |
l | |
| 8 | 0000 0111 0101 |
l |
La dimensione di parola coincide con un byte; la cache ha ampiezza 16 B, dimensione di blocco 4 B, è inizialmente vuota, a 2 vie, rimpiazzo LRU, politica di scrittura write-back, miss in scrittura con write allocate. La memoria ha il contenuto esadecimale:
| indirizzo | byte | byte | byte | byte |
|---|---|---|---|---|
| 100 | 08 | 00 | 07 | 02 |
| 104 | 00 | 00 | 00 | 00 |
| 108 | AE | 13 | A1 | 23 |
| 10C | A1 | 42 | 90 | 75 |
| 110 | B9 | 16 | 00 | 00 |
| 114 | 0A | 07 | 03 | 71 |
(Nel testo l'ultima riga è stampata "110 B9 111 16 112 00 112 00": un errore di battitura; il contenuto del blocco che inizia a 074, usato dall'ultimo accesso, non è indicato: lo si assume 00 00 00 00.) Si mostri come cambiano il contenuto della cache e quello della memoria.
Teoria: Memoria cacheBlocchi, linee ed etichette; scomposizione dell'indirizzo; associazione diretta, completamente associativa e associativa a insiemi con calcolo dei campi; politiche di rimpiazzo (LRU, FIFO, casuale); politiche di scrittura (write-through, write-back con bit sporco, write-allocate); dimensione del blocco; cache multilivello e separate; come ridurre i miss; quesiti sui campi dell'indirizzo.Memoria cache →. Esercizi analoghi: Esercizio 22 · cache a due vie LRU con write-back, Esercizio 11 · cache a due vie con rimpiazzo FIFO.
Campi e struttura
- Parola: blocco di 4 B → 2 bit.
- Linee: ; a 2 vie → 2 insiemi → set 1 bit.
- Etichetta: bit.
Il bit di set è il bit 2 dell'indirizzo: i blocchi 100, 108, 110, 118... (indirizzo del blocco pari) vanno nell'insieme 0, i blocchi 104, 10C, 114... nell'insieme 1. Con soli due insiemi i conflitti sono frequenti: è quello che fa succedere un rimpiazzo di linea sporca all'ultimo accesso.
Evoluzione
| # | indirizzo | accesso | etichetta | set | parola | esito | linea | contenuto della linea dopo l'accesso | memoria / note |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 100 |
l | 020 | 0 | 0 | miss | 0 | 08 00 07 02 | |
| 2 | 108 |
l | 021 | 0 | 0 | miss | 1 | AE 13 A1 23 | l'insieme 0 è pieno |
| 3 | 10C |
s FF | 021 | 1 | 0 | miss | 0 | FF 42 90 75 * | write allocate: carica A1 42 90 75, scrive FF; sporca |
| 4 | 10D |
s AD | 021 | 1 | 1 | hit | 0 | FF AD 90 75 * | resta sporca |
| 5 | 110 |
l | 022 | 0 | 0 | miss | 0 | B9 16 00 00 | insieme 0 pieno: esce la linea usata meno di recente (blocco 100, usato al passo 1), pulita: niente riscrittura |
| 6 | 110 |
s 1B | 022 | 0 | 0 | hit | 0 | 1B 16 00 00 * | sporca (memoria ancora B9 16 00 00) |
| 7 | 114 |
l | 022 | 1 | 0 | miss | 1 | 0A 07 03 71 | l'insieme 1 è ora pieno |
| 8 | 075 |
l | 00E | 1 | 1 | miss | 0 | 00 00 00 00 | insieme 1 pieno: esce la linea 0 (blocco 10C, ultimo uso al passo 4), sporca: va riscritta in memoria prima di caricare il nuovo blocco |
Esito: 2 hit (accessi 4 e 6), 6 miss.
Il rimpiazzo dell'accesso 8. Nell'insieme 1 ci sono la linea 0 (blocco 10C, sporca, ultimo uso al passo 4) e la linea 1 (blocco 114, ultimo uso al passo 7). La più vecchia è la linea 0: poiché è sporca si riscrive in memoria l'intero blocco, non solo il byte:
(in memoria c'era A1 42 90 75: cambiano due byte, M[10C] = FF e M[10D] = AD, ma il trasferimento è di 4 byte). Poi nella linea 0 si carica il blocco 074..077 (tutti 00, per ipotesi).
La linea 0 dell'insieme 0 (blocco 110) è ancora sporca a fine esercizio e non è stata riscritta: la sua modifica M[110] = 1B non è ancora visibile in memoria.
Stato finale
| insieme | linea 0 | linea 1 |
|---|---|---|
| 0 | etichetta 022: 1B 16 00 00 (sporca) |
etichetta 021: AE 13 A1 23 |
| 1 | etichetta 00E: 00 00 00 00 |
etichetta 022: 0A 07 03 71 |
Memoria modificata: solo il blocco 10C..10F, che ora vale FF AD 90 75.
Verifica
def cache_wb(accessi, memoria, byte_cache, blocco, vie):
insiemi = byte_cache // blocco // vie
righe = {i: [] for i in range(insiemi)} # linee dal meno al più recentemente usato
esiti, riscritti = [], []
for a, op, val in accessi:
s, base = (a // blocco) % insiemi, a - a % blocco
et = a // blocco // insiemi
linea = next((l for l in righe[s] if l["et"] == et), None)
hit = linea is not None
if hit:
righe[s].remove(linea)
else:
if len(righe[s]) == vie:
v = righe[s].pop(0)
if v["sporca"]:
vb = (v["et"] * insiemi + s) * blocco
for k in range(blocco):
memoria[vb + k] = v["dati"][k]
riscritti.append(hex(vb))
linea = {"et": et, "dati": [memoria.get(base + k, 0) for k in range(blocco)], "sporca": False}
righe[s].append(linea)
if op == "s":
linea["dati"][a % blocco] = val
linea["sporca"] = True
esiti.append("hit" if hit else "miss")
return esiti, righe, riscritti
memoria = {}
for ind, byte4 in [(0x100, "08 00 07 02"), (0x104, "00 00 00 00"), (0x108, "AE 13 A1 23"),
(0x10C, "A1 42 90 75"), (0x110, "B9 16 00 00"), (0x114, "0A 07 03 71")]:
for k, b in enumerate(byte4.split()):
memoria[ind + k] = int(b, 16)
accessi = [(0b000100000000, "l", None), (0b000100001000, "l", None), (0b000100001100, "s", 0xFF),
(0b000100001101, "s", 0xAD), (0b000100010000, "l", None), (0b000100010000, "s", 0x1B),
(0b000100010100, "l", None), (0b000001110101, "l", None)]
esiti, righe, riscritti = cache_wb(accessi, memoria, 16, 4, 2)
print(esiti) # ['miss', 'miss', 'miss', 'hit', 'miss', 'hit', 'miss', 'miss']
print(riscritti) # ['0x10c']: l'unico blocco sporco rimpiazzato
print([format(memoria[a], "02X") for a in range(0x10C, 0x110)]) # ['FF', 'AD', '90', '75']
print(format(memoria[0x110], "02X")) # B9: la linea sporca del blocco 110 è ancora in cacheErrori comuni
- Rimpiazzare con FIFO o scegliere la linea sbagliata: con LRU all'accesso 8 esce la linea 0 dell'insieme 1 (ultimo uso al passo 4), non la linea 1 (passo 7).
- Non riscrivere la linea sporca in memoria quando viene rimpiazzata (o riscrivere un byte solo invece del blocco di 4).
- Riscrivere in memoria anche la linea pulita uscita all'accesso 5: non serve.
- Scrivere subito in memoria
FF,ADe1B(comportamento da write-through). - Contare 4 insiemi: con 4 linee e 2 vie gli insiemi sono 2.
Versione ripasso
Esempio di compitino intermedio a.a. 2010-11: cache da 16 B, blocchi da 4 B, 2 vie, LRU, write-back, write allocate, indirizzi di 12 bit. Teoria: Memoria cacheBlocchi, linee ed etichette; scomposizione dell'indirizzo; associazione diretta, completamente associativa e associativa a insiemi con calcolo dei campi; politiche di rimpiazzo (LRU, FIFO, casuale); politiche di scrittura (write-through, write-back con bit sporco, write-allocate); dimensione del blocco; cache multilivello e separate; come ridurre i miss; quesiti sui campi dell'indirizzo.Memoria cache →.
Campi: parola 2 bit; linee ; insiemi → set 1 bit; etichetta bit.
Esito (100 l, 108 l, 10C s FF, 10D s AD, 110 l, 110 s 1B, 114 l, 075 l): miss, miss, miss, hit, miss, hit, miss, miss → 2 hit e 6 miss.
- Accesso 5: l'insieme 0 è pieno ed esce la linea usata meno di recente (blocco
100, pulita): nessuna scrittura in memoria. - Accesso 8: l'insieme 1 è pieno ed esce la linea 0 (blocco
10C, ultimo uso al passo 4), sporca: si riscrive in memoria l'intero blocco10C..10F=FF AD 90 75, poi si carica il blocco074..077(assunto00). - La linea del blocco
110è sporca (1B 16 00 00) e non ancora in memoria.
Errori comuni: scelta della linea sbagliata (FIFO); linea sporca non riscritta o riscritta per un solo byte; linea pulita riscritta; scritture subito in memoria; 4 insiemi invece di 2.