Differences

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

Link to this comparison view

so:cursuri:curs-10 [2014/04/14 18:13]
razvan.deaconescu created
so:cursuri:curs-10 [2019/04/20 20:24] (current)
razvan.deaconescu
Line 1: Line 1:
 ====== Curs 10 - Dispozitive de intrare/​ieșire ====== ====== Curs 10 - Dispozitive de intrare/​ieșire ======
  
-<​html>​ +  * [[http://​prezi.com/​z_hkmewcaqm_/?​utm_campaign=share&utm_medium=copy&rc=ex0share|Curs 10 -  Dispozitive de Intrare/Iesire (Prezi)]] 
-<iframe src="http://​prezi.com/embed/​z_hkmewcaqm_/?​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> +  * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-10.pdf|Curs 10 - Dispozitive de Intrare/Iesire (PDF)]]
-</html>+
  
-  * [[http://prezi.com/z_hkmewcaqm_/present/?auth_key=qr031kg&​follow=n6sg-tqs2wm6&​kw=present-z_hkmewcaqm_&​rc=ref-37087337 ​Curs 09 -  Dispozitive ​de Intrare/​Iesire (Prezi)]] +  * [[https://docs.google.com/document/d/1dc5Kaamjo6WPy7LABkBGTcxjVwgl3JbnlHnE0iREmwM/​edit?usp=sharing|Notițe ​de curs]]
-  * [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​SO_Curs-09.pdf | Curs 09 - Dispozitive de Intrare/​Iesire (PDF)]]+
  
   * Suport curs   * Suport curs
-    * Operating Systems Concepts +    * Operating Systems Concepts ​Essentials 
-    * Capitolul ​13 -- I/O Systems +      * Capitolul ​11 -- Mass Storage Structure 
-    * Capitolul 12 -- Mass Storage Structure +        * Secțiunile ​11.2, 11.4, 11.7 
-      * Secțiunile ​12.2, 12.4, 12.7+      * Capitolul 12 -- I/O Systems
     * Modern Operating Systems     * Modern Operating Systems
       * Capitolul 5 -- Input/​Output       * Capitolul 5 -- Input/​Output
         * Secțiunile 5.1, 5.2, 5.3         * Secțiunile 5.1, 5.2, 5.3
         * Subsecțiunile 5.4.1, 5.4.3         * Subsecțiunile 5.4.1, 5.4.3
 +
 +<​html>​
 +  <​center>​
 +    <iframe src="​https://​prezi.com/​embed/​z_hkmewcaqm_/?​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 =====
 +
 +Pentru parcurgerea demo-urilor,​ folosim [[http://​elf.cs.pub.ro/​so/​res/​cursuri/​curs-10-demo.zip|arhiva aferentă]]. Demo-urile rulează pe Linux. Descărcăm arhiva folosind comanda<​code bash>
 +wget http://​elf.cs.pub.ro/​so/​res/​cursuri/​curs-10-demo.zip
 +</​code>​ și apoi decomprimăm arhiva<​code bash>
 +unzip curs-10-demo.zip
 +</​code>​ și accesăm directorul rezultat în urma decomprimării<​code bash>
 +cd curs-10-demo/​
 +</​code>​
 +
 +Acum putem parcurge secțiunile cu demo-uri de mai jos.
 +
 +==== Investigare întreruperi ====
 +
 +Dorim să investigăm livrarea întreruperilor hardware către sistemul local. Vom urmări întreruperea de ceas (timer) și întreruperea de tastatură.
 +
 +În Linux fișierul care afișează informații despre tastatură este ''/​proc/​interrupts''​. În acest fișier sunt afișate informații statistice despre întreruperilor livrate, câte o coloană pentru fiecare procesor. În cadrul fișierului găsim informații și despre întreruperea de ceas și cea de tastatură:<​code>​
 +$ cat /​proc/​interrupts ​
 +           ​CPU0 ​      ​CPU1 ​      ​CPU2 ​      ​CPU3 ​      
 +  0:         ​14 ​         0          0          0  IR-IO-APIC-edge ​     timer
 +  1:    1358967 ​         0          0          0  IR-IO-APIC-edge ​     i8042
 +[...]
 +LOC:   ​96023026 ​  ​47877718 ​  ​90900926 ​  ​54219891 ​  Local timer interrupts
 +[...]
 +</​code>​
 +
 +Prima coloană este linia de întrerupere (''​IRQ line''​) pe care se livrează semnalul de întrerupere către procesor. Este 0 în cazul [[http://​en.wikipedia.org/​wiki/​Intel_8253|timer-ului programabil (8253)]] și 1 în cazul [[http://​en.wikipedia.org/​wiki/​Keyboard_controller_(computing)|controller-ului de tastatură (8042)]].
 +
 +Din output-ul comenzii de mai sus am selectat doar intrările referitoare la întreruperea de ceas (''​timer''​ și //Local timer interrupts//​) și cea de tastatură (''​i8042''​). La noi rulări ale comenzii<​code>​
 +cat /proc interrupts
 +</​code>​
 +vom observa actualizări ale valorilor întreruperilor. În figura de mai sus întreruperea de tastatură (''​i8042''​) este tratată doar pe primul procesor (''​CPU0''​) în vreme ce există întreruperi de ceas locale pentru fiecare procesor (de unde și denumirea de //local//).
 +
 +Pe sistemele multi-core/​multiprocesor se folosesc întreruperile de ceas locale (cele indicate de //Local timer interrupts//​). Acestea sunt livrate de controller-ul de întreruperi (APIC) către fiecare procesor în parte. Din acest motiv există actualizări pentru linia identificată de ''​LOC:''​ dar nu și pentru timer-ul programabil de pe linia identificată cu ''​timer''​. Pe sisteme uniprocesor,​ pentru livrarea întreruperii de ceas se folosește timer-ul programabil.((What are Linux local timer interrupts? http://​stackoverflow.com/​questions/​10567214/​what-are-linux-local-timer-interrupts))
 +
 +Informațiile despre întreruperea de ceas sunt actualizate periodic în fișierul ''/​proc/​interrupts''​ pentru că la un interval dat se livrează o nouă întrerupere.
 +
 +Întreruperile de tastatură sunt livrate la fiecare apăsare de tastă. Pentru a investiga evoluția numărului de întreruperi de tastatură livrate, tastăm șirul de comenzi de mai jos:<​code>​
 +$ cat /​proc/​interrupts | grep ' 1:'
 +  1:    1366012 ​         0          0          0  IR-IO-APIC-edge ​     i8042
 +$ echo '​aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'​
 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 +$ cat /​proc/​interrupts | grep ' 1:'
 +  1:    1366184 ​         0          0          0  IR-IO-APIC-edge ​     i8042
 +</​code>​
 +
 +<note important>​
 +Șirul de comenzi de mai sus trebuie tastat pentru a genera întreruperi. **Nu** dăm copy-paste la șir.
 +</​note>​
 +
 +Între prima afișare și a doua afișare a conținutului fișierul ''/​proc/​interrupts''​ am tastat circa 70-80 de taste pentru comanda ''​echo ...''​ și a doua comandă ''​cat''​ (am mai apăsat și pe tasta Backspace când am greșit). Observăm că diferența între cele două rezultate (întreruperi livrate) este ''​1336184 - 1336012 = 172''​. Au fost livrate circa dublu de întreruperi față de tastele apăsate. Acest lucru se întâmplă pentru că se livrează o întrerupere pentru fiecare apăsare de tastă (//key press//) și una pentru fiecare eliberare de tastă (//key release//); de unde și numărul dublu de întreruperi livrate față de taste apăsate.
 +==== Utilitate disk cache ====
 +
 +Dorim să urmărim efectul cache-ul de disk (numit și //page cache//). Acesta stochează datele frecvent accesate în memorie astfel că viitoare folosiri ale acestora să fie mai rapide. Vom copia de două ori un fișier și vom observa că a doua oară copierea este mai rapidă datorită cache-ului.
 +
 +Creăm un fișier ''​in.dat''​ de 100MB de date aleatoare folosind comanda ''​dd'':<​code bash>
 +$ dd if=/​dev/​urandom bs=1M count=100 of=in.dat
 +100+0 records in
 +100+0 records out
 +104857600 bytes (105 MB) copied, 7.14143 s, 14.7 MB/s
 +</​code>​
 +
 +Apoi copiem fișierul ''​in.dat''​ în fișierul ''​out.dat''​ folosind comanda ''​cp''​ și măsurând durata de execuție cu ajutorul comenzii ''​time'':<​code bash>
 +razvan@einherjar:​~$ /​usr/​bin/​time -v cp in.dat out.dat
 + Command being timed: "cp in.dat out.dat"​
 + User time (seconds): 0.00
 + System time (seconds): 0.09
 + Percent of CPU this job got: 100%
 + Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.09
 +        [...]
 +        Voluntary context switches: 1
 + Involuntary context switches: 2
 + Swaps: 0
 + File system inputs: 0
 + File system outputs: 204800
 +        [...]
 +</​code>​
 +Observăm ca a durat foarte puțin copierea, sub ''​10''​ milisecunde în rularea de mai sus. Aceasta s-a întâmplat pentru că fișierul ''​in.dat''​ a fost cache-uit în page cache de la rularea comenzii ''​dd'',​ când a fost generat.
 +
 +Ca să urmărim ce se întâmplă când fișierul nu se găsește în page cache, facem flush la page cache și apoi invalidăm intrările folosind comenzile de mai jos:<​code bash>
 +$ free -m
 +             ​total ​      ​used ​      ​free ​    ​shared ​   buffers ​    ​cached
 +Mem:          7893       ​4715 ​      ​3178 ​       251        728       1687
 +-/+ buffers/​cache: ​      ​2299 ​      5593
 +Swap:         ​3813 ​       427       3386
 +$ sudo sync
 +$ echo 1 | sudo tee /​proc/​sys/​vm/​drop_caches ​
 +1
 +$ free -m
 +             ​total ​      ​used ​      ​free ​    ​shared ​   buffers ​    ​cached
 +Mem:          7893       ​2653 ​      ​5240 ​       251          0        397
 +-/+ buffers/​cache: ​      ​2255 ​      5637
 +Swap:         ​3813 ​       427       3386
 +</​code>​
 +
 +Am folosit comanda ''​free''​ doar pentru a raporta folosirea bufferelor și a cache-ului. După rularea comenzilor ''​sync''​ și ''​echo ...''​ observăm eliberarea completă a bufferelor și aproape compleă a cache-ului.((Linux memory: buffer vs cache: http://​stackoverflow.com/​questions/​6345020/​linux-memory-buffer-vs-cache))
 +
 +Copiem din nou fișierul ''​in.dat''​ într-un nou fișier ''​out2.dat''​ și folosim comanda ''​time''​ pentru a măsura durata:<​code bash>
 +$ /​usr/​bin/​time -v cp in.dat out2.dat
 + Command being timed: "cp in.dat out2.dat"​
 + User time (seconds): 0.00
 + System time (seconds): 0.22
 + Percent of CPU this job got: 11%
 + Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.02
 +        [...]
 +        Voluntary context switches: 451
 + Involuntary context switches: 11
 + Swaps: 0
 + File system inputs: 205632
 + File system outputs: 204800
 + [...]
 +</​code>​
 +Observăm că acum operația durează semnificativ mai mult (2 secunde). De asemenea încărcarea pe procesor este mai mică (''​11%''​ față de ''​100%''​ pentru că acum procesorul așteaptă după disc. Observăm diferența mare de schimbări de context voluntare (procesul se blochează) și numărul diferit de zero de citiri din sistemul de fișiere: acum întreg fișierul de intrare este citit de pe disc, nu mai este cache-uit în memorie.
 +
 +Cache-ul de disk este esențial pentru funcționarea eficientă a sistemului. În absența acestuia procesorul ar trebui să solicite informații de pe disc, dispozitiv foarte lent comparativ cu memoria și procesor. Trebuie avut grijă la flush-ul/​sincronizarea periodică a informațiilor din memorie pe disc pentru ca acestea să nu se piardă la o închidere bruscă a sistemului, memoria fiind volatilă.
 +==== Copiere conținut CD/DVD în fișier .iso ====
 +
 +Dorim să creăm facil un fișier format .iso conținând imaginea unui CD/DVD. Pentru aceasta comanda de creare este una foarte simplă ce folosește ''​dd'':<​code bash>
 +$ dd if=/​dev/​cdrom of=file.iso bs=1M
 +</​code>​
 +
 +Comanda copiază octet cu octet conținutul CD-ului/​DVD-ului,​ indicat de dispozitivul ''/​dev/​cdrom''​ și îl scrie în fișierul ''​file.iso''​. Întrucât comanda ''​dd''​ acționează și pe dispozitive,​ va reieși un fișier în format ''​.iso'',​ copia sector cu sector a discului.
 +
 +Pentru a urmări evoluția comenzii, dintr-un alt terminal putem rula comanda:<​code bash>
 +$ kill -USR1 $(pidof dd)
 +</​code>​
 +Livrarea semnalului ''​USR1''​ procesului ''​dd''​ înseamnă afișarea unui raport de stare din partea comenzii ''​dd''​ (adică în primul terminal).
 +
 +==== Folosire operație de control (ioctl) ====
 +
 +Dorim să urmărim câteva cazuri de folosire a funcției [[http://​man7.org/​linux/​man-pages/​man2/​ioctl.2.html|ioctl]]. Funcția este utilizată pentru operații de control a unui dispozitiv sau de citire a unei stări sau a configurații,​ acolo unde funcțiile [[http://​man7.org/​linux/​man-pages/​man2/​read.2.html|read]] sau [[http://​man7.org/​linux/​man-pages/​man2/​write.2.html|write]] nu pot fi folosite. Apelurile ''​ioctl''​ sunt folosite în special pe fișiere speciale (dispozitive,​ sockeți, terminale etc.); dezavantajul este că nu există o formă standard a operațiilor aferente și în general nu sunt portabile. O listă **incompletă** de operații se găsește în [[http://​man7.org/​linux/​man-pages/​man2/​ioctl_list.2.html|pagina de manual ioctl_list]].
 +
 +Pentru a urmări folosirea apelului ''​ioctl''​ accesăm subdirectorul ''​ioctl/'';​ urmărim conținutul fișierelor ''​cdrom-ioctl.c''​ și ''​hwaddr-ioctl.c''​. Fișierele implementează,​ respectiv, operații pe CD-ROM drive și pe socket pentru aflarea adresei hardware (MAC).
 +
 +Pentru fișierul sursă ''​cdrom-ioctl.c''​ înlocuim valoarea macro-ului ''​CDROM_DEV_PATH''​ cu șirul ce reprezintă calea către CD-ROM. La fel, în fișierul ''​hwaddr-ioctl.c''​ înlocuim valoarea macro-ului ''​IFNAME''​ cu șirul ce reprezintă numele interfeței a cărei adresă hardware dorim să o determinăm.
 +
 +Compilăm fișierele folosind ''​make''​. Rezultă două fișiere în format executabil: ''​cdrom-ioctl''​ și ''​hwaddr-ioctl''​.
 +
 +Cu ajutorul executabilului ''​cdrom-ioctl''​ putem executa trei tipuri de operații pe CD-ROM așa cum este indicat prin rularea sa fără argumente:<​code>​
 +$ ./​cdrom-ioctl ​
 +You must provide exactly one argument.
 +
 +Usage: ./​cdrom-ioctl e|l|u
 + e - eject CD-ROM
 + l - lock CD-ROM drive
 + e - unlock CD-ROM drive
 +</​code>​
 +
 +În continuare putem rula comanda ''​cdrom-ioctl''​ cu exact unul dintre argumentele ''​e'',​ ''​l'',​ ''​u''​ pentru a deschide trapa CD-ROM drive-ului saua bloca/​debloca deschiderea manuală a acestuia (din buton). După cum vedem din codul sursă, aceste trei operații sunt realizate cu un apel ''​ioctl''​ și cu parametrii aferenți (documentați în [[http://​lxr.free-electrons.com/​source/​Documentation/​ioctl/​cdrom.txt?​v=3.13|sursele nucleului Linux]]): ''​CDROMEJECT''​ și ''​CDROM_LOCKDOOR''​.
 +
 +Cu ajutorul executabilului ''​hwaddr-ioctl''​ putem determina adresa hardware (MAC) a unei interfețe de rețea așa cum se întâmplă mai jos:<​code>​
 +$ ./​hwaddr-ioctl ​
 +Hardware address for interface eth0 is 00:​21:​cc:​68:​d0:​53
 +</​code>​
 +
 +Adresa hardware a fost obținută într-o structură [[http://​lxr.free-electrons.com/​source/​include/​uapi/​linux/​if.h?​v=3.13#​L170|struct ifreq]] cu ajutorul unui apel ''​ioctl''​ aplicat pe un descriptor de socket. Parametrul ''​ioctl''​ a fost ''​SIOCGIFHWADDR''​.
so/cursuri/curs-10.1397488405.txt.gz · Last modified: 2014/04/14 18:13 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