Esercizio - Sostituzione delle pagine con FIFO, LRU e OPT (eserciziario, esercizi 38, 39, 40, 48, 57, 58 e 80)
In questa pagina 9
Testo (eserciziario del corso di Sistemi Operativi, Ing. Informatica UniPD). Paginazione su richiesta pura (all'inizio nessuna pagina in memoria), salvo dove indicato.
- 38. Stringa
2, 6, 3, 2, 9, 10, 9, 3, 11, 12, 3, 2, 4 frame, FIFO: quanti page fault? - 39. Stringa
8, 0, 10, 12, 9, 10, 11, 3, 11, 11, 3 frame, LRU: quanti page fault? - 40 (identico al 57). LRU con prepaginazione (all'avvio si caricano le prime pagine fino a riempire i frame). Stringa
15, 15, 0, 2, 3, 11, 2, 6, 4, 14, 4 frame ; una pagina libera va nel frame di indice minimo. Page fault? - 48. 4 frame inizialmente liberi, 8 pagine virtuali, FIFO, stringa
0 1 4 7 3 7 4 1 0 3. Quanti page fault? Mostrare il procedimento. - 58. OPT, stringa
6, 6, 2, 12, 7, 2, 0, 12, 2, 6. (1) Con 3 frame (una pagina libera va nel frame di indice minimo): quanti fault? (2) Se i frame aumentano, i fault possono diminuire? (3) La risposta cambia con altre stringhe? - 80. Stringa
1, 2, 3, 4, 2, 1, 5, 6, 2, 1, 2, 3, 7, 6, 3, 2, 1, 2, 3, 6: quanti fault con LRU e con OPT con 5 frame?
Il procedimento
Si scorre la stringa. Per ogni riferimento: se la pagina è già in un frame (hit), non succede niente (con LRU si aggiorna solo il momento dell'ultimo uso); altrimenti è un page fault e:
- c'è un frame libero: la pagina ci va;
- altrimenti si sceglie la vittima: con FIFO la pagina in memoria da più tempo (conta il momento del caricamento, un hit non lo cambia); con LRU quella usata meno recentemente (conta l'ultimo accesso); con OPT quella il cui prossimo uso è più lontano (o che non sarà mai più usata).
Nelle tabelle ogni colonna è un riferimento, ogni riga un frame, e F segna i fault.
Esercizio 38 (FIFO, 4 frame): 9 fault
| rif. | 2 | 6 | 3 | 2 | 9 | 10 | 9 | 3 | 11 | 12 | 3 | 2 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| frame 1 | 2 | 2 | 2 | 2 | 2 | 10 | 10 | 10 | 10 | 10 | 10 | 2 |
| frame 2 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 11 | 11 | 11 | 11 | |
| frame 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 12 | 12 | 12 | ||
| frame 4 | 9 | 9 | 9 | 9 | 9 | 9 | 3 | 3 | ||||
| fault | F | F | F | F | F | F | F | F | F |
- : tre fault per riempire i frame con 2, 6, 3.
- : la pagina 2 c'è. : la 9 entra nel quarto frame. : la 10 non c'è e non ci sono frame liberi: FIFO toglie la più vecchia, la 2.
- : hit su 9 e 3. : ogni accesso è un fault che sostituisce, nell'ordine di arrivo, 6, 3, 9 e 10.
Totale: 9 fault.
Esercizio 39 (LRU, 3 frame): 7 fault
| rif. | 8 | 0 | 10 | 12 | 9 | 10 | 11 | 3 | 11 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|
| frame 1 | 8 | 8 | 8 | 12 | 12 | 12 | 11 | 11 | 11 | 11 |
| frame 2 | 0 | 0 | 0 | 9 | 9 | 9 | 3 | 3 | 3 | |
| frame 3 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | ||
| fault | F | F | F | F | F | F | F |
I primi tre accessi riempiono i frame. Il 12 sostituisce la meno recente (8), il 9 sostituisce lo 0, il 10 è un hit (e diventa la più recente), l'11 sostituisce il 12 (usato meno di recente tra 12, 9, 10) e il 3 sostituisce il 9. Gli ultimi due accessi all'11 sono hit. Totale: 7.
Esercizi 40 e 57 (LRU con prepaginazione, 4 frame): 6 fault
All'istante 0 sono già caricate le pagine 0, 1, 2, 3 nei frame (con 0 la meno recente, 3 la più recente).
| rif. | 15 | 15 | 0 | 2 | 3 | 11 | 2 | 6 | 4 | 14 |
|---|---|---|---|---|---|---|---|---|---|---|
| 15 | 15 | 15 | 15 | 15 | 11 | 11 | 11 | 11 | 14 | |
| 1 | 1 | 0 | 0 | 0 | 0 | 0 | 6 | 6 | 6 | |
| 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | |
| 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | |
| fault | F | F | F | F | F | F |
- : la 15 non c'è; la meno recente è la 0, nel frame : la 15 va in .
- : la 0 è appena stata scacciata, quindi è un fault; la meno recente è la 1 ().
- : la 11 sostituisce la meno recente tra 15 (usata a ), 0, 2, 3: è la 15.
- : le pagine 6, 4, 14 sostituiscono rispettivamente 0, 3 e 11.
Totale: 6 fault (le due soluzioni del corso, per 40 e per 57, coincidono).
Esercizio 48 (FIFO, 4 frame): 6 fault
| rif. | 0 | 1 | 4 | 7 | 3 | 7 | 4 | 1 | 0 | 3 |
|---|---|---|---|---|---|---|---|---|---|---|
| frame 1 | 0 | 0 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 |
| frame 2 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | |
| frame 3 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | ||
| frame 4 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | |||
| fault | F | F | F | F | F | F |
I primi quattro accessi riempiono i frame; il 3 sostituisce la più vecchia (0); 7, 4, 1 sono hit; lo 0 sostituisce la più vecchia, l'1; il 3 è un hit. Totale: 6 fault.
Esercizio 58 (OPT, 3 frame): 6 fault
| rif. | 6 | 6 | 2 | 12 | 7 | 2 | 0 | 12 | 2 | 6 |
|---|---|---|---|---|---|---|---|---|---|---|
| 6 | 6 | 6 | 6 | 7 | 7 | 0 | 0 | 0 | 6 | |
| 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | |||
| 12 | 12 | 12 | 12 | 12 | 12 | 12 | ||||
| fault | F | F | F | F | F | F |
- (la 7): in memoria 6, 2, 12; il prossimo uso è: 2 a , 12 a , 6 a . Si toglie la 6 (la più lontana).
- (lo 0): tra 7 (mai più), 2 (a ), 12 (a ) si toglie il 7, perché non serve più.
- (la 6): nessuna delle pagine in memoria sarà più usata: si può scegliere un frame qualsiasi ().
(1) 6 fault. (2) Con più frame i fault non possono aumentare e possono diminuire: OPT non ha l'anomalia di Belady (è un algoritmo a pila). Con 4, 5 o più frame i fault scendono a 5 (con 3 frame: 6; con 2: 7; con 1: 9): il numero minimo di fault è il numero di pagine distinte. (3) No: questa proprietà di OPT vale per qualsiasi stringa. (Si possono confrontare le conclusioni con quelle di un algoritmo che soffre dell'anomalia, come FIFO.)
Errore nella soluzione del corso. La soluzione scrive che il numero minimo di fault è "pari a sei", il numero di pagine diverse. In realtà le pagine distinte sono cinque (6, 2, 12, 7, 0), quindi il minimo possibile è 5 (si raggiunge con 5 o più frame, come mostra il conto).
Esercizio 80 (5 frame): LRU 8, OPT 7
La stringa 1, 2, 3, 4, 2, 1, 5, 6, 2, 1, 2, 3, 7, 6, 3, 2, 1, 2, 3, 6.
LRU (8 fault)
| rif. | 1 | 2 | 3 | 4 | 2 | 1 | 5 | 6 | 2 | 1 | 2 | 3 | 7 | 6 | 3 | 2 | 1 | 2 | 3 | 6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| frame 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| frame 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | |
| frame 3 | 3 | 3 | 3 | 3 | 3 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | ||
| frame 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 4 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | |||
| frame 5 | 5 | 5 | 5 | 5 | 5 | 5 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | ||||||
| fault | F | F | F | F | F | F | F | F |
OPT (7 fault)
| rif. | 1 | 2 | 3 | 4 | 2 | 1 | 5 | 6 | 2 | 1 | 2 | 3 | 7 | 6 | 3 | 2 | 1 | 2 | 3 | 6 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| frame 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
| frame 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | |
| frame 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | ||
| frame 4 | 4 | 4 | 4 | 4 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | 6 | |||
| frame 5 | 5 | 5 | 5 | 5 | 5 | 5 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | ||||||
| fault | F | F | F | F | F | F | F |
Variando i frame (soluzione del corso, verificata):
| frame | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|
| LRU | 20 | 18 | 15 | 10 | 8 | 7 | 7 |
| FIFO | 20 | 18 | 16 | 14 | 10 | 10 | 7 |
| OPT | 20 | 15 | 11 | 8 | 7 | 7 | 7 |
OPT è sempre il minimo e LRU sta fra OPT e FIFO.
Un simulatore in C
Il programma simula le tre politiche sulla stessa stringa e stampa a ogni riferimento il contenuto dei frame. Si compila con gcc -Wall -Wextra -o replace replace.c (compilato qui con zig cc per Linux, senza avvisi; non eseguito).
/* replace.c - simula FIFO, LRU e OPT su una stringa di riferimenti.
* Compilare: gcc -Wall -Wextra -o replace replace.c
* Usare: ./replace 3 7 0 1 2 0 3 0 4 2 3 0 3 0 3 2 1 2 0 1 7 0 1
* (il primo numero e' quello dei frame, gli altri sono i riferimenti)
*/
#include <stdio.h>
#include <stdlib.h>
#define MAXF 16
static int cerca(const int *fr, int n, int pagina) {
for (int i = 0; i < n; i++)
if (fr[i] == pagina) return i;
return -1;
}
/* politica: 'F' = FIFO, 'L' = LRU, 'O' = OPT. Restituisce i page fault. */
static int simula(char politica, int nframe, const int *rif, int len) {
int fr[MAXF]; /* pagina contenuta in ogni frame */
int caricata[MAXF]; /* istante in cui la pagina e' stata caricata (per FIFO) */
int usata[MAXF]; /* istante dell'ultimo accesso (per LRU) */
int usati = 0, fault = 0;
printf("%c rif frame\n", politica);
for (int t = 0; t < len; t++) {
int p = rif[t];
int i = cerca(fr, usati, p);
int errore = (i < 0);
if (errore) {
fault++;
if (usati < nframe) {
i = usati++; /* c'e' un frame libero */
} else if (politica == 'F') {
i = 0; /* la piu' vecchia in memoria */
for (int k = 1; k < usati; k++)
if (caricata[k] < caricata[i]) i = k;
} else if (politica == 'L') {
i = 0; /* la meno recentemente usata */
for (int k = 1; k < usati; k++)
if (usata[k] < usata[i]) i = k;
} else { /* OPT: il prossimo uso piu' lontano */
int lontano = -1;
i = 0;
for (int k = 0; k < usati; k++) {
int j = t + 1;
while (j < len && rif[j] != fr[k]) j++; /* j == len: mai piu' usata */
if (j > lontano) { lontano = j; i = k; }
}
}
fr[i] = p;
caricata[i] = t;
}
usata[i] = t;
printf(" %3d ", p);
for (int k = 0; k < usati; k++) printf(" %3d", fr[k]);
printf("%s\n", errore ? " <- page fault" : "");
}
printf("page fault: %d\n\n", fault);
return fault;
}
int main(int argc, char **argv) {
if (argc < 3) {
fprintf(stderr, "uso: %s nframe rif1 rif2 ...\n", argv[0]);
return 1;
}
int nframe = atoi(argv[1]);
int len = argc - 2;
if (nframe < 1 || nframe > MAXF) {
fprintf(stderr, "nframe deve stare fra 1 e %d\n", MAXF);
return 1;
}
int *rif = malloc((size_t)len * sizeof *rif);
if (!rif) return 1;
for (int i = 0; i < len; i++) rif[i] = atoi(argv[i + 2]);
simula('F', nframe, rif, len);
simula('L', nframe, rif, len);
simula('O', nframe, rif, len);
free(rif);
return 0;
}Con ./replace 4 2 6 3 2 9 10 9 3 11 12 3 2 (esercizio 38) il programma dà, per la riga FIFO, page fault: 9 e per LRU e OPT rispettivamente 8 e 7. Questi numeri sono stati controllati con una simulazione equivalente in Python; per il caso FIFO l'ultima riga di frame è 2 11 12 3 (lo stesso che nella tabella sopra, letto per colonna).
Come funziona la scelta della vittima: in FIFO caricata[k] conserva l'istante del caricamento e non viene aggiornato dagli hit; in LRU usata[i] = t si aggiorna a ogni accesso, hit compresi. In OPT si cerca in avanti nella stringa il primo uso di ciascuna pagina; se non c'è, e quella pagina vince (è la più lontana).
Errori tipici
- Aggiornare in FIFO l'ordine con gli hit (è una caratteristica di LRU).
- Contare un fault quando la pagina è già presente.
- Con la prepaginazione, partire dai frame vuoti e non dalle pagine 0-3 già caricate.
- Scegliere in OPT in base al passato invece che al futuro.
- Dire che aumentando i frame i fault non diminuiscono mai di meno: vale per LRU e OPT, non per FIFO (anomalia di Belady).
Versione ripasso
Regole. Hit: niente (LRU aggiorna l'ultimo uso). Fault: frame libero, altrimenti vittima. FIFO: caricata da più tempo (gli hit non contano). LRU: usata meno di recente. OPT: prossimo uso più lontano o mai. Il numero minimo di fault è il numero di pagine distinte.
Risultati. 38 (FIFO, 4 frame, 2 6 3 2 9 10 9 3 11 12 3 2): 9. 39 (LRU, 3 frame, 8 0 10 12 9 10 11 3 11 11): 7. 40 e 57 (LRU, prepaginazione 0-3 in , 15 15 0 2 3 11 2 6 4 14): 6 (15 in , 0 in perché appena scacciato, 11 al posto di 15, 6 al posto di 0, 4 al posto di 3, 14 al posto di 11). 48 (FIFO, 4 frame, 0 1 4 7 3 7 4 1 0 3): 6. 58 (OPT, 3 frame, 6 6 2 12 7 2 0 12 2 6): 6; più frame non peggiorano (OPT è a pila); il minimo è 5 (pagine distinte 6, 2, 12, 7, 0): la soluzione del corso dice 6, ma sono cinque. 80 (5 frame): LRU 8, OPT 7; tabella LRU/FIFO/OPT per 1-7 frame: 20/20/20, 18/18/15, 15/16/11, 10/14/8, 8/10/7, 7/10/7, 7/7/7.
Simulatore C. replace nframe rif...: caricata[k] (FIFO) e usata[k] (LRU); OPT cerca in avanti il primo uso; vittima con se mai più usata.
Tabelle in breve (F = fault). Ex. 38 (FIFO, 4 frame): fault su 2, 6, 3, 9, 10, 11, 12, 3, 2 (hit su 2, 9, 3): vittime nell'ordine 2, 6, 3, 9, 10. Ex. 39 (LRU, 3): fault su 8, 0, 10, 12, 9, 11, 3 (vittime 8, 0, 12, 9): 7. Ex. 40/57 (LRU, prepaginazione 0-3): fault su 15 (), 0 (), 11 (), 6 (), 4 (), 14 (): 6. Ex. 48 (FIFO, 4): fault su 0, 1, 4, 7, 3 (toglie 0), 0 (toglie 1): 6. Ex. 58 (OPT, 3): fault su 6, 2, 12, 7 (toglie 6), 0 (toglie 7), 6: 6; con 4 o più frame 5, come le pagine distinte 6, 2, 12, 7, 0 (il corso scrive 6, ma sono cinque). Ex. 80 (5 frame): LRU 8, OPT 7; LRU/FIFO/OPT per 1-7 frame: 20/20/20, 18/18/15, 15/16/11, 10/14/8, 8/10/7, 7/10/7, 7/7/7. Simulatore replace.c: per FIFO caricata[k] (istante di caricamento, non aggiornato dagli hit), per LRU usata[k] (ultimo accesso), per OPT cerca in avanti il prossimo uso ( se mai più usata); uscita page fault: 9, 8, 7 per l'ex. 38 con FIFO, LRU e OPT.
Come si costruisce una tabella. Una colonna per ogni riferimento, una riga per ogni frame, F sulla colonna dei fault. FIFO: vittima frame con l'istante di caricamento minore, gli hit non lo cambiano; LRU: vittima frame con l'ultimo accesso minore, gli hit lo aggiornano; OPT: per ogni pagina in memoria si cerca il primo riferimento successivo, vittima quella con il riferimento più lontano o inesistente (in caso di parità, il frame di indice minore). Con prepaginazione si parte con le pagine 0-3 già nei frame (0 la meno recente per LRU). Il minimo assoluto di fault è il numero di pagine distinte; più frame non peggiorano mai LRU e OPT (algoritmi a pila), FIFO può peggiorare (Belady).
Controllo con il simulatore. ./replace 4 2 6 3 2 9 10 9 3 11 12 3 2 stampa page fault: 9 (FIFO), 8 (LRU), 7 (OPT); righe rif frame... con <- page fault.
Errori tipici: hit che aggiornano FIFO; fault su pagina presente; prepaginazione ignorata; OPT sul passato; più frame non peggiorano sempre (solo algoritmi a pila).