Salta al contenuto
Note per Studenti Esercizio - Programmi che scorrono array, stringhe di riferimenti e page fault (eserciziario, esercizi 50, 73 e 77)

Esercizio - Programmi che scorrono array, stringhe di riferimenti e page fault (eserciziario, esercizi 50, 73 e 77)

In questa pagina 5

Testo (eserciziario del corso di Sistemi Operativi, Ing. Informatica UniPD).

  • Esercizio 50. Matrice int A[100][100], con la posizione A[0][0] alla locazione 200 di una memoria paginata con 3 pagine di 200 B. Un valore int occupa 1 B; le pagine sono inizialmente vuote e il processo (il cui codice occupa esattamente 200 B) esegue for (i = 0; i < 100; i++) for (j = 0; j < 100; j++) A[i][j] = 0;. Quanti page fault con LRU? (Ogni pagina contiene 200 elementi della matrice.)
  • Esercizio 73. Il sistema di paginazione assegna 3 frame da 512 B a ogni processo. Programma: #define N 512, int A[N], C[N], for (i = 1; i <= 2; i++) for (j = 0; j < N/2; j++) A[i*j] = A[2*i] + C[2*j];. Un intero è rappresentato con 2 B. Gli array AA e CC occupano 1024 B ciascuno, in 2 pagine da 512 B: A[0..255] pagina 0, A[256..511] pagina 1, C[0..255] pagina 2, C[256..511] pagina 3. (1) Stringa dei riferimenti alle pagine della memoria. (2) Tabella delle pagine al termine della procedura con avvicendamento (i) FIFO, (ii) LRU.
  • Esercizio 77. 3 frame da 512 B a ogni processo, algoritmo LRU. Programma: #define N 512, int a[N], for (i = 0; i < N/2; i++) a[i] = a[2*i] + a[N-i-1];. (a) Se un intero è di 4 B, quanti page fault? (b) Se il tempo medio di servizio di un page fault è di 25 ms e l'accesso alla memoria 100 μ\mus, qual è il tempo di accesso medio della paginazione su richiesta? Le pagine sono da 512 B e ogni intero è di 4 B (128 elementi per pagina): a[0..127] pagina 0, a[128..255] pagina 1, a[256..383] pagina 2, a[384..511] pagina 3.

Teoria: Memoria virtuale - paginazione su richiesta e sostituzione delle pagineLa memoria virtuale separa la memoria logica da quella fisica: basta che alcune pagine siano in RAM; con la paginazione su richiesta (demand paging) una pagina si carica solo al primo riferimento, e un riferimento a una pagina non residente (bit di validità = i) genera un page fault gestito dal sistema operativo in sei passi; EAT = (1 - p) * accesso + p * servizio del fault, con p minuscolo; copy-on-write rende economica la fork; se non ci sono frame liberi si sceglie una vittima con FIFO (anomalia di Belady), OPT (ottimo, irrealizzabile), LRU (algoritmo a stack), second chance (bit di riferimento, orologio) o la versione con bit di modifica; i frame si assegnano in modo uguale o proporzionale, con sostituzione globale o locale; se un processo non ha abbastanza frame va in thrashing; il modello del working set e la frequenza dei page fault lo evitano; considerazioni su prepaging, dimensione della pagina, TLB reach e struttura dei programmi; memoria del kernel con buddy system e slab.Memoria virtuale - paginazione su richiesta e sostituzione delle pagine →.


Il metodo

  1. Si scrive l'ordine in cui il programma tocca la memoria, istruzione per istruzione: di solito prima le letture (nell'ordine di valutazione) e poi la scrittura.
  2. Per ogni indice, si calcola la pagina: ⌊indice⋅byte per elemento/dimensione pagina⌋\lfloor\text{indice}\cdot\text{byte per elemento}/\text{dimensione pagina}\rfloor (o, per le matrici, la posizione lineare in memoria).
  3. Si comprime la stringa dei riferimenti (accessi consecutivi alla stessa pagina non contano come nuovi fault) e si applica l'algoritmo di sostituzione.

Esercizio 50 (matrice per righe, LRU, 3 frame)

La matrice è memorizzata per righe: A[0][0], A[0][1], …, A[99][99]. Ha 100⋅100=10 000100\cdot100=10\,000 elementi da 1 B e comincia alla locazione 200: occupa le locazioni da 200 a 10 199, cioè 10 000/200=5010\,000/200=50 pagine, a partire dalla pagina 1 (la pagina 0, le locazioni 0-199, contiene il codice).

Ad ogni iterazione si accede al codice (pagina 0, per leggere l'istruzione) e a un elemento di A. Poiché ad ogni passo si riferisce la pagina 0, questa è sempre la più recente: non viene mai scelta come vittima. Delle altre due pagine si alternano i due frame:

  • i primi 200 azzeramenti (A[0][0]…A[1][99], righe 0 e 1) accedono alla pagina 1;
  • i successivi 200 alla pagina 2, e così via: ogni 200 elementi si cambia pagina.

Page fault: 1 per caricare il codice (pagina 0) e 50 (una per ciascuna delle 50 pagine della matrice, quando vi si accede la prima volta), in totale

1+50=51 page fault.1+50=\mathbf{51\ page\ fault}.

La pagina matrice usata meno di recente è quella vecchia, quindi la sostituzione toglie sempre una pagina già finita di scorrere. Il valore è lo stesso (51) per la soluzione del corso.

(Se la matrice fosse scandita per colonne, for j … for i …, ogni elemento sarebbe in una pagina diversa dal precedente: salti di 100 posizioni, due righe ogni pagina: molti più fault; il caso esteso è nel laboratorio 7.)

Esercizio 73

(1) Stringa dei riferimenti. Ogni iterazione calcola A[i*j] = A[2*i] + C[2*j] e quindi legge A[2*i], legge C[2*j] e scrive A[i*j].

  • A[2*i]: con i=1i=1 è A[2] (pagina 0); con i=2i=2 è A[4] (pagina 0).
  • C[2*j]: 2j<2562j<256 per j<128j<128 (pagina 2), 2j≥2562j\ge256 per j≥128j\ge128 (pagina 3).
  • A[i*j]: con i=1i=1 è A[j], indice <256<256: pagina 0. Con i=2i=2 è A[2j]: pagina 0 per j<128j<128, pagina 1 per j≥128j\ge128 (2j∈[256,510]2j\in[256,510]).
ii jj riferimenti per iterazione iterazioni
1 0-127 0 2 0 128
1 128-255 0 3 0 128
2 0-127 0 2 0 128
2 128-255 0 3 1 128

Stringa compressa: (0 2 0)128 (0 3 0)128 (0 2 0)128 (0 3 1)128(0\,2\,0)^{128}\,(0\,3\,0)^{128}\,(0\,2\,0)^{128}\,(0\,3\,1)^{128}.

(2) Tabella delle pagine. I frame sono 3.

FIFO (5 fault):

  • primo accesso alla pagina 0: fault; poi la pagina 2: fault (i=1,j=0i=1,j=0);
  • i=1,j=128i=1,j=128: la pagina 3 entra nel terzo frame: fault. Ora i frame hanno 0, 2, 3 (in ordine di caricamento: 0 la più vecchia);
  • i=2,j=128i=2,j=128: la pagina 1 è nuova: fault; FIFO toglie la 0 (la più vecchia);
  • subito dopo la pagina 0 serve di nuovo (iterazione j=129j=129): fault; FIFO toglie la 2.

Totale 5 fault. Alla fine in memoria: pagine 1, 0, 3 (la 2 non c'è più).

LRU (4 fault): come FIFO fino a i=2,j=128i=2,j=128. Qui si deve inserire la 1; nella stessa iterazione le pagine 0 (A[4]) e 3 (C[256]) sono appena state riferite, quindi la meno recente fra 0, 2, 3 è la 2: LRU toglie la 2 e non la 0, e non c'è il fault aggiuntivo. Totale 4 fault. Alla fine in memoria: pagine 0, 1, 3.

La differenza è in una pagina (la 0) riferita continuamente: FIFO guarda solo quando è stata caricata (per prima), LRU guarda che è sempre in uso.

Esercizio 77

(a) Gli elementi a[0..127] sono nella pagina 0, a[128..255] nella 1, a[256..383] nella 2, a[384..511] nella 3. Ogni iterazione riferisce a[2*i], a[N-i-1] e scrive a[i]: tre riferimenti, in totale 256⋅3=768256\cdot3=768 riferimenti.

ii a[2*i] a[N-i-1] a[i]
0-63 pagina 0 (2i<1282i<128) pagina 3 (511−i≥448511-i\ge448) pagina 0
64-127 pagina 1 (128≤2i<256128\le2i<256) pagina 3 pagina 0
128-191 pagina 2 (256≤2i<384256\le2i<384) pagina 2 (320≤511−i≤383320\le511-i\le383) pagina 1
192-255 pagina 3 (384≤2i<512384\le2i<512) pagina 2 (256≤511−i≤319256\le511-i\le319) pagina 1

Con LRU e 3 frame:

  1. i=0i=0: la pagina 0 (fault), la 3 (fault);
  2. i=64i=64: la pagina 1 (fault): frame 0, 3, 1; da qui ii fino a 127 si usano 0, 1, 3;
  3. i=128i=128: a[256] è nella pagina 2 (fault): si toglie la meno recente, la 1; ma la scrittura a[128] della stessa iterazione richiede subito la pagina 1, quindi un altro fault, che toglie la meno recente fra 0, 3, 2, cioè la 3;
  4. i=192i=192: la pagina 3 (fault, si toglie la 0 non più usata).

In totale 6 page fault, e 768−6=762768-6=762 riferimenti validi (senza fault). (Il risultato coincide con la soluzione del corso: 6 fault e 762 riferimenti.)

(b) Tempo medio di accesso con paginazione su richiesta:

EAT=6768⋅25 ms+762768⋅100 μs=0,1953 ms+0,0992 ms=0,2945 ms≈0,294 ms.\text{EAT}=\frac{6}{768}\cdot25\ \text{ms}+\frac{762}{768}\cdot100\ \mu\text{s}=0{,}1953\ \text{ms}+0{,}0992\ \text{ms}=0{,}2945\ \text{ms}\approx\mathbf{0{,}294\ ms}.

(La soluzione scrive 0,294⋅10−30{,}294\cdot10^{-3} s.)


Errori tipici

  • Dimenticare l'accesso al codice nell'esercizio 50: la pagina 0 occupa un frame e si carica una volta.
  • Compressione sbagliata della stringa: accessi consecutivi alla stessa pagina sono hit, non nuovi riferimenti da ripetere.
  • Calcolare la pagina di A[i*j] senza distinguere i=1i=1 e i=2i=2 nell'esercizio 73.
  • Non scrivere la scrittura a[i] fra i riferimenti.

Versione ripasso

Metodo. Elencare gli accessi (letture poi scrittura), calcolare la pagina di ognuno, comprimere gli accessi consecutivi alla stessa pagina, applicare FIFO/LRU.

50. Matrice 100x100 byte da 200 (50 pagine), pagina 0 con il codice, 3 frame, LRU: la pagina 0 è sempre la più recente; ogni 200 elementi cambia pagina: 1+50=511+50=51 fault.

73. A[i*j]=A[2*i]+C[2*j], pagine 0, 1 (AA) e 2, 3 (CC). Riferimenti: (0 2 0)128(0 3 0)128(0 2 0)128(0 3 1)128(0\,2\,0)^{128}(0\,3\,0)^{128}(0\,2\,0)^{128}(0\,3\,1)^{128}. FIFO: 5 fault (la 1 toglie la 0, poi la 0 toglie la 2); finale 1, 0, 3. LRU: 4 fault (la 1 toglie la 2); finale 0, 1, 3.

77. a[i]=a[2*i]+a[N-i-1], 128 interi per pagina, 768 riferimenti, LRU 3 frame: 6 fault, 762 senza fault. EAT=6768⋅25 ms+762768⋅100 μs≈0,294\text{EAT}=\frac6{768}\cdot25\text{ ms}+\frac{762}{768}\cdot100\ \mu\text{s}\approx0{,}294 ms.

Passaggi. 73: letture A[2*i], C[2*j], scrittura A[i*j]; pagina =⌊indice⋅2/512⌋=\lfloor\text{indice}\cdot2/512\rfloor; i=2i=2, j≥128j\ge128: A[2*j] in pagina 1. Frame dopo i=1i=1, j=128j=128: 0, 2, 3. FIFO: 1 toglie 0 (la più vecchia), poi 0 toglie 2 →\to 5 fault, finale 1, 0, 3. LRU: 1 toglie 2 →\to 4 fault, finale 0, 1, 3. 77: 768 riferimenti; i∈[0,63]i\in[0,63] pagine 0, 3, 0; [64,127][64,127] 1, 3, 0; [128,191][128,191] 2, 2, 1; [192,255][192,255] 3, 2, 1; fault a i=0i=0 (pagine 0 e 3), i=64i=64 (pagina 1), i=128i=128 (pagine 2 e di nuovo 1), i=192i=192 (pagina 3) →6\to6; EAT=0,1953+0,0992=0,2945\text{EAT}=0{,}1953+0{,}0992=0{,}2945 ms. 50: matrice da 10 000 byte a partire da 200: 50 pagine (1-50) più il codice: 51 fault.

Errori tipici: dimenticare il codice (ex. 50); stringa non compressa; pagina di A[i*j] senza distinguere ii; scrittura dimenticata.

Teoria: Memoria virtuale - paginazione su richiesta e sostituzione delle pagineLa memoria virtuale separa la memoria logica da quella fisica: basta che alcune pagine siano in RAM; con la paginazione su richiesta (demand paging) una pagina si carica solo al primo riferimento, e un riferimento a una pagina non residente (bit di validità = i) genera un page fault gestito dal sistema operativo in sei passi; EAT = (1 - p) * accesso + p * servizio del fault, con p minuscolo; copy-on-write rende economica la fork; se non ci sono frame liberi si sceglie una vittima con FIFO (anomalia di Belady), OPT (ottimo, irrealizzabile), LRU (algoritmo a stack), second chance (bit di riferimento, orologio) o la versione con bit di modifica; i frame si assegnano in modo uguale o proporzionale, con sostituzione globale o locale; se un processo non ha abbastanza frame va in thrashing; il modello del working set e la frequenza dei page fault lo evitano; considerazioni su prepaging, dimensione della pagina, TLB reach e struttura dei programmi; memoria del kernel con buddy system e slab.Memoria virtuale - paginazione su richiesta e sostituzione delle pagine →.

Teoria collegata