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-04-demo.zip
și apoi decomprimăm arhiva
unzip curs-04-demo.zip
și accesăm directorul rezultat în urma decomprimării
cd curs-04-demo/
Acum putem parcurge secțiunile cu demo-uri de mai jos.
Dorim să vedem numărul de schimbări de context (voluntare sau nevoluntare) ale unei comenzi. Pentru aceasta rulăm comanda
/usr/bin/time -v find /var/log
Din output-ul comenzii de mai sus, extragem numărul de schimbări de context. Numerele de schimbări de context se găsesc, respectiv, pe liniile care încep cu Voluntary context switches, respectiv Involuntary context switches.
Rulăm din nou comanda
/usr/bin/time -v find /var/log
Observăm că acum, la a doua rulare, este semnificativ mai mic numărul schimbărilor voluntare. Aceasta se întâmplă deoarece se realizează, la prima rulare a comenzii, caching în memorie pentru date. Adică nu se mai execută operații blocante la dispozitivele de I/O, rezultând într-un număr mai mic de schimbări voluntare.
Dorim să comparăm numărul de schimbări de context pentru o comandă față de varianta acesteia cu redirectarea ieșirii standard la /dev/null
. Pentru aceasta rulăm comanda
/usr/bin/time -v find /var/log > /dev/null
Ce valori sunt acum afișate pentru cele două tipuri de schimbări de context?
Întrucât nu se mai lucrează cu terminalul aferent ieșirii standard, nu se execută multe operații blocante și nu se tranferă date generate de comandă în fișier. Rezultă direct un număr și mai mic de schimbări de context (atât voluntare cât și nevoluntare) și o durată de execuție mai mică a procesului.
Dorim să analizăm impactul configurării priorității statice (nice) a sistemului. Pentru aceasta vom porni același proces cu diverse valori pentru nice și vom observa durata de rulare.
Intrăm în directorul nice/
din arhiva cu demo-uri a cursului și parcurgem fișierele cpu.c
și start-all
. Fișierul cpu.c
execută operații care țin procesorul ocupat; fișierul start-all
este un script care pornește 6 procese cu diverse valori pentru nice.
Pentru a putea rula, începem prin compilarea programului cpu.c
folosind comanda
make
Pentru a testa scenariul rulăm scriptul:
./start-all
Scriptul va porni 6 procese cu valori diferite pentru nice
:
nice = -20
);nice = 0
, implicit);nice = 19
).Pentru fiecare proces, este reținut output-ul într-un fișier. Pentru a afla timpul fiecărui proces în fișierul rezultat, folosim comanda:
grep -H 'Elapsed' pri*
Observăm că procesele prioritare au avut cel mai scurt timp de rulare iar cele subprioritare cel mai lung timp. Planificatorul a ținut, așadar, cont de valoarea priorității statice (nice
).
Vrem să vedem cât timp durează pentru un proces să stea în coada READY. Pentru aceasta forțăm trecerea procesului din starea RUNNING în starea READY; ulterior, când va veni rândul său, procesul va fi planificat și va fi trecut din nou în starea RUNNING.
Forțarea trecerii procesului din starea RUNNING în starea READY se face cu ajutorul apelului sched_yield. Acesta eliberează procesorul curent și trece procesul în starea READY. Dacă nu există alt proces în starea READY, procesul curent va fi replanificat practic instant înapoi pe procesor.
Intrăm în directorul yield/
din arhiva cu demo-uri a cursului și parcurgem fișierele yield.c
și run-many
. Fișierul yield.c
execută operații care țin procesorul ocupat apoi apelează sched_yield
; în momentul apelării sched_yield
procesul este trecut din starea RUNNING în starea READY; în momentul în care procesul revine din sched_yield
, a fost replanificat, adică retrecut din starea READY în starea RUNNING; se rulează 10 runde. Fișierul run-many
este un script care pornește mai multe procese yield
; numărul de procese pornite este argumentul primit ca parametru.
Pentru a putea rula, începem prin compilarea programului yield.c
folosind comanda
make
În urma compilării obținem executabilul yield
.
Ca să pornim mai multe procese din executabil, rulăm pe rând scriptul run-many
cu un număr crescător dat ca parametru:
./run-many 1 ./run-many 2 ./run-many 3 ./run-many 4 ./run-many 5
Pentru rulările de la început durata apelului sched_yield
(adică tranziția RUNNING → READY și înapoi READY → RUNNING) este de 1-2 microsecunde. Practic este instantă schimbarea. De la o anumită valoare primită ca argument durata crește semnificativ pentru anumite apeluri (de ordinul miilor de microsecunde).
Motivul acestei creșteri este atingerea numărului de procesoare/core-uri ale sistemului. Fiecare core/procesor are coada proprie READY. Dacă se creează un număr de procese mai mic sau egal cu numărul de procesoare/core-uri ale sistemului atunci nu există competiție pe procesor; un proces este trecut în starea READY și apoi revine imediat în RUNNING.
În momentul în care există unele core-uri care au alocate mai multe procese atunci un proces în READY va aștepta ca un alt proces din RUNNING să elibereze procesorul (fie prin yielding, fie prin blocare, fie prin expirarea cuantei). De aici se observă creșterea duratei apelului sched_yield
.
Durata apelului sched_yield
este timpul de așteptare al procesului (waiting time), timp care se dorește să fie cât mai mic.
Dorim să creăm un exemplu simplu de folosire a pipe-urilor anonime pentru comunicare între procese înrudite.
Intrăm în directorul pipe/
din arhiva cu demo-uri a cursului și parcurgem fișierul pipe.c
.