Differences

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

Link to this comparison view

so:laboratoare:laborator-10 [2017/04/29 11:13]
adrian.stanciu [Exercițiul 3 - Operații sincrone/asincrone (3p)]
so:laboratoare:laborator-10 [2022/05/10 17:40] (current)
teodor_stefan.dutu [Zero-copy I/O] Replace broken link.
Line 1: Line 1:
 ====== Laborator 10 - Operații IO avansate - Windows ====== ====== Laborator 10 - Operații IO avansate - Windows ======
  
-==== Materiale ajutătoare ==== 
  
-  *[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab10-slides.pdf | lab10-slides.pdf]] ​ 
-  *[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab10-refcard.pdf | lab10-refcard.pdf]] 
  
 ==== Nice to read ==== ==== Nice to read ====
Line 138: Line 135:
 #include <​stdlib.h>​ #include <​stdlib.h>​
  
-#define BUF_SIZE 1024 * 1024 /1MB+#define BUF_SIZE (1024 * 1024/1MB */
  
 int main(int argc, char **argv) int main(int argc, char **argv)
Line 147: Line 144:
  DWORD dwRet, dwErr, dwBytesRead;​  DWORD dwRet, dwErr, dwBytesRead;​
  char *buffer = malloc(BUF_SIZE * sizeof(char));​  char *buffer = malloc(BUF_SIZE * sizeof(char));​
- +
  /* Make sure overlapped structure is clean */  /* Make sure overlapped structure is clean */
  ZeroMemory(&​ov,​ sizeof(ov));​  ZeroMemory(&​ov,​ sizeof(ov));​
Line 159: Line 156:
  
  hFile = CreateFile(argv[1],​  hFile = CreateFile(argv[1],​
-                           GENERIC_READ, ​    ​/* access mode */ +    GENERIC_READ,​ /​* access mode */ 
-                           ​FILE_SHARE_READ, ​ /* sharing option */ +    FILE_SHARE_READ,​ /​* sharing option */ 
-                           ​NULL,             ​/* security attributes */ +    NULL, /* security attributes */ 
-                           ​OPEN_EXISTING, ​   /* open only if it exists */ +    OPEN_EXISTING,​ /​* open only if it exists */ 
-                           ​FILE_FLAG_OVERLAPPED,/​* file attributes */ +    FILE_FLAG_OVERLAPPED,/​* file attributes */ 
-                           ​NULL); ​           /* no template */+    NULL); /* no template */
  DIE(hFile == INVALID_HANDLE_VALUE,​ "​CreateFile"​);​  DIE(hFile == INVALID_HANDLE_VALUE,​ "​CreateFile"​);​
-  
- dwRet = ReadFile(hFile,​ buffer, BUF_SIZE, &​dwBytesRead,​ &ov); 
  
- if (dwRet == FALSE) { + dwRet = ReadFile(hFile,​ buffer, BUF_SIZE, &​dwBytesRead,​ &ov); 
 + if (dwRet == FALSE) {
  dwErr = GetLastError();​  dwErr = GetLastError();​
  
  switch (dwErr) {  switch (dwErr) {
- case ERROR_HANDLE_EOF:​  + case ERROR_HANDLE_EOF:​ 
- + printf("​End of File Reached\n"​);​ 
- printf("​End of File Reached\n"​);​ + break;
- break;+
  
- case ERROR_IO_PENDING:​+ case ERROR_IO_PENDING:​ 
 + /* async io not ready */ 
 + printf("​Async IO not finished immediately\n"​);​
  
- /* async io not ready */ + /* do some other work  in the meantime ​*/ 
- printf("Async IO not finished immediately\n"​);+ Sleep(1);
  
- /* do some other work  in the meantime */ + /* Wait for it to finish */ 
- Sleep(1);​ + dwRet = GetOverlappedResult(ov.hEvent,​ &ov, 
-  + &​dwBytesRead,​ TRUE); 
- /* Wait for it to finish */ + printf("​nRead = %d\n", dwBytesRead);​ 
- dwRet = GetOverlappedResult(ov.hEvent,​ &ov, &​dwBytesRead,​ TRUE); + break;
- printf("​nRead = %d\n", dwBytesRead);​ +
- break;+
  
- default: + default: 
- /* ReadFile failed */ + /* ReadFile failed */ 
- PrintLastError("​ReadFile"​);​+ PrintLastError("​ReadFile"​);​
  }  }
  } else {  } else {
Line 214: Line 209:
 Mecanismul de **completion ports** este cel mai scalabil dintre toate cele prezentate până acum. Un server care folosește completion ports poate face față la foarte multe (zeci de mii) conexiuni simultan, fără probleme prea mari. Celelalte metode își ating limitările cu mult înainte. Mecanismul de **completion ports** este cel mai scalabil dintre toate cele prezentate până acum. Un server care folosește completion ports poate face față la foarte multe (zeci de mii) conexiuni simultan, fără probleme prea mari. Celelalte metode își ating limitările cu mult înainte.
  
-Un **completion port** este un obiect în kernel cu care se asociază alți descriptori (fișiere, sockeți) și prin intermediul căruia se transmit notificările de completare ​ale unor operații asincrone lansate anterior. Un completion port are asociat un pool de worker threads. Aceste fire de execuție așteaptă să primească notificări de completare ​a operațiilor asincrone. În momentul în care un fir de execuție primește o notificare va deveni activ și va lucra o perioadă până se va întoarce din nou așteptând următoarea notificare.+Un **completion port** este un obiect în kernel cu care se asociază alți descriptori (fișiere, sockeți) și prin intermediul căruia se transmit notificările de încheiere ​ale unor operații asincrone lansate anterior. Un completion port are asociat un pool de worker threads. Aceste fire de execuție așteaptă să primească notificări de încheiere ​a operațiilor asincrone. În momentul în care un fir de execuție primește o notificare va deveni activ și va lucra o perioadă până se va întoarce din nou așteptând următoarea notificare.
  
 {{ so:​laboratoare-2013:​io_completion.png?​700 | }} {{ so:​laboratoare-2013:​io_completion.png?​700 | }}
Line 244: Line 239:
 </​code>​ </​code>​
 </​columns>​ </​columns>​
 +
 +<note important>​
 +În caz de eroare, apelul întoarce ''​NULL'',​ nu ''​INVALID_HANDLE_VALUE''​.
 +</​note>​
  
 Pentru crearea unui nou completion port, primul parametru trebuie să fie ''​INVALID_HANDLE_VALUE''​. În acest caz, ultimul parametru indică numărul maxim de fire de execuție concurente care pot rula. În caz că se specifică 0, atunci numărul de fire de execuție concurente este setat la numărul de procesoare. Pentru crearea unui nou completion port, primul parametru trebuie să fie ''​INVALID_HANDLE_VALUE''​. În acest caz, ultimul parametru indică numărul maxim de fire de execuție concurente care pot rula. În caz că se specifică 0, atunci numărul de fire de execuție concurente este setat la numărul de procesoare.
Line 334: Line 333:
 ===== Zero-copy I/O ===== ===== Zero-copy I/O =====
  
-''​Zero-copy''​ se referă la tehnica prin care procesorul evită operațiile de copiere a datelor dintr-o zonă de memorie într-alta. Operațiile ''​zero-copy''​ reduc numărul de schimbări de context ​între spațiul utilizator și spațiul kernel, resursele sistemului fiind utilizate eficient.+''​Zero-copy''​ se referă la tehnica prin care procesorul evită operațiile de copiere a datelor dintr-o zonă de memorie într-alta. Operațiile ''​zero-copy''​ reduc numărul de schimbări de privilegiu ​între spațiul utilizator și spațiul kernel, resursele sistemului fiind utilizate eficient.
  
  
Line 340: Line 339:
 {{ so:​laboratoare-2013:​normal_copy.gif | }} {{ so:​laboratoare-2013:​normal_copy.gif | }}
  
-Se observă că există multiple copieri cu aceleași date. O schemă mai eficientă, care elimină o copiere și totodată două context-switch-uri, este aceasta:+Se observă că există multiple copieri cu aceleași date. O schemă mai eficientă, care elimină o copiere și totodată două schimbări de privilegiu, este aceasta:
 {{ so:​laboratoare-2013:​zero_copy.gif | }} {{ so:​laboratoare-2013:​zero_copy.gif | }}
  
-Mai multe detalii, inclusiv explicarea mai pe larg a contextului,​ puteți găsi [[http://www.ibm.com/developerworks/​library/​j-zerocopy/​ | aici]].+Mai multe detalii, inclusiv explicarea mai pe larg a contextului,​ puteți găsi [[https://developer.ibm.com/articles/​j-zerocopy/​ | aici]]. **Atentie:​** articolul folosește greșit termenul //context switch//. De fapt, este vorba de o //schimbare de privilegiu//,​ deoarece se face o trecere din user mode în kernel mode.
 ==== TransmitFile ==== ==== TransmitFile ====
  
Line 379: Line 378:
 O funcție similară este funcția ''​[[http://​msdn.microsoft.com/​en-us/​library/​ms740566%28v=vs.85%29.aspx |TransmitPackets]]''​ care transmite date stocate în memorie pe un socket folosind cache-ul intern al sistemului de operare. Datele sunt reprezentate de o structură ''​TRANSMIT_PACKETS_ELEMENT''​. O funcție similară este funcția ''​[[http://​msdn.microsoft.com/​en-us/​library/​ms740566%28v=vs.85%29.aspx |TransmitPackets]]''​ care transmite date stocate în memorie pe un socket folosind cache-ul intern al sistemului de operare. Datele sunt reprezentate de o structură ''​TRANSMIT_PACKETS_ELEMENT''​.
  
-====== Exerciții ​de laborator ​====== +====== Exerciții ======
-===== Exercițiul 0 - Joc interactiv (2p) =====+
  
-  * Detalii desfășurare [[http://ocw.cs.pub.ro/courses/so/meta/notare#​joc_interactiv|joc]].+<note important>​ 
 +Î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 lucrul, pentru 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>​
  
-===== Windows (9p) =====+Pentru mai multe informații despre folosirea utilitarului git, urmați ghidul de la https://​gitimmersion.com. 
 +</​note>​
  
-<note important>​Înainte de a folosi o structură specifică Async I/O Win32 API, asigurați-vă că ați zeroizat-o.</​note>​+===== Windows =====
  
-În rezolvarea laboratorului ​folosiți ​arhiva de sarcini [[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab10-tasks.zip | lab10-tasks.zip]]+<note important>​ 
 +Înainte de a folosi ​o structură specifică Async I/O Win32 API, asigurați-vă că ați zero-izat-o. 
 +</​note>​
  
-==== Exercițiul 1 - Test operații asincrone ​(1p) ====+==== Exercițiul 1 - Test operații asincrone ====
  
 Setați proiectul ''​1-test_overlapp''​ ca default ([[http://​ocw.cs.pub.ro/​courses/​so/​laboratoare/​resurse/​vs_tips#​setarea_unui_subproiect_ca_default | detalii aici]]). Setați proiectul ''​1-test_overlapp''​ ca default ([[http://​ocw.cs.pub.ro/​courses/​so/​laboratoare/​resurse/​vs_tips#​setarea_unui_subproiect_ca_default | detalii aici]]).
Line 400: Line 409:
 </​code>​ </​code>​
  
-==== Exercițiul 2 - Zero-copy/​TransmitFile ​ ​(2p) ​====+==== Exercițiul 2 - Zero-copy/​TransmitFile ====
  
 Un client dorește să trimită serverului un fișier folosind operații [[#​zero-copy io | zero-copy IO]]. Un client dorește să trimită serverului un fișier folosind operații [[#​zero-copy io | zero-copy IO]].
Line 422: Line 431:
 </​code>​ </​code>​
 Comanda vă va preciza dacă cele două fișiere sunt identice sau nu. Comanda vă va preciza dacă cele două fișiere sunt identice sau nu.
-==== Exercițiul 3 - Operații sincrone/​asincrone ​(3p) ====+==== Exercițiul 3 - Operații sincrone/​asincrone ====
  
 Ne propunem să realizăm implementarea unor operații IO asincrone pentru popularea unor fișiere cu conținut. Ne propunem să realizăm implementarea unor operații IO asincrone pentru popularea unor fișiere cu conținut.
  
-Intrați în proiectul ''​3-aio/''​ și urmăriți implementarea funcției ''​do_io_sync''​ și implementați ''​do_io_async''​.+Intrați în proiectul ''​3-aio''​ și urmăriți implementarea funcției ''​do_io_sync''​ și implementați ''​do_io_async''​.
  
 Alocați spațiu pentru structurile ''​OVERLAPPED''​ pentru toate cele 4 fișiere. Pentru inițializarea structurilor ''​OVERLAPPED''​ se recomandă implementarea funcției ''​init_overlapped''​. În cadrul funcției ''​init_overlapped''​ "​zero-izați"​ structura de tipul ''​OVERLAPPED''​ și apoi completați câmpurile aferente parametrilor transmiși. Alocați spațiu pentru structurile ''​OVERLAPPED''​ pentru toate cele 4 fișiere. Pentru inițializarea structurilor ''​OVERLAPPED''​ se recomandă implementarea funcției ''​init_overlapped''​. În cadrul funcției ''​init_overlapped''​ "​zero-izați"​ structura de tipul ''​OVERLAPPED''​ și apoi completați câmpurile aferente parametrilor transmiși.
  
-Când apelați funcția ''​init_overlapped''​ (din cadrul funcției ''​do_io_async''​),​ folosiți valorea ''​0''​ ca argument pentru offset și ''​NULL''​ pentru event (nu vom folosi event ca să notifice de încheierea operației). Funcția ''​init_overlapped''​ este apelată într-un ciclu for, pentru fiecare element al array-ului ''​ov''​. ​Folosiți ''​GetOverlappedResult''​ pentru realizarea operațiilor asincrone pe cele 4 fișiere. Funcțiile trebuie să scrie conținutul bufferului ''​g_buffer''​ în cele 4 fișiere cu numele ​dat de vectorul ''​files''​. Folosiți macro-ul ''​IO_OP_TYPE''​ pentru a determina comportamentul programului (revedeți secțiunea despre [[ #windows - io asincron overlapped | Overlapped IO]])+Când apelați funcția ''​init_overlapped''​ (din cadrul funcției ''​do_io_async''​),​ folosiți valorea ''​0''​ ca argument pentru offset și ''​NULL''​ pentru event (nu vom folosi event-uri pentru a notifica ​încheierea operației). Funcția ''​init_overlapped''​ este apelată într-un ciclu for, pentru fiecare element al array-ului ''​ov''​. ​Scrieți asincron ​conținutul bufferului ''​g_buffer''​ în cele 4 fișiere cu numele ​date de vectorul ''​files''​. Folosiți ''​GetOverlappedResult''​ pentru așteptarea operațiilor asincrone pe cele 4 fișiere. Folosiți macro-ul ''​IO_OP_TYPE''​ pentru a determina comportamentul programului (revedeți secțiunea despre [[ #windows - io asincron overlapped | Overlapped IO]])
  
 Rulați programul compilat folosind comanda:<​code bash> Rulați programul compilat folosind comanda:<​code bash>
Line 436: Line 445:
 </​code>​ </​code>​
 Dacă ați lucrat corect, în urma rulării comenzii de mai sus se vor genera în directorul curent 4 fișiere text (cu extensia ''​.txt''​) de dimensiune ''​BUFSIZ'',​ conținând caractere random. Dacă ați lucrat corect, în urma rulării comenzii de mai sus se vor genera în directorul curent 4 fișiere text (cu extensia ''​.txt''​) de dimensiune ''​BUFSIZ'',​ conținând caractere random.
-==== Exercițiul 4 - I/O completion ports (3p) ====+==== Exercițiul 4 - I/O completion ports ====
  
 Vom folosi API-ul de I/O completion ports. Vom folosi API-ul de I/O completion ports.
  
-=== Crearea unui completion ports (1p) ===+=== Crearea unui completion ports ===
  
-Intrați în proiectul ''​4-iocp/''​ și analizați conținutul fișierelor ''​iocp.h''​ și ''​iocp.c''​. Completați cele 4 funcții definite în fișierul ''​iocp.c''​ (revedeți secțiunea despre [[#crearea unui completion port| IO completion ports]]).+Intrați în proiectul ''​4-iocp''​ și analizați conținutul fișierelor ''​iocp.h''​ și ''​iocp.c''​. Completați cele 4 funcții definite în fișierul ''​iocp.c''​ (revedeți secțiunea despre [[#crearea unui completion port| IO completion ports]]).
  
-=== Operații I/O asincrone cu I/O completion ports (2p) ===+=== Operații I/O asincrone cu I/O completion ports ===
  
 Analizați conținutul fișierului ''​aio.c''​. Scopul exercițiului este folosirea I/O completion ports pentru așteptarea încheierii operațiilor I/O asincrone (overlapped I/O). Analizați conținutul fișierului ''​aio.c''​. Scopul exercițiului este folosirea I/O completion ports pentru așteptarea încheierii operațiilor I/O asincrone (overlapped I/O).
  
-Implementați funcțiile ''​init_io_async''​ și ''​do_io_async''​. În funcția ''​do_io_async'' ​înainte de a trimite o cerere folosind ''​WriteFile'', ​folosiți funcția ''​init_overlapped''​ pentru a inițializa elementul aferent al vectorului ​''​ov''​.+Implementați funcțiile ''​init_io_async''​ și ''​do_io_async''​. În funcția ''​init_io_async''​ folosiți funcția ''​init_overlapped''​ pentru a inițializa elementul aferent al array-ului ​''​ov'' ​(folosiți valorea 0 ca argument pentru offset și NULL pentru event).
  
 Compilați și rulați programul. ​ Compilați și rulați programul. ​
-===== Soluții ===== 
  
-[[http://​elf.cs.pub.ro/​so/​res/​laboratoare/​lab10-sol.zip | Soluţii laborator 10]] 
so/laboratoare/laborator-10.1493453605.txt.gz · Last modified: 2017/04/29 11:13 by adrian.stanciu
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