Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Gerarchie di memoria nei sistemi informatici: Diremo che esiste una gerarchia di memoria, nella quale al
livello più alto stanno i dispositivi di memoria più capaci, più lenti e meno costosi. Man mano che si scende
di livello nella gerarchia, i supporti hanno capacità sempre più piccola, tempo di acceso sempre più basso e
costo per bit sempre più grande. Obiettivo del progettista di una gerarchia di memoria è di ottimizzare il
rapporto prestazioni/costo agendo sugli spostamenti di dati tra livelli.
Paginazione a domanda: Nel metodo detto della paginazione a domanda, quando, nel tentativo di tradurre
un indirizzo n di M2, viene generato un fault (miss), allora l’intera pagina che contiene inf[n] viene trasferita
da M2 a M1 provocando il rimpiazzamento di una pagina già presente in M 1. L’efficacia di questo metodo si
basa su due proprietà dei programmi che, statisticamente, si verificano di frequente:
la località, o località temporale, secondo la quale i riferimenti generati da un processo tendono ad
accentrarsi, in ogni istante, in gruppi relativamente piccoli di indirizzi tra loro vicini, e tali gruppi tendono a
cambiare in modo relativamente lento e intermittente (=accedere non solo a quel dato in memoria ma
anche a quello immediatamente prima e dopo);
il riuso, o località spaziale, secondo la quale, nel corso dell’esecuzione di un processo, questo tende a
riferirsi più volte a certe locazioni (cicli iterativi, procedure, riassegnamenti di una variabile, oggetti).
In tal modo, una volta che una pagina è stata trasferita in M 1, questa tende a essere riferita più volte.
Statisticamente, se in M1 è presente un numero sufficientemente alto di pagine di M 1 (insieme di lavoro,
WS: working set), la probabilità che si generi un fault (probabilità di fault, o miss ratio) può essere
mantenuta a un valore basso a piacere. Inoltre, le proprietà di località e riuso vanno d’accordo con le
proprietà di molti dispositivi di memorizzazione dal punto di vista dell’ottimizzazione del tempo di
comunicazione di blocchi di informazione.
Un modello spesso valido è quello secondo il quale il tempo di comunicazione di k informazioni elementari
(parole, byte) è esprimibile come: Tcom = Tsetup + kTtrasm, dove Ttrasm è il tempo di latenza per trasmettere
una singola informazione elementare, e T setup è un ritardo costante di “overhead” necessario per
inizializzare il trasferimento. Secondo
Usiamo euristiche LRU (Last Recently Used): se ho bisogno di spazio allora cerco di eliminare l’informazione
acceduta meno di recente. Infatti se in Cache possiamo memorizzare 2 tipi di accessi, su ad esempio 3.
Memorizziamo per esempio i primi due e man mano sostituiamo il meno recente con quello nuovo
Definizione di WS: {blocchi di M (σ)} che se stanno in cache minimizzano il numero di fault.
RICORDIAMO: M – C – MMU – P
1
- M: contiene tutte le informazioni del mio processo, è grande, economica, molto capiente e lenta;
è un vettore di informazioni; ci ritrovo sempre la stessa roba
- C: tengo le informazioni del working set,costosa, poco capiente e veloce; più piccola di M e in istanti
contiene informazioni diverse.
Per C serve un modo per far corrispondere ad un indirizzo di M una ed una sola posizione di C: Metodo di
indirizzamento della PAGINAZIONE. Dentro la Cache vogliamo sfruttare tutti e due i principi.
Più la capacità è alta più la curva (secondo grafico) è traslata a dx, poiché consideriamo valori più grandi.
Insieme di lavoro (Working set): In una gerarchia di memoria M2 – M1, l’insieme di lavoro di un programma
(processo) è definito come l’insieme di pagine (blocchi) che, se presenti contemporaneamente in M 1,
rendono minima la probabilità di fault. L’insieme di lavoro va considerato sia in termini di quante pagine
che di quali pagine devono essere possibilmente presenti in M 1 contemporaneamente. L’obiettivo di una
gestione efficiente di una gerarchia di memoria è quello di individuare l’insieme di lavoro e cercare di
mantenerlo in M. A questo scopo, occorre cercare di sfruttare al meglio le proprietà di località e, in
particolare, di riuso di ogni programma.
ES) per array che viene completamente scansionato
#fault = 2 N /σ ||Se è possibile garantire la presenza in cache del Working set
Paginazione non su domanda: Alle volte le prestazioni sarebbero, invece, molto più soddisfacenti se la
paginazione non venisse applicata su domanda, bensì “in anticipo”: dalle proprietà del programma si
comprende come, ogni volta che si trasferisce una pagina, sia utile anticipare subito il trasferimento di una
o più pagine immediatamente successive.
Prefetching: La strategia, detta prefetching, è applicabile se, staticamente, si riesce a comprendere
l’andamento dei riferimenti. Il prefetching delle istruzioni viene, di regola, implementato per default
direttamente a firmware dall’unità cache; quello sui dati, quando si riveli conveniente, viene deciso dal
compilatore annotando le istruzioni di LOAD e STORE con l’opzione “prefetch”.
2
indirizzamento alla parola, la massima ampiezza della memoria virtuale di ogni programma è 4G parole.
L’insieme degli indirizzi logici di un processo è detto il suo spazio logico di indirizzamento.
Il codice eseguibile del processo, generato dal compilatore, è quindi riferito alla memoria virtuale. Il
processore genera indirizzi logici sia per le istruzioni sia per i dati. Quando viene creato e caricato, il
processo viene allocato in una zona della memoria principale, la cui ampiezza e i cui indirizzi non coincidono
(tranne casi particolari) con quelli della memoria virtuale del processo. La memoria principale viene allocata
dinamicamente a ogni processo, contando sul fatto che una copia completa, e integra, del processo è
sempre presente in memoria secondaria. Quando un processo viene allocato (o riallocato) in memoria
principale, viene stabilita una corrispondenza tra gli indirizzi logici della parte allocata e gli indirizzi fisici in
cui viene allocata. Questa funzione, detta funzione di rilocazione o di traduzione dell’indirizzo, è di norma
implementata come una tabella associata al processo (Tabella di Rilocazione), che, come il PCB e altre
informazioni di utilità, fa parte essa stessa della memoria virtuale e verrà allocata essa stessa in memoria
principale.
La funzione di rilocazione viene aggiornata (dalla funzionalità del sistema relativa alla gestione della
memoria principale) ogni volta che l’allocazione del processo viene modificata. Ad esempio, in un certo
istante un processo in esecuzione può avere bisogno di informazioni che non sono attualmente allocate in
memoria principale. Queste verranno copiate da memoria secondaria a memoria principale. In generale, le
nuove informazioni andranno a sostituirne altre “meno urgenti” (dello stesso programma o di altri
programmi); se le informazioni sostituite sono state nel frattempo modificate (scritture in variabili), i loro
valori verranno ricopiati da memoria principale nelle posizioni corrispondenti della memoria secondaria.
Questi spostamenti (riallocazioni) comportano opportune modifiche della Tabella di Rilocazione del
processo (dei processi). Si noti che il file eseguibile, presente in memoria secondaria, è sempre
un’immagine affidabile del processo.
μ(indirizzo logico) indirizzo fisico (a cui andare a cercare quell’informazione). L’indirizzo logico è quello
dato dal processore. I moduli di elaborazione a livello delle applicazioni e a livello del sistema operativo
sono i processi: programmi sequenziali con propria capacità di controllo, eseguibili concorrentemente ad
altri e cooperanti con essi.
Nel secondo caso, la conseguente gestione dell’eccezione provvederà a caricare in memoria la pagina
contenente l’informazione richiesta (inf[n]) prelevandola da memoria secondaria (file contenente la
versione compilata del processo).
La rilocazione dell’indirizzo logico, e l’eventuale gestione dell’eccezione di fault di pagina, sono
completamente invisibili al programma la cui compilazione ha dato luogo al processo. La funzione di
3
rilocazione del processo Q, μQ , viene implementata mediante una tabella, detta Tabella di Rilocazione del
processo, TABRILQ, il cui contenuto è inizializzato a tempo di caricamento/creazione e varia durante
l’esecuzione del processo in seguito all’allocazione dinamica di pagine.
Copio l’Offset dal logico al fisico. Uso l’indirizzo logico IPL per accedere alla posizione nella TABRIL (a destra)
dove è presente un bit di presenza che se a uno indica che la pagina logica i-esima è presente in memoria
principale. Nell’identificatore della pagina di memoria principale vi risiede la pagina logica i-esima nel caso
che il bit di presenza è = 1.
Durante la traduzione dell’indirizzo, attraverso la Tabella di Rilocazione è anche possibile effettuare
controlli di protezione: ad esempio controllare se il processo in esecuzione ha diritto di accedere in lettura o
scrittura, o altre modalità più complesse, alla pagina riferita. Allo scopo, nello schema di TABRIL esiste il
campo “Diritti di Protezione”. In caso di controllo negativo, viene generata un'eccezione di violazione di
protezione. Nello schema di TABR1L è anche indicato il campo “Bit di controllo” contenente un bit per
ricordare se la pagina è stata modificata e informazioni per implementare la politica di rimpiazzamento.
Quest’ultima politica, eseguita dalle funzionalità di gestione della memoria in seguito all’eccezione di fault
di pagina, ha come scopo la scelta della pagina da sostituire. La scelta che mediamente fornisce il risultato
migliore, agli effetti della riduzione della frequenza dei fault di pagina è la LRU (Least Recently Used).
Spesso questa politica viene implementata in modo approssimato, per non essere costretti a usare troppi
bit per contare da quanto tempo una pagina non viene usata; come caso limite, ma adottato in molti
sistemi, si ha la politica NRU (Not Recently Used) implementata mediante un contatore di un solo bit.
4
poche decine) è costituita da C registri, ognuno contenente una Chiave, e altrettanti contenenti i
corrispondenti Valori.
5
Le uscite dei registri-chiave sono ingressi di C confrontatori, il cui secondo ingresso è costituito dalla Chiave
Key (Key è il IPLi) con la quale si vuole effettuare la ricerca. Viene quindi effettuato il confronto simultaneo
di Key con tutte le Chiavi in tabella. Se uno dei confronti è positivo, allora l’indice del registro-chiave relativo
fornisce univocamente l’indirizzo della RAM dalla quale leggere il Valore(Key) corrispondente a Key; in caso
di tutti confronti negativi, l’evento negativo viene segnalato attraverso il valore di un bit di Fault. In
generale, per poter aggiornare la tabella, sia la parte Chiave sia la parte Valore sono accedibili anche per
indirizzo. Una parte di Tabella di Rilocazione TABRIL è mantenuta, dinamicamente, nella Memoria
Associativa MA nella PO della MMU (ad esempio, con C = 32). Le Chiavi sono gli identificatori di pagina
logica 1PL, mentre i Valori sono i corrispondenti contenuti TABRIL[IPL] della Tabella di Rilocazione.
Normalmente, si mantengono in MA le entrate di TABRIL usate più di recente: questo permette di rendere
trascurabile la probabilità che l’entrata di interesse non risieda in MA (si tratta di un’ulteriore applicazione
della politica LRU). In caso che venga generato “fault di MA’’, MMU provvede a copiare in MA l’entrata di
TABRIL corrispondente alla pagina logica riferita, sostituendo l’entrata usata meno di recente. Per questa
ragione, all’atto della commutazione di contesto, quando viene posto in esecuzione il processo Q, l
’indirizzo di TABRILQ deve essere comunicato a MMU, che lo mantiene in un suo registro interno. Si verifichi
che, in assenza di “fault di MA”, il ritardo introdotto dalla traduzione dell’indirizzo è un ciclo di clock della
CPU.
Nei confrontatori entrano i valori del registro IPL e il valore in IPL i (se esce uno 0 vuol dire che abbiamo
trovato un valore corrispondente). I valori uscenti dai confrontatori vengono messi in AND e questo
restituisce il FAULT. Questi valori vengono mandati ad un decodificatore e a un commutatore (a cui
vengono associati i bit di presenza).
6
Avviene tutto in un ciclo di clock: abbiamo all’inizio del ciclo tutti i registri disponibili. Dobbiamo aspettare
un t dei confrontatori e se non ho FAULT un t del decodificatore e un t del commutatore. in un ciclo di
clock posso farlo perché ho implementato una cache associativa
SE FAULT=1 ? IND = IND.TAB.RIL[IPL i] ordiniamo una lettura della memoria
di indirizzo IND
Struttura della CPU con cache: Nella figura seguente è mostrato lo schema delle interazioni tra MMU,
processore P e memoria cache C all’interno della CPU, rimanendo ancora nel modello elementare di
elaboratore:
Nel caso di successo nella rilocazione dell’indirizzo logico (di memoria virtuale), MMU passa la richiesta con
l’indirizzo fisico (di memoria principale) all’unità cache C. Questa provvede all’ulteriore traduzione da
indirizzo di memoria principale a indirizzo di memoria cache, nel caso che la funzione di traduzione sia
definita; in caso di insuccesso (cache fault o cache miss) ha luogo il trasferimento del blocco di memoria
principale richiesto in uno dei blocchi di C, in generale sostituendone uno già presente scelto mediante un
opportuno algoritmo di rimpiazzamento. Il trasferimento del blocco è, a differenza del fault di memoria
virtuale, del tutto invisibile a P.
Occorre prevedere un metodo per il trattamento delle scritture nella memoria cache:
1. nel metodo Write Back, il blocco modificato viene ricopiato nel livello superiore di memoria solo all’atto
della sostituzione del blocco stesso nel livello inferiore (come nella gerarchia della memoria virtuale -
memoria principale) o alla terminazione del processo;
2. nel metodo Write Through, ogni modifica della cache è effettuata immediatamente e
contemporaneamente anche in memoria principale (ovviamente, questa tecnica non è applicabile alla
memoria virtuale).
I metodi di indirizzamento della memoria cache sono descritti di seguito. Il termine “blocco” viene usato al
posto del termine “pagina”, per non creare confusione quando si consideri contemporaneamente le due
gerarchie MV - M e M - C.
Metodi di indirizzamento della cache: I principali metodi sono chiamati diretto, completamente
associativo, e associativo su insiemi.
- METODO DIRETTO: In questo caso ogni blocco di memoria principale può essere trasferito solo in un
determinato blocco della cache: esiste dunque uno e un solo blocco della cache in cui una certa
informazione può risiedere. Si può scegliere di adottare una semplice funzione di corrispondenza tra
7
blocchi, tipicamente la funzione moduloIn questo metodo dunque la funzione di traduzione dell'indirizzo è
immediata -> l'accesso alla cache è dunque effettuato direttamente. Il sistema dovrà mantenere una
Tabella di Corrispondenza, avente NC posizioni: ogni posizione contiene il valore del TAG corrispondente al
blocco di M effettivamente presente nel blocco di cache individuato da BC. Accedendo a questa tabella per
indirizzo con il valore BC, si confronta il contenuto letto con il campo TAG dell'indirizzo fisico; se il confronto
non è positivo si genera un fault. In questa eventualità, l'algoritmo di rimpiazzamento è banale: il blocco da
sostituire non può che essere quello individuato da BC.
La Tabella di Corrispondenza è realizzata mediante una memoria RAM di registri; nel nostro caso, 8K registri
ciascuno di 16 bit (più i bit di controllo).
L'accesso a tale tabella può essere effettuato in parallelo all'accesso del cache: ne consegue che l'accesso
stesso è completato in un ciclo di clock. Questo è reso possibile dall’adozione di variabili di
condizionamento complesse oppure dalla tecnica del controllo residuo: il bit che indica l’eventuale presenza
di fault è quello che condiziona la scrittura nella memoria cache (se richiesta) e la scrittura nell’interfaccia
verso il processore. Come esercizio, i realizzi in dettaglio l’applicazione di questa tecnica. Con il metodo
diretto, tenendo conto anche della presenza della MMU, il tempo di accesso alla memoria cache, in assenza
di fault, come visto dal processore è: tc = 2τ che rappresenta il minimo valore possibile con il protocollo a
domanda e risposta.
I vantaggi di questo metodo sono la velocità e la semplicità. Per contro esso presenta uno svantaggio, che
può rivelarsi anche molto gravoso, derivante dalla rigidità della legge di corrispondenza: quando occorre
accedere ripetutamente a coppie di informazioni (ad esempio, componenti di due strutture dati) che stanno
in blocchi di M corrispondenti allo stesso blocco di C, il numero di fault risulta molto elevato.
Modello dei costi: Si vuole valutare il tempo di completamento del programma e il tempo di servizio per
istruzione. L'efficienza relativa dell’architettura con cache, ε, è valutata come il rapporto tra tempo di
completamento Tideale in assenza di fault di cache e il tempo di completamento effettivo Tc considerando la
penalità dovuta ai fault Tfault. Il tempo di completamento è valutato come: Tc = Tideale + Tfault
Nella valutazione di Tideale, per il tempo di accesso in memoria va, quindi, utilizzato il tempo di accesso alla
cache tc (come “visto” dal processore).
Tfault si valuta come: Tfault = Nfault * Ttrasf
dove:
- Nfault è il numero medio di fault di cache che hanno luogo durante tutta l’esecuzione dello specifico
programma;
- Ttrasf è il tempo necessario per effettuare il trasferimento di un blocco di cache dal livello superiore alla
cache primaria.
La valutazione di Nfault, è il punto chiave del modello dei costi: occorre determinare l'insieme di lavoro del
programma in base alle proprietà di località e riuso, e determinare e se/come è implementabile.
Ricordiamo che il modello dei costi deve essere utilizzabile dal compilatore, per effettuare scelte
relativamente all’ottimizzazione del programma in base alle strategie messe a disposizione dal livello
assembler e firmware. Dunque, il procedimento deve essere formalizzabile in un algoritmo, eventualmente
un’euristica, in base ad un’analisi statica del programma.
Da Tc si ricavano il tempo di servizio T T = Tc / Nistr dove Nistr è il numero medio di istruzioni eseguite per
completare il programma, e l’efficienza relativa ε = Tideale/Tc
10