Curs 04 - Planificarea execuției. IPC

Demo-uri

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.

Schimbări de context

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.

Schimbări de context pentru rulare cu redirectare

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.

Alterare prioritate proces

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:

  • 2 procese vor fi prioritare (nice = -20);
  • 2 procese vor avea prioritate medie (nice = 0, implicit);
  • 2 procese vor fi subprioritare (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).

Durată timp de așteptare în coada READY (yield)

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.

Folosire pipe-uri

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.

so/cursuri/curs-04.txt · Last modified: 2017/02/23 16:28 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