Differences

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

Link to this comparison view

so:laboratoare:laborator-11 [2015/05/18 01:04]
laura.vasilescu [Exercițiul 3 - eventfd (2p)]
so:laboratoare:laborator-11 [2022/05/19 16:54] (current)
liza_elena.babu [Înainte de laborator: Feedback]
Line 1: Line 1:
 ====== Laborator 11 - Operații IO avansate - Linux ====== ====== Laborator 11 - Operații IO avansate - Linux ======
- 
-===== Materiale Ajutătoare ===== 
- 
-  * [[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab11-slides.pdf | lab11-slides.pdf]] 
-  * [[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab11-refcard.pdf | lab11-refcard.pdf]] 
  
  
Line 10: Line 5:
  
   * TLPI - Chapter 63, Alternative I/O models   * TLPI - Chapter 63, Alternative I/O models
 +
 +===== Link-uri către secțiuni utile =====
 +==== Linux ====
 +
 +  * [[#​linux_-_multiplexarea_io|Linux - multiplexarea I/O]]
 +    * [[#​select|select]]
 +    * [[#​poll|poll]]
 +    * [[#​epoll|epoll]]
 +  * [[#​linux_-_generalizarea_multiplexarii|Linux - generalizarea multiplexării]]
 +    * [[#​eventfd|eventfd]]
 +    * [[#​signalfd|signalfd]]
 +  * [[#​linux_-_operatii_asincrone|Linux - operații asincrone]]
 +  * [[#​zero-copy_io|Zero-copy I/O]]
 +  * [[#​vectored_io|Vectored I/O]]
 +
 +<​hidden>​
 +===== Înainte de laborator: Feedback =====
 +
 +Pentru a îmbunătăți cursul de SO, componentele sale și modul de desfășurare,​ ne sunt foarte utile opiniile voastre. Pentru aceasta, vă rugăm să accesați și completați formularul de feedback de pe site-ul acs.curs.pub.ro. Trebuie să fiți autentificați și înrolați în cadrul cursului.
 +
 +Formularul este anonim și este activ în perioada 11 mai 2020 - 22 mai 2020. Rezultatele vor fi vizibile în cadrul echipei cursului doar după încheierea sesiunii. Este accesibil la link-ul “Formular feedback” a paginii principale a cursului de SO al seriei voastre pe acs.curs.pub.ro. Nu este în meta-cursul disponibil tuturor seriilor.
 +
 +Vă invităm să evaluați activitatea echipei de SO și să precizați punctele tari și punctele slabe și sugestiile voastre de îmbunătățire a disciplinei. Feedback-ul vostru ne ajută să creștem calitatea materiei în anii următori și să îmbunătățim disciplinele pe care le veți face în continuare.
 +
 +Vom publica la începutul semestrului viitor analiza feedback-ului vostru.
 +
 +Ne interesează în special:
 +
 +  * Ce nu v-a plăcut și ce credeți că nu a mers bine?
 +  * De ce nu v-a plăcut și de ce credeți că nu a mers bine?
 +  * Ce ar trebuie să facem ca lucrurile să fie plăcute și să meargă bine?
 +</​hidden>​
 =====  Linux - multiplexarea I/O ===== =====  Linux - multiplexarea I/O =====
  
Line 56: Line 83:
  
 Dezavantaje:​ Dezavantaje:​
-    * lungimea ​setul de descriptori este definită cu ajutorul lui FD_SETSIZE, și implicit are valoarea ​64;+    * lungimea ​setului ​de descriptori este definită cu ajutorul lui ''​FD_SETSIZE''​, și implicit are valoarea ​1024;
     * este necesar ca seturile de descriptori să fie reconstruite la fiecare apel ''​select'';​     * este necesar ca seturile de descriptori să fie reconstruite la fiecare apel ''​select'';​
     * la apariția unui eveniment pe unul dintre descriptori,​ toți descriptorii puși în set înainte de ''​select''​ trebuie testați pentru a vedea pe care dintre ei a apărut evenimentul;​     * la apariția unui eveniment pe unul dintre descriptori,​ toți descriptorii puși în set înainte de ''​select''​ trebuie testați pentru a vedea pe care dintre ei a apărut evenimentul;​
Line 290: Line 317:
     epoll_wait(epfd,​ &​ret_ev,​ 1, -1);     epoll_wait(epfd,​ &​ret_ev,​ 1, -1);
    
-    if ((rev_ev.data.fd == listenfd && ((ret_ev.events & EPOLLIN) != 0)) {+    if ((ret_ev.data.fd == listenfd&& ((ret_ev.events & EPOLLIN) != 0)) {
         /* TODO ... handle new connection */         /* TODO ... handle new connection */
     }     }
-    else if ((rev_ev.data.fd == STDIN_FILENO &&+    else if ((ret_ev.data.fd == STDIN_FILENO&&
                     ((ret_ev.events & EPOLLIN) != 0)) {                     ((ret_ev.events & EPOLLIN) != 0)) {
         /* TODO ... read user data from standard input */         /* TODO ... read user data from standard input */
Line 310: Line 337:
  
 Pentru a asigura în Linux posibilitatea așteptării de evenimente multiple s-a definit interfața ''​eventfd''​. Cu ajutorul acestei interfețe și combinat cu interfețele de multiplexare I/O existente, kernel-ul poate notifica o aplicație utilizator de orice tip de eveniment. Pentru a asigura în Linux posibilitatea așteptării de evenimente multiple s-a definit interfața ''​eventfd''​. Cu ajutorul acestei interfețe și combinat cu interfețele de multiplexare I/O existente, kernel-ul poate notifica o aplicație utilizator de orice tip de eveniment.
- 
-Interfața ''​eventfd''​ este prezentă în nucleul Linux începând cu versiunea 2.6.22 și este suportată de către glibc începând cu versiunea 2.8. 
  
 Interfața ''​eventfd''​ permite unificarea mecanismelor de notificare ale kernel-ului într-un descriptor de fișier care va fi folosit de utilizator. Interfața ''​eventfd''​ permite unificarea mecanismelor de notificare ale kernel-ului într-un descriptor de fișier care va fi folosit de utilizator.
Line 426: Line 451:
 ==== Linux AIO ==== ==== Linux AIO ====
  
-Standardul ''​POSIX.1b''​ definește ​un nou set de operații I/O care pot reduce semnificativ timpul pe care o aplicație îl petrece așteptând pentru I/O. Noile funcții permit unui program să inițieze una sau mai multe operații de I/O și să-și continue lucrul normal în timp ce operațiile de I/O sunt executate în paralel. ​+Începând cu versiunea 2.5.32, kernelul Linux expune ​un set de operații I/O care pot reduce semnificativ timpul pe care o aplicație îl petrece așteptând pentru I/O. Noile funcții permit unui program să inițieze una sau mai multe operații de I/O și să-și continue lucrul normal în timp ce operațiile de I/O sunt executate în paralel. ​
  
 Această funcționalitate este disponibilă dacă se instalează biblioteca ''​libaio'':​ <code bash> Această funcționalitate este disponibilă dacă se instalează biblioteca ''​libaio'':​ <code bash>
Line 436: Line 461:
 </​code>​ </​code>​
  
-Totodată, programul care folosește acest API trebuie să includă fișierul header ''​[[http://​www.koders.com/c/fid4725E35EA2BE17467E3BB724D74D9FA6A471BFE7.aspx | libaio.h]]''​ și să link-eze biblioteca ''​libaio''​. Toate funcțiile și structurile de care vom vorbi în continuare se pot găsi în acest fișier header. Dacă ați instalat pachetul, fișierul se găsește în ''/​usr/​include/​libaio.h''​.+Totodată, programul care folosește acest API trebuie să includă fișierul header ''​[[http://​libaio.sourcearchive.com/documentation/0.3.109-1ubuntu1/​libaio_8h_source.html ​| libaio.h]]''​ și să link-eze biblioteca ''​libaio''​. Toate funcțiile și structurile de care vom vorbi în continuare se pot găsi în acest fișier header. Dacă ați instalat pachetul, fișierul se găsește în ''/​usr/​include/​libaio.h''​.
  
 ====Structuri de bază Linux AIO==== ====Structuri de bază Linux AIO====
  
-Structura ''​iocb''​ folosită pentru încapsularea unei operații asincrone. Structura este definită în header-ul ''​[[http://​www.koders.com/c/fid4725E35EA2BE17467E3BB724D74D9FA6A471BFE7.aspx | libaio.h]]''​.+Structura ''​iocb''​ folosită pentru încapsularea unei operații asincrone. Structura este definită în header-ul ''​[[http://​libaio.sourcearchive.com/documentation/0.3.109-1ubuntu1/​libaio_8h_source.html ​| libaio.h]]''​.
 <code c> <code c>
 struct iocb { struct iocb {
Line 502: Line 527:
  
  
- ​Pentru folosirea acesteia o aplicație va include ''​[[http://​www.koders.com/c/fid4725E35EA2BE17467E3BB724D74D9FA6A471BFE7.aspx | libaio.h]]''​. Un exemplu de inițializare a acestei structuri este:+ ​Pentru folosirea acesteia o aplicație va include ''​[[http://​libaio.sourcearchive.com/documentation/0.3.109-1ubuntu1/​libaio_8h_source.html ​| libaio.h]]''​. Un exemplu de inițializare a acestei structuri este:
 <code c> <code c>
         #include <​libaio.h>​         #include <​libaio.h>​
Line 647: Line 672:
 int efd; int efd;
    
-/creare event cu valoare inițială 0, fără flaguri speciale+/creare event cu valoare inițială 0, fără flaguri speciale ​*/
 efd = eventfd(0, 0); efd = eventfd(0, 0);
    
Line 674: Line 699:
 Este un apel de sistem ce permite transferul de date între 2 descriptori de fișier, dintre care cel puțin unul este pipe. Avantajul este că nu se folosește un buffer (byte array) în userspace. ​ Este un apel de sistem ce permite transferul de date între 2 descriptori de fișier, dintre care cel puțin unul este pipe. Avantajul este că nu se folosește un buffer (byte array) în userspace. ​
 <code c> <code c>
-#define _GNU_SOURCE /trebuie definit pentru că splice este o extensie nespecificată de standardele POSIX/​SYSV/​BSD/​etc.+#define _GNU_SOURCE /trebuie definit pentru că splice este o extensie nespecificată de standardele POSIX/​SYSV/​BSD/​etc. ​*/
  
 #include <​fcntl.h>​ #include <​fcntl.h>​
Line 702: Line 727:
 size_t count = 4096; size_t count = 4096;
    
-/... deschideri fișiere, creare pipe+/... deschideri fișiere, creare pipe */
    
 splice(file1,​ &​offset,​ pipe, NULL, count, 0); splice(file1,​ &​offset,​ pipe, NULL, count, 0);
Line 772: Line 797:
 } }
 </​code>​ </​code>​
-===== Exercițiul 0 - Joc interactiv (2p) ===== 
  
-  * Detalii desfășurare [[http://​ocw.cs.pub.ro/​courses/​so/​meta/​notare#​joc_interactiv|joc]]. +===== Exerciții ​=====
- +
-===== Linux (9p) ===== +
- +
-În rezolvarea laboratorului folosiți arhiva de sarcini [[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab11-tasks.zip | lab11-tasks.zip]]+
  
 <note important>​ <note important>​
-Acest laborator se desfășoară în echipe. O echipă este formată din 2 studenți. În cazul în care numărul de studenți prezenți este imparo singură echipă va avea dreptul de a avea 3 studenți.+În cadrul laboratoarelor vom folosi repository-ul de git al materiei SO - https://​github.com/​systems-cs-pub-ro/​so. Va trebui sa clonați repository-ul pe masinile virtuale folosind comanda: ''​git clone https://​github.com/​systems-cs-pub-ro/​so''​. Dacă doriți să descărcați repositoryul ​în altă locație, folosiți comanda ''​git clone https://​github.com/​systems-cs-pub-ro/​so ${target}''​. 
 + 
 +Pentru a actualiza repository-ul,​ folosiți comanda ''​git pull origin master''​ din interiorul directorului ​în care se află repository-ul. Recomandarea este să îl actualizați cât mai frecvent, înainte să începeți lucrulpentru a vă asigura că aveți versiunea cea mai recentăÎn cazul în care gitul detectează conflicte la nivelul vreunui fişier, folosiți următoarele comenzi pentru a vă păstra modificările:​ 
 +<​code>​ 
 +git stash 
 +git pull origin master 
 +git stash pop 
 +</​code>​
  
-Discutați exercițiile școlaborați pe parcursul întregului laboratorHave fun! :-)+Pentru mai multe informații despre folosirea utilitarului git, urmați ghidul de la https://​gitimmersion.com.
 </​note>​ </​note>​
  
-==== Exercițiul 1 - poll (1p) ====+==== Linux ==== 
 + 
 +=== Exercițiul 1 - poll ===
  
 Intrați în directorul ''​1-pollpipe''​. Parcurgeți fișierul ''​poll.c''​ pentru a vedea un exemplu de folosire al funcției ''​poll''​. Intrați în directorul ''​1-pollpipe''​. Parcurgeți fișierul ''​poll.c''​ pentru a vedea un exemplu de folosire al funcției ''​poll''​.
Line 805: Line 834:
  
  
-==== Exercițiul 2 - epoll (2p) ====+=== Exercițiul 2 - epoll ===
  
 Intrați în directorul ''​2-epollpipe''​ și parcurgeți fișierul ''​epoll.c''​. Considerând cerința de la exercițiul anterior, în loc de ''​poll''​ folosiți ''​epoll''​. Intrați în directorul ''​2-epollpipe''​ și parcurgeți fișierul ''​epoll.c''​. Considerând cerința de la exercițiul anterior, în loc de ''​poll''​ folosiți ''​epoll''​.
  
-În partea de inițializare realizați următoare operații:+În partea de inițializare realizați următoarele ​operații:
   * Inițializați,​ înainte de ciclul ''​for'',​ handle-ul de epoll folosing ''​epoll_create''​.   * Inițializați,​ înainte de ciclul ''​for'',​ handle-ul de epoll folosing ''​epoll_create''​.
   * Adăugați câte un eveniment pentru fiecare pipe (folosind variabila ''​ev''​) folosind ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_ADD''​.   * Adăugați câte un eveniment pentru fiecare pipe (folosind variabila ''​ev''​) folosind ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_ADD''​.
Line 820: Line 849:
      * Descriptorul indicat în structura întoarsă de ''​epoll_wait''​ (adică ''​ev.data.fd''​) este capătul de citire al pipe-ului.      * Descriptorul indicat în structura întoarsă de ''​epoll_wait''​ (adică ''​ev.data.fd''​) este capătul de citire al pipe-ului.
   * Din pipe citiți mesajul trimis de client, folosind ''​read''​.   * Din pipe citiți mesajul trimis de client, folosind ''​read''​.
-  * Închideți pipe-ul ​(folosind ''​close''​) și eliminați-l ​din multiplexor (folosind ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_DEL''​).+  * Eliminați pipe-ul din multiplexor (folosind ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_DEL''​) ​și închideți-l folosind ''​close''​.
   * Incremenetați valoarea variabilei ''​recv_msgs''​.   * Incremenetați valoarea variabilei ''​recv_msgs''​.
-==== Exercițiul 3 - eventfd ​(2p) ====+ 
 +=== Exercițiul 3 - eventfd ===
  
 Pornind de la codul scris pentru execițiul anterior, notificați serverul de terminarea unui client utilizând ''​eventfd''​. Clientul transmite mesaje către server și, când dorește să închidă comunicația,​ va trimite un mesaj pe canalul de control reprezentat de ''​eventfd''​. Acum, ''​epoll''​ este folosit pentru a demultiplexa atât descriptorii de pipe, cât și descriptorul de ''​eventfd''​. Pornind de la codul scris pentru execițiul anterior, notificați serverul de terminarea unui client utilizând ''​eventfd''​. Clientul transmite mesaje către server și, când dorește să închidă comunicația,​ va trimite un mesaj pe canalul de control reprezentat de ''​eventfd''​. Acum, ''​epoll''​ este folosit pentru a demultiplexa atât descriptorii de pipe, cât și descriptorul de ''​eventfd''​.
Line 835: Line 865:
 Dacă descriptorul întors în urma ''​epoll_wait''​ este descriptorul de ''​eventfd'',​ atunci veți citi ''​64''​ de biți de pe acest descriptor (folosind ''​read''​). Dacă primii 32 biți sunt valoarea descrisă de macro-ul ''​MAGIC_EXIT'',​ atunci **scoate** capătul pipe-ului corespunzător din ''​epoll''​ și închide acel capăt (adică folosește ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_DEL''​ și apoi ''​close''​). Pentru a extrage ultimii 32 de biți din mesajul de ''​64''​ de biți primit pe descriptorul de ''​eventfd'',​ reprezentând indexul clientului, folosiți funcția ''​get_index''​ definită local în program. Dacă descriptorul întors în urma ''​epoll_wait''​ este descriptorul de ''​eventfd'',​ atunci veți citi ''​64''​ de biți de pe acest descriptor (folosind ''​read''​). Dacă primii 32 biți sunt valoarea descrisă de macro-ul ''​MAGIC_EXIT'',​ atunci **scoate** capătul pipe-ului corespunzător din ''​epoll''​ și închide acel capăt (adică folosește ''​epoll_ctl''​ cu opțiunea ''​EPOLL_CTL_DEL''​ și apoi ''​close''​). Pentru a extrage ultimii 32 de biți din mesajul de ''​64''​ de biți primit pe descriptorul de ''​eventfd'',​ reprezentând indexul clientului, folosiți funcția ''​get_index''​ definită local în program.
       ​       ​
-==== Exercițiul 4 - async I/O (KAIO) (2p==== +=== Exercițiul 4 - async I/O (KAIO) === 
-  - (**3 puncte**) Asynchronous I/O (KAIO) + 
-         * Intrați în directorul ''​4-kaio''​+Intrați în directorul ''​4-kaio'' ​și parcurgeți fișierul ''​kaio.c''​. Completați zonele lipsă pentru a programa scrierea a 4 fișiere cu numele date de variabila ''​files''​. 
-         * Parcurgeți fișierul ''​kaio.c''​. + 
-         ​* ​Completați zonele lipsă pentru a programa scrierea a 4 fișiere cu numele date de variabila ''​files''​. +Folosiți API-ul KAIO (io_setup, io_destroy, io_submit, io_getevents). Folosiți **doar** io_getevents pentru așteptarea încheierii operațiilor asincrone. 
-         * Folosiți API-ul KAIO (io_setup, io_destroy, io_submit, io_getevents). + 
-         ​* ​Folosiți **doar** io_getevents pentru așteptarea încheierii operațiilor asincrone. +Parcurgeți secțiunea [[#​linux_aio|Linux AIO]] și consultați exemplul lui [[http://​www.xmailserver.org/​eventfd-aio-test.c | Davide Libenzi]]. Urmăriți comentariile cu // TODO 1 // 
-         * **Hints**: ​ + 
-           * Parcurgeți secțiunea [[#​linux_aio|Linux AIO]]+Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune ​''​BUFSIZ'' ​octeți create în ''/​tmp''​.  
-           * Consultați exemplul lui [[http://​www.xmailserver.org/​eventfd-aio-test.c | Davide Libenzi]]. ​ + 
-           ​* ​Urmăriți comentariile cu // TODO 1 // +**Atenţie!** În cazul în care, la compilare, header-ul '​libaio'​ nu este găsit rulaţi <code bash>
-         * Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune ​8192 octeți create în ''/​tmp''​.  +
-           * **Atenţie!** În cazul în care, la compilare, header-ul '​libaio'​ nu este găsit rulaţi <code bash>+
 so$ sudo apt-get install libaio1 libaio-dev so$ sudo apt-get install libaio1 libaio-dev
 </​code>​ </​code>​
  
  
-==== Exercițiul 5 - async I/O (KAIO) (2p==== +=== Exercițiul 5 - async I/O (KAIO) === 
-  - (**2 puncte**) Asynchronous I/O (KAIO) + eventfd + 
-         * Folosiți ''​eventfd''​ pentru așteptarea operațiilor asincrone. + ​Folosiți ''​eventfd''​ pentru așteptarea operațiilor asincrone. Porniți de la codul scris pentru execițiul anterior. 
-           ​* ​Porniți de la codul scris pentru execițiul anterior. + 
-           * Decomentați în ''​kaio.c''​ linia cu <code c>#​define USE_EVENTFD</​code>​ +Decomentați în ''​kaio.c''​ linia cu <code c>#​define USE_EVENTFD</​code>​ 
-           * La inițializarea structurilor ''​iocb'',​ folosiți funcția ''​io_set_eventfd''​ pentru a activa folosirea ''​eventfd''​ +La inițializarea structurilor ''​iocb'',​ folosiți funcția ''​io_set_eventfd''​ pentru a activa folosirea ''​eventfd''​Completați funcția ''​wait_aio''​ pentru a aștepta terminarea operațiilor asincrone folosind ''​eventfd''​. 
-           ​* ​Completați funcția ''​wait_aio''​ pentru a aștepta terminarea operațiilor asincrone folosind ''​eventfd''​ + 
-         * **Hints**: ​ +Parcurgeți secțiunea [[#​linux_aio|Linux AIO]] și urmăriți comentariile cu // TODO 2 //Consultați exemplul lui [[http://​www.xmailserver.org/​eventfd-aio-test.c | Davide Libenzi]].  
-           * Parcurgeți secțiunea [[#​linux_aio|Linux AIO]]+ 
-           * Urmăriți comentariile cu // TODO 2 // +Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune 8192 octeți create în ''/​tmp''​. 
-           ​* ​Consultați exemplul lui [[http://​www.xmailserver.org/​eventfd-aio-test.c | Davide Libenzi]].  + 
-         * Compilați și rulați programul. Va trebui să aveți 4 fișiere de dimensiune 8192 octeți create în ''/​tmp''​.  +==== BONUS ====
-===== BONUS =====+
  
-  - **(1 so karma)** ​''​signalfd''​+  - ''​signalfd''​
      * Modificați codul de la exercițiul 2 pentru a permite notificarea de terminare a clienților bazată pe semnale.      * Modificați codul de la exercițiul 2 pentru a permite notificarea de terminare a clienților bazată pe semnale.
      * Server-ul:      * Server-ul:
Line 874: Line 901:
        * Consultați secțiunea [[#​signalfd|signalfd]]        * Consultați secțiunea [[#​signalfd|signalfd]]
        * [[ http://​linux.die.net/​man/​2/​signalfd | man signalfd ]]        * [[ http://​linux.die.net/​man/​2/​signalfd | man signalfd ]]
-===== Soluții ===== 
  
-[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab11-sol.zip | Soluţii laborator 11]]  
so/laboratoare/laborator-11.1431900282.txt.gz · Last modified: 2015/05/18 01:04 by laura.vasilescu
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