This is an old revision of the document!
Pentru parcurgerea demo-urilor, folosim arhiva aferentă. Demo-urile rulează pe Linux. Descărcăm arhiva folosind comanda
wget http://elf.cs.pub.ro/so/res/cursuri/curs-06-demo.zip
și apoi decomprimăm arhiva
unzip curs-06-demo.zip
și accesăm directorul rezultat în urma decomprimării
cd curs-06-demo/
Acum putem parcurge secțiunile cu demo-uri de mai jos.
Dorim să investigăm modul în care se alocă variabilele într-un executabil. Pentru aceasta accesăm subdirectorul exec-vars/
; urmărim conținutul fișierului exec-vars.c
. În acest fișier definim/alocăm variabile în diverse forme: dinamic, static, global. Vrem să vedem cum sunt acestea alocate în executabil și în proces.
Compilăm programul folosind make
.
Investigăm zonele de memorie din executabil în care sunt salvate variabilele, folosind comanda
objdump -t addr-space | grep var
De ce apar doar unele variabile?
Ce semnfică l
și g
în output-ul obținut?
Pentru a afișa conținutul zonei .rodata
folosind comanda
readelf -x .rodata addr-space
Secțiunea .rodata
conține variabile read-only, în cazul de față literalul rulz
. Literalii și constantele se stocează în secțiunea .rodata
a unui executabil.
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:
./pmap
Într-o altă consolă urmărim schimbările din spațiul virtual de adrese al procesului creat folosind comanda
watch -d pmap $(pidof pmap)
Comanda de mai sus urmărește spațiul virtual de adrese. Ca să generăm schimbări în spațiul virtual de adrese, apăsăm ENTER
în consola în care rulează programul pentru a continua pașii din cod.
Urmărim modificările care apar în urma diferitelor tipuri de mapare din cod. Observăm că se mapează câte o singură pagină; la fiecare operație de mapare spațiul total crește cu 4K, iar la fiecare operație de demapare spațiul total scade cu 4K. Observăm că în cazul mapării partajate permisiunile sunt rw-s
; s
înseamnă shared. Tot în cazul memoriei partajate apare mapat dispozitivul /dev/zero
, unul dintre modurile uzuale de a face mapare partajată.
De ce unele biblioteci sunt mapate cu permisiuni de scriere?
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
.
Compilăm fișierul folosind comanda make
.
Deschidem o consolă nouă și rulăm în cele două console astfel:
./allocation
watch -n 1 ps -o pid,rss,vsz,cmd -p $(pidof allocation)
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
.
Pentru a explica acest comportament, rulăm executabilul prin strace
:
strace ./allocation
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ă.
Observăm de asemenea, că 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.
Pentru a vedea comportamentului funcției de bibliotecă mallooc
, 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:
for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { puts("Using malloc to allocate 1024 sets of 1024 bytes."); p = malloc(1024*1024); DIE(p == NULL, "malloc"); sleep(2); }
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 și funcția de bibliotecă mmap
alocă doar memorie virtuală.
Folosim în continuare strace
pentru a investiga:
strace ./allocation
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 un valoare dată, alocarea cu malloc
folosește apelul de sistem mmap
.
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:
./demand-paging
watch -n 1 ps -o pid,rss,vsz,cmd -p $(pidof demand-paging)
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.
Ca să detaliem, urmărim page fault-urile realizate pe parcursul rulării programului. Folosim, la fel, două console:
./demand-paging
min_flt
este coloana de interes, maj_flt
este pentru interacțiuni cu discul – swapping):watch -n 1 ps -o pid,min_flt,maj_flt,cmd -p $(pidof demand-paging)
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.
Câte page fault-uri sunt generate la o “trecere prin chunk”? De ce?
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.
5-fork-faults/
.fork-faults.c
.fork-faults
.ENTER
pentru a continua programul, dar după rularea pidstat
(vedeți mai jos).pidstat
din pachetul sysstat
care permite monitorizarea page fault-urilor unui proces (prin intermediul argumentului -r
).pidstat
trebuie să instalați pachetul sysstat
folosind comanda:apt-get install sysstat
pidstat -r -T ALL -p $(pidof fork-faults) 5 100
pentru a urmări page fault-urile.
ENTER
cu afișajul comenzii pidstat
.