Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so:cursuri:curs-06 [2014/03/22 21:20]
razvan.deaconescu [Demo-uri]
so:cursuri:curs-06 [2019/03/24 14:10] (current)
razvan.deaconescu
Line 1: Line 1:
 ====== Curs 06 - Memoria virtuală ====== ====== Curs 06 - Memoria virtuală ======
- 
-<​html>​ 
-<iframe src="​http://​prezi.com/​embed/​qshrq7oeytj2/?​bgcolor=ffffff&​amp;​lock_to_path=0&​amp;​autoplay=0&​amp;​autohide_ctrls=0&​amp;​features=undefined&​amp;​disabled_features=undefined"​ width="​550"​ height="​400"​ frameBorder="​0"></​iframe>​ 
-</​html>​ 
  
   * [[http://​prezi.com/​qshrq7oeytj2/?​utm_campaign=share&​utm_medium=copy&​rc=ex0share | Curs 06 - Memoria virtuală (vizualizare Prezi)]]   * [[http://​prezi.com/​qshrq7oeytj2/?​utm_campaign=share&​utm_medium=copy&​rc=ex0share | Curs 06 - Memoria virtuală (vizualizare Prezi)]]
   * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-06.pdf | Curs 06 - Memoria virtuală (PDF)]]   * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-06.pdf | Curs 06 - Memoria virtuală (PDF)]]
 +
 +  * [[https://​drive.google.com/​open?​id=1jsFIY2bG2QssLX1X9AWn4_0Ec2x_hK9oOGohmFqKSRM|Notițe de curs]]
  
   * Suport curs   * Suport curs
     * Operating Systems Concepts Essentials     * Operating Systems Concepts Essentials
       * Capitolul 8 - Virtual Memory       * Capitolul 8 - Virtual Memory
-    * Modern Operating Systems+    * Modern Operating Systems, 2nd Ed.
       * Capitolul 4 - Memory Management       * Capitolul 4 - Memory Management
         * Secțiunile 4.4, 4.5         * Secțiunile 4.4, 4.5
 +    * Modern Operating Systems, 3rd Ed.
 +      * Capitolul 3 - Memory Management
 +        * Secțiunile 3.4, 3.5
 +    * [[http://​duartes.org/​gustavo/​blog/​post/​anatomy-of-a-program-in-memory/​|Anatomy of a Program in Memory]]
 +
 +<​html>​
 +  <​center>​
 +    <iframe src="​https://​prezi.com/​embed/​qshrq7oeytj2/?​bgcolor=ffffff&​amp;​lock_to_path=0&​amp;​autoplay=0&​amp;​autohide_ctrls=0&​amp;​features=undefined&​amp;​disabled_features=undefined"​ width="​550"​ height="​400"​ frameBorder="​0"></​iframe>​
 +  </​center>​
 +</​html>​
  
 ===== Demo-uri ===== ===== Demo-uri =====
Line 56: Line 64:
 ==== Investigarea mapării folosind pmap ==== ==== Investigarea mapării folosind pmap ====
  
-Vrem să vizualizăm spațiul virtual de adrese al unui proces. Pentru aceasta, accesăm subdirectorul ''​pmap'';​ urmărim conținutul fișierului ''​pmap.c'';​ facem mapări (folosind apelul ''​mmap''​) folosind diverse flag-uri.+Vrem să vizualizăm spațiul virtual de adrese al unui proces. Pentru aceasta, accesăm subdirectorul ''​pmap/'';​ urmărim conținutul fișierului ''​pmap.c'';​ facem mapări (folosind apelul ''​mmap''​) folosind diverse flag-uri.
  
 Compilăm programul folosind ''​make''​ și apoi îl rulăm:<​code bash> Compilăm programul folosind ''​make''​ și apoi îl rulăm:<​code bash>
Line 74: Line 82:
 </​spoiler>​ </​spoiler>​
  
-  - Alocarea de memorie virtuală +==== Alocarea de memorie virtuală ​==== 
-    * Intrați ​în directorul ​''​3-allocation/''​+ 
-    * Consultațfișierul ''​allocation.c''​. +Vrem să urmărim modul în care se alocă memorie virtuală în spațiul virtual de adrese al unui proces. Pentru aceasta, accesăm subdirectorul ​''​allocation/''​; urmărim conținutul ​fișierului ​''​allocation.c'';​ în cadrul fișierului se fac alocări de memorie virtuală folosind pe rând apelul ''​malloc''​ și apelul ''​mmap''​. 
-    * Compilați sursele ​folosind comanda ''​make''​. + 
-    * Deschideți ​o consolă nouă. +Compilăm fișierul ​folosind comanda ''​make''​. 
-    * Într-o consolă ​rulați ​executabilul aferent:<​code>​+ 
 +Deschidem ​o consolă nouă și rulăm în cele două console astfel: 
 +    * Într-o consolă ​rulăm ​executabilul aferent:<​code>​
 ./​allocation ./​allocation
 </​code>​ </​code>​
-    * Într-o altă consolă ​vizualizați ​dimensiunea spațiului fizic ocupat și a a spatiului virtual ocupat, folosind comanda:<code bash>+    * Într-o altă consolă ​vizualizăm ​dimensiunea spațiului fizic ocupat și a a spatiului virtual ocupat, folosind comanda<​code bash>
 watch -n 1 ps -o pid,​rss,​vsz,​cmd -p $(pidof allocation) watch -n 1 ps -o pid,​rss,​vsz,​cmd -p $(pidof allocation)
 </​code>​ </​code>​
-    * Observați cum crește dimensiunea spațiului fizic și a spatiului virtual în cazul folosirii ''​malloc''​ și **doar** a spațiului virtual folosind ''​mmap''​. + 
-      * Cum explicați acest comportament+Observați cum crește dimensiunea spațiului fizic și a spatiului virtual în cazul folosirii ''​malloc''​ și **doar** a spațiului virtual folosind ''​mmap''​. 
-    * Rulați ​executabilul prin ''​strace'':<​code>​+ 
 +Pentru a explica acest comportament, rulăm ​executabilul prin ''​strace'':<​code>​
 strace ./​allocation strace ./​allocation
 </​code>​ </​code>​
-      * Ce apel de sistem invocă funcția ''​malloc''​+ 
-      * Dar funcția ''​mmap''​+Observăm că în cazul funcției de bibliotecă ​''​malloc'' ​se realizează apelul de sistem ''​brk'',​ în timp ce în cazul funcției de bibliotecă ​''​mmap'' ​se realizează apelul de sistem ''​mmap''​. Apelul de sistem ''​mmap''​ alocă ​**doar** memorie virtuală. 
-      ​De ce, la 1024 de apeluri ​ale funcției ​''​malloc'' ​sunt mai puține apeluri ​de sistem? + 
-    * Actualizațcodul astfel încât ''​malloc''​ să aloce, la fel ca și ''​mmap''​ calupuri de ''​1MB''​ de memorie. +Observăm de asemeneacă se realizează un număr redus de apeluri de sistem ''​brk''​ raportat ​la cele ''​1024'' ​de apeluri ​de bibliotecă ​''​malloc''​. Un apel ''​brk''​ alocă un pool mai mare de memorie care va fi apoi folosit la apeluri viitoare ''​malloc'';​ realizează o prealocare. 
-    Compilați ​noua sursă folosind comanda ''​make''​. + 
-    * Rulați ​executabilul într-o consolă și comanda de vizualizare în altă consolă. +Pentru a vedea comportamentului funcției de bibliotecă ''​malloc'',​ actualizăm ​codul astfel încât ''​malloc''​ să aloce, la fel ca ''​mmap''​ calupuri de ''​1MB''​ de memorie. ​Adică bucla ''​for''​ aferentă să arate așa:<​code c> 
-      * Ce observați+ for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { 
-      ​Cum vă explicați acest comportament?​ + puts("​Using malloc to allocate 1024 sets of 1024 bytes."​);​ 
-    * Rulați executabilul nou prin ''​strace''​. + p = malloc(1024*1024); 
-      * Ce apel de sistem invocă **acum** funcția ''​malloc''​+ DIE(p == NULL, "​malloc"​);​ 
-      * Comparați ​apelul de sistem ​(și argumentele acestuia) invocat acum de ''​malloc'' ​cu apelul de sistem ​și argumentele acestuia invocate ​de ''​mmap''​. + sleep(2);​ 
-  ​Paginare la cerere (demand paging) +
-    * Intrați ​în directorul ​''​4-demand-paging/''​+</​code>​ 
-    * Consultațfișierul ''​demand-paging.c''​. + 
-    * Compilați sursele ​folosind comanda ''​make''​. +Compilăm ​noua sursă folosind comanda ''​make''​. ​La fel ca mai devreme rulăm ​executabilul într-o consolă și comanda de vizualizare în altă consolă. ​Observăm că acum atât funcția de bibliotecă ''​malloc'',​ cât șfuncția de bibliotecă ''​mmap''​ alocă ​**doar** memorie virtuală. 
-    * Deschideți o consolă nouă. + 
-    * Într-o consolă ​rulați ​executabilul aferent:<​code>​+Folosim în continuare ​''​strace'' ​pentru a investiga:<​code bash> 
 +strace ​./allocation 
 +</​code>​ 
 + 
 +Observăm că acum și funcția ​de bibliotecă ​''​malloc'' ​folosește în spate tot apelul de sistem ​''​mmap''​. Acesta alocă doar memorie virtuală de unde și comportamentul. De la o valoare dată, alocarea cu ''​malloc'' ​folosește ​apelul de sistem ​''​mmap''​. 
 + 
 +<spoiler Despre apelul malloc>​ 
 +Valoarea ​de la care funcția de bibliotecă ''​malloc''​ folosește ​''​mmap''​ este definită de ''​MMAP_THRESHOLD'',​ în mod implicit configurat la ''​128KB''​. ​Detalii se găsesc în [[http://​man7.org/​linux/​man-pages/​man3/​malloc.3.html#​NOTES|pagina de manual a malloc]]:<​code>​ 
 +       Normally, malloc() allocates memory from the heap, and adjusts the 
 +       size of the heap as required, using sbrk(2). ​ When allocating blocks 
 +       of memory larger than MMAP_THRESHOLD bytes, the glibc malloc() 
 +       ​implementation allocates the memory as a private anonymous mapping 
 +       using mmap(2). ​ MMAP_THRESHOLD is 128 kB by default, but is 
 +       ​adjustable using mallopt(3). ​ Allocations performed using mmap(2) are 
 +       ​unaffected by the RLIMIT_DATA resource limit (see getrlimit(2)). 
 +</​code>​ 
 +</​spoiler>​ 
 + 
 +==== Paginare la cerere (demand paging) ​==== 
 + 
 +Vrem să urmărim modul în care se alocă pagini de memorie fizică la cerere, proces care se numește ''​(on) demand paging''​. Pentru aceasta, accesăm subdirectorul ​''​demand-paging/''​; urmărim conținutul ​fișierului ​''​demand-paging.c''​; în cadrul fișierului alocăm memorie virtuală folosind ''​mmap''​ și apoi accesăm primul octet al fiecărei pagini alocate
 + 
 +Compilăm codul sursă ​folosind comanda ''​make''​. 
 + 
 +Avem nevoie de două console: 
 +  * Într-o consolă ​rulăm ​executabilul aferent:<​code>​
 ./​demand-paging ./​demand-paging
 </​code>​ </​code>​
-    ​* Într-o altă consolă ​vizualizați ​dimensiunea spațiului fizic ocupat și a a spatiului virtual ocupat, folosind comanda:<​code bash>+  ​* Într-o altă consolă ​vizualizăm ​dimensiunea spațiului fizic ocupat și a a spatiului virtual ocupat, folosind comanda:<​code bash>
 watch -n 1 ps -o pid,​rss,​vsz,​cmd -p $(pidof demand-paging) watch -n 1 ps -o pid,​rss,​vsz,​cmd -p $(pidof demand-paging)
 </​code>​ </​code>​
-    * Observați ​cum crește dimensiunea spațiului spatiului virtual fără a crește dimensiunea spațiului fizic în prima parte. + 
-      * Observați cum crește dimensiunea spațiului fizic în a doua parte (fără a crește dimensiunea spațiului virtual). +Observăm ​cum crește dimensiunea spațiului spatiului virtual ​(coloana ''​VSZ''​) ​fără a crește dimensiunea spațiului fizic în prima parte. ​Se face alocare de memorie virtuală, fără paginare - adică fără alocare de spațiu fizic aferent. În partea a doua, observați cum crește dimensiunea spațiului fizic (coloana ''​RSS''​) ​în a doua parte (fără a crește dimensiunea spațiului virtual). ​Aceasta este //(on) demand paging//, cu alocarea paginilor fizice necesare la nevoie. 
-    * Într-o consolă ​rulați ​executabilul aferent:<​code>​+ 
 +Ca să detaliem, urmărim page fault-urile realizate pe parcursul rulării programului. Folosim, la fel, două console: 
 +  * Într-o consolă ​rulăm ​executabilul aferent:<​code>​
 ./​demand-paging ./​demand-paging
 </​code>​ </​code>​
-    ​* Într-o altă consolă ​vizualizați ​numărul de page fault-uri generate de program (''​min_flt''​ este coloana de interes, ''​maj_flt''​ este pentru interacțiuni cu discul -- swapping):<​code bash>+  ​* Într-o altă consolă ​vizualizăm ​numărul de page fault-uri generate de program (''​min_flt''​ este coloana de interes, ''​maj_flt''​ este pentru interacțiuni cu discul -- swapping):<​code bash>
 watch -n 1 ps -o pid,​min_flt,​maj_flt,​cmd -p $(pidof demand-paging) watch -n 1 ps -o pid,​min_flt,​maj_flt,​cmd -p $(pidof demand-paging)
 </​code>​ </​code>​
-    * Observați cum nu există page fault-uri în prima pare a rulării programului+Observați cum nu există page fault-uri în prima pare a rulării programului, în momentul în care facem mapări de memorie. Dar apar page fault-uri în a doua parte a rulării programului. 
-      * Observați cum există page fault-uri în a doua parte a rulării programului. + 
-      ​* ​Câte page fault-uri sunt generate la o "​trecere prin chunk"?​ De ce? +Câte page fault-uri sunt generate la o "​trecere prin chunk"?​ De ce? 
-  - Page-Faulturi + 
-    * Intrați ​în directorul ​''​5-fork-faults/''​+<spoiler Răspuns>​ 
-    * Consultațfișierului ''​fork-faults.c''​. +Se generează 256 page fault-uri. Asta se întâmplă pentru ca la fiecare "​trecere prin chunk" se accesează 256 pagini, fiecare pagină având câte 4KB, pentru un total de 1MB. Un page fault înseamnă alocarea (on demand) a unei pagini fizice. 
-    * **Câte page-fault-uri** credeți că se realizează la rulare? +</​spoiler>​ 
-    * Compilați ​fișierul+ 
-    * Rulați programul ​''​fork-faults''​. +==== Page fault-uri la fork (copy-on-write) ==== 
-    * Folosiț''​ENTER''​ pentru a continua programul, dar după rularea ''​pidstat''​ (vedeți ​mai jos). + 
-    * Pe un alt terminal sau tab de terminal folosiți ​utilitarul ''​pidstat''​ din pachetul ''​sysstat''​ care permite monitorizarea page fault-urilor unui proces (prin intermediul argumentului ''​-r''​). +Vrem să urmărim realizarea page fault-urilor ​în urma unui apel ''​fork'';​ page fault-urilor vor fi cauzate de mecanismul de copy-on-write în momentul în care unul dintre cele două procese (copil sau părinte) scrie în zona respectivă. Pentru aceasta, accesăm subdirectorul ''​fork-faults''​; urmărim conținutul ​fișierului ''​fork-faults.c''​. ​În cadrul fișierului ''​fork-faults.c''​ se execută următorii pași: 
-      * Dacă nu merge comanda ''​pidstat''​ trebuie să instalați ​pachetul ''​sysstat''​ folosind comanda:<​code bash>+  - se alocă memorie virtuală folosind ''​mmap''​ 
 +  - se alocă memorie fizică pentru paginile de mai sus, folosind //(on) demand paging// prin accesarea primului octet al fiecărei pagini 
 +  - se creează un proces nou 
 +  - procesul copil citește valoarea din prima jumătate a numărului de pagini (**doar** citește) 
 +  ​procesul copil scrie o valoare în cadrul fiecărei pagini din a două jumătate 
 +  ​procesul părinte scrie o valoare în toate paginile 
 + 
 +Ca să urmărim ce se întâmplă, compilăm ​fișierul ​folosind ​''​make''​. ​Apoi rulăm programul obținut:<​code bash> 
 +./​fork-faults 
 +</​code>​ Folosim ​''​ENTER''​ pentru a continua programul, dar după rularea ''​pidstat''​ (mai jos). 
 + 
 +Într-o ​altă consolă folosim ​utilitarul ''​pidstat''​ din pachetul ''​sysstat''​ care permite monitorizarea page fault-urilor unui proces (prin intermediul argumentului ''​-r''​). Dacă nu există ​comanda ''​pidstat''​ trebuie să instalăm ​pachetul ''​sysstat''​ folosind comanda:<​code bash>
 apt-get install sysstat apt-get install sysstat
 </​code>​ </​code>​
-    * Folosiți comanda <code bash>+ 
 +Pentru a rula ''​pidstat''​ șa urmări page fault-urile,​ folosim, pe a doua consolă, ​comanda<​code bash>
 pidstat -r -T ALL -p $(pidof fork-faults) 5 100 pidstat -r -T ALL -p $(pidof fork-faults) 5 100
-</​code> ​pentru a urmări page fault-urile. +</​code>​ Comanda de mai sus afișează câte un mesaj la fiecare 5 secunde. ​În prima consolă ​apăsăm ''​ENTER'' ​pentru a continua rularea și urmărim informațiile ​afișate de ''​pidstat''​, apoi continuăm apăsarea ''​ENTER''​ etc
-      * Comanda de mai sus vă afișează câte un mesaj la fiecare 5 secunde. ​Sincronizați ​apăsarea tastei ​''​ENTER'' ​cu afișajul comenzii ​''​pidstat''​. + 
-    ​* ​Urmăriți evoluția numărului de page fault-uri pentru cele două procese: părinte și copil. +Urmărim, în outputul comenzii ''​pidstat'', ​evoluția numărului de page fault-uri pentru cele două procese: părinte și copil. Page fault-urile care apar în cazul unui copy-on-write în procesul copil vor fi vizibile ulterior și în procesul părinte. Observăm că procesul copil generează page fault-uri doar pe jumătate din pagini (cele în care scrie), iar procesul părinte generează page fault-uri pe toate paginile. Asta pentru că un proces creează o copie a paginilor inițiale, dar lasă acele pagini ''​read-only'',​ iar alt proces primește page fault dar doar schimbă permisiunile din read-only în read-write.
-      * Page fault-urile care apar în cazul unui copy-on-write în procesul copil vor fi vizibile ulterior și în procesul părinte.+
so/cursuri/curs-06.1395516054.txt.gz · Last modified: 2014/03/22 21:20 by razvan.deaconescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0