Salta al contenuto
Note per Studenti Esercizio 22 · cache a due vie LRU con write-back

Esercizio 22cache a due vie LRU con write-back

Esame
In questa pagina 7

Testo (compitino di Architettura degli Elaboratori, UniPD, del 17 novembre 2015, esercizio 8). Sia data la seguente sequenza di indirizzi in lettura (l) o scrittura (s) emessi dalla CPU e la memoria abbia il contenuto esadecimale indicato.

# indirizzo (binario) l/s byte scritto (hex)
1 0001 0000 1001 l
2 0001 0000 1101 s AB
3 0001 0000 1110 s 39
4 0001 0001 1100 l
5 0001 0000 1000 s D4
6 0001 0001 1110 l
7 0001 0000 1010 s 98
8 0001 0010 0001 l
indirizzo byte byte byte byte
100 08 00 07 02
104 00 00 00 00
108 AE 59 AD 23
10C A1 42 90 75
110 B9 16 00 00
114 0A 07 03 71
118 3E 13 71 23
11C A1 82 90 15
120 FF C6 AD 00
124 E9 16 05 00

Si assuma che la dimensione di parola coincida con un byte e la presenza di una cache di ampiezza 32 B, dimensione di blocco 2 B, inizialmente vuota, ad associazione a 2 vie, rimpiazzo LRU, politica di scrittura write-back e gestione dei miss in scrittura con write allocate. Si indichino i campi dell'indirizzo, la suddivisione della cache e 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 9 · cache con blocchi di due parole, Esercizio 11 · cache a due vie con rimpiazzo FIFO.


Campi e struttura

  • Blocco di 2 B → parola 1 bit.
  • Linee: 32/2=1632 / 2 = 16; a 2 vie → 16/2=816 / 2 = 8 insiemi → set 3 bit.
  • Etichetta: 12−3−1=812 - 3 - 1 = 8 bit.

(La soluzione allegata al testo scrive "4 set, ognuno di 2 linee" ma indica correttamente i campi etichetta 8 bit, set 3 bit, parola 1 bit: con 3 bit di set gli insiemi sono 8, ciascuno di 2 linee da 2 B; i risultati dell'esempio sono quelli che si ottengono con 8 insiemi.)

L'indirizzo 0001 0000 1001 ha etichetta 00010000 (10 esadecimale), set 100 (4), parola 1.

Regole applicate

  • LRU: nell'insieme pieno esce la linea usata meno di recente (un accesso, in lettura o scrittura, "usa" la linea).
  • Write-back: la scrittura modifica solo la cache e mette a 1 il bit sporco (nella tabella un * dopo il contenuto). La memoria si aggiorna solo quando una linea sporca viene rimpiazzata, e allora si riscrive l'intero blocco.
  • Write allocate: su miss in scrittura il blocco viene prima caricato, poi modificato in cache (e resta sporco).

Evoluzione

# indirizzo accesso etichetta set parola esito linea contenuto della linea dopo l'accesso memoria / note
1 109 l 10 100 1 miss 0 AE 59
2 10D s AB 10 110 1 miss 0 A1 AB* write allocate: carica A1 42, scrive AB, sporco
3 10E s 39 10 111 0 miss 0 39 75* write allocate: carica 90 75, sporco
4 11C l 11 110 0 miss 1 A1 82 l'insieme 110 ha ora due linee
5 108 s D4 10 100 0 hit 0 D4 59* stesso blocco del passo 1; sporco
6 11E l 11 111 0 miss 1 90 15
7 10A s 98 10 101 0 miss 0 98 23* write allocate: carica AD 23
8 121 l 12 000 1 miss 0 FF C6

Esito: 1 hit (accesso 5) e 7 miss. Nessun rimpiazzo: in nessun passo un insieme già pieno riceve un nuovo blocco (al più due blocchi per insieme), quindi la memoria non cambia per tutto l'esercizio: le quattro scritture (AB, 39, D4, 98) vivono solo nella cache, nelle linee marcate *. In un sistema reale quei dati arriverebbero in memoria solo al rimpiazzo della linea o con una operazione di svuotamento (flush).

Stato finale

insieme linea 0 linea 1
000 etichetta 12: FF C6 vuota
100 etichetta 10: D4 59 (sporca) vuota
101 etichetta 10: 98 23 (sporca) vuota
110 etichetta 10: A1 AB (sporca) etichetta 11: A1 82
111 etichetta 10: 39 75 (sporca) etichetta 11: 90 15

Che cosa cambierebbe con write-through

Con write-through ogni s aggiornerebbe subito la memoria: M[10D] = AB, M[10E] = 39, M[108] = D4, M[10A] = 98 (quattro scritture di un byte, in memoria da subito); con write-back nessuna scrittura in memoria in questo esempio, ma un eventuale rimpiazzo successivo di una linea sporca costerebbe la riscrittura di 2 byte. Vedi Esercizio 21 · cache a due vie FIFO con write-through per il caso opposto.

Verifica con un simulatore

python
def cache_wb(accessi, memoria, byte_cache, blocco, vie):
    """LRU, write-back, write allocate. Restituisce esiti, cache e memoria."""
    insiemi = byte_cache // blocco // vie
    righe = {i: [] for i in range(insiemi)}           # per insieme: linee dal meno al più recentemente usato
    esiti = []
    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)                    # LRU: la prima della lista
                if v["sporca"]:
                    vb = (v["et"] * insiemi + s) * blocco
                    for k in range(blocco):
                        memoria[vb + k] = v["dati"][k]  # riscrive l'intero blocco
            linea = {"et": et, "dati": [memoria.get(base + k, 0) for k in range(blocco)], "sporca": False}
        righe[s].append(linea)                         # ora è la più recente
        if op == "s":
            linea["dati"][a % blocco] = val
            linea["sporca"] = True
        esiti.append("hit" if hit else "miss")
    return esiti, righe, memoria

memoria = {}
for ind, byte4 in [(0x100, "08 00 07 02"), (0x104, "00 00 00 00"), (0x108, "AE 59 AD 23"), (0x10C, "A1 42 90 75"),
                   (0x110, "B9 16 00 00"), (0x114, "0A 07 03 71"), (0x118, "3E 13 71 23"), (0x11C, "A1 82 90 15"),
                   (0x120, "FF C6 AD 00"), (0x124, "E9 16 05 00")]:
    for k, b in enumerate(byte4.split()):
        memoria[ind + k] = int(b, 16)
originale = dict(memoria)

accessi = [(0x109, "l", None), (0x10D, "s", 0xAB), (0x10E, "s", 0x39), (0x11C, "l", None),
           (0x108, "s", 0xD4), (0x11E, "l", None), (0x10A, "s", 0x98), (0x121, "l", None)]
esiti, righe, memoria = cache_wb(accessi, memoria, 32, 2, 2)
print(esiti)                                           # ['miss', 'miss', 'miss', 'miss', 'hit', 'miss', 'miss', 'miss']
print(memoria == originale)                            # True: nessuna scrittura in memoria
for s in range(8):
    print(format(s, "03b"), [(hex(l["et"]), [format(b, "02X") for b in l["dati"]], l["sporca"]) for l in righe[s]])

Errori comuni

  • Applicare write-through: scrivere subito in memoria. Con write-back la memoria resta uguale finché non si rimpiazza una linea sporca.
  • Dimenticare il write allocate: un s che manca va trattato come una lettura che carica il blocco e poi modifica un byte.
  • Con LRU, non aggiornare l'"uso" sugli hit (nell'accesso 5 la linea 0 dell'insieme 100 diventa la più recente).
  • Contare 4 insiemi invece di 8: i 3 bit di set sono dati dal rapporto 16/216 / 2.
  • Riscrivere solo il byte modificato al rimpiazzo di una linea sporca: va riscritto tutto il blocco.

Versione ripasso

Compitino del 17 novembre 2015: cache da 32 B, blocchi da 2 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 1 bit; linee 32/2=1632/2 = 16; insiemi 16/2=816/2 = 8 → set 3 bit; etichetta 12−3−1=812 - 3 - 1 = 8 bit (la soluzione allegata dice "4 set" ma i campi sono quelli con 8 insiemi).

Regole: LRU = esce la linea usata meno di recente (anche gli hit contano come uso); write-back = la scrittura modifica solo la cache e mette a 1 il bit sporco; al rimpiazzo di una linea sporca si riscrive l'intero blocco; write allocate = su miss in scrittura si carica il blocco e poi si modifica.

Esito (109 l, 10D s AB, 10E s 39, 11C l, 108 s D4, 11E l, 10A s 98, 121 l): miss, miss, miss, miss, hit, miss, miss, miss → 1 hit e 7 miss. Nessuna linea viene rimpiazzata, quindi la memoria non cambia: le scritture AB, 39, D4, 98 stanno solo nelle linee sporche (A1 AB*, 39 75*, D4 59*, 98 23*).

Errori comuni: write-through al posto di write-back; write allocate dimenticato; LRU non aggiornato sugli hit; 4 insiemi invece di 8; riscrittura del solo byte modificato.

Esercizi su questo argomento

Teoria collegata