This shows you the differences between two versions of the page.
so:cursuri:curs-10 [2014/04/21 10:03] razvan.deaconescu [Investigare întreruperi] |
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&lock_to_path=0&autoplay=0&autohide_ctrls=0&features=undefined&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 10 - 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-10.pdf|Curs 10 - 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&lock_to_path=0&autoplay=0&autohide_ctrls=0&features=undefined&disabled_features=undefined" width="550" height="400" frameBorder="0"></iframe> | ||
+ | </center> | ||
+ | </html> | ||
===== Demo-uri ===== | ===== Demo-uri ===== | ||
Line 71: | Line 75: | ||
==== Utilitate disk cache ==== | ==== Utilitate disk cache ==== | ||
- | Dorim să urmărim ce se întâmplă în cazul în care avem date partajate într-un mediu multithread. Pentru aceasta accesăm subdirectorul ''list-excl/''; urmărim conținutul fișierelor ''thread-list-app.c'' și ''list.c''. Este vorba de o aplicație care lucrează cu liste înlănțuite într-un mediu multithreaded. Vom observa că există riscul ca datele să fie corupte, fiind necesară sincronizare. | + | 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. |
- | Compilăm fișierele folosind ''make''. Rezultă două fișiere în format executabil: ''thread-list-app'' și ''thread-list-app-mutex''. | + | 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> | ||
- | Programul ''thread-list-app-mutex'' folosește intern un mutex pentru sincronizare. Pentru aceasta folosim macro-ul ''USE_MUTEX'' pe care îl definim în fișierul ''Makefile''. | + | 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ă cu o aplicație multithreaded cu date partajate, rulăm de mai multe ori programul ''thread-list-app'', până la obținerea unei erori:<code bash> | + | 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> |
- | ./thread-list-app | + | $ 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> | </code> | ||
- | ==== Copiere conținut CD/DVD în fișier .iso ==== | + | 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)) |
- | Dorim să urmărim ce se întâmplă în cazul în care avem date partajate într-un mediu multithread. Pentru aceasta accesăm subdirectorul ''list-excl/''; urmărim conținutul fișierelor ''thread-list-app.c'' și ''list.c''. Este vorba de o aplicație care lucrează cu liste înlănțuite într-un mediu multithreaded. Vom observa că există riscul ca datele să fie corupte, fiind necesară sincronizare. | + | 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. | ||
- | Compilăm fișierele folosind ''make''. Rezultă două fișiere în format executabil: ''thread-list-app'' și ''thread-list-app-mutex''. | + | 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 ==== | ||
- | Programul ''thread-list-app-mutex'' folosește intern un mutex pentru sincronizare. Pentru aceasta folosim macro-ul ''USE_MUTEX'' pe care îl definim în fișierul ''Makefile''. | + | 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> | ||
- | Ca să urmărim ce se întâmplă cu o aplicație multithreaded cu date partajate, rulăm de mai multe ori programul ''thread-list-app'', până la obținerea unei erori:<code bash> | + | 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. |
- | ./thread-list-app | + | |
+ | Pentru a urmări evoluția comenzii, dintr-un alt terminal putem rula comanda:<code bash> | ||
+ | $ kill -USR1 $(pidof dd) | ||
</code> | </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) ==== | ==== Folosire operație de control (ioctl) ==== | ||
- | Dorim să urmărim ce se întâmplă în cazul în care avem date partajate într-un mediu multithread. Pentru aceasta accesăm subdirectorul ''list-excl/''; urmărim conținutul fișierelor ''thread-list-app.c'' și ''list.c''. Este vorba de o aplicație care lucrează cu liste înlănțuite într-un mediu multithreaded. Vom observa că există riscul ca datele să fie corupte, fiind necesară sincronizare. | + | 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]]. |
- | Compilăm fișierele folosind ''make''. Rezultă două fișiere în format executabil: ''thread-list-app'' și ''thread-list-app-mutex''. | + | 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). |
- | Programul ''thread-list-app-mutex'' folosește intern un mutex pentru sincronizare. Pentru aceasta folosim macro-ul ''USE_MUTEX'' pe care îl definim în fișierul ''Makefile''. | + | 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. |
- | Ca să urmărim ce se întâmplă cu o aplicație multithreaded cu date partajate, rulăm de mai multe ori programul ''thread-list-app'', până la obținerea unei erori:<code bash> | + | Compilăm fișierele folosind ''make''. Rezultă două fișiere în format executabil: ''cdrom-ioctl'' și ''hwaddr-ioctl''. |
- | ./thread-list-app | + | |
+ | 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> | </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''. |