Differences

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

Link to this comparison view

apd:laboratoare:11 [2022/01/18 19:38]
elena.taran [Alte funcții de schimb de mesaje]
apd:laboratoare:11 [2023/10/08 16:34] (current)
dorinel.filip Move
Line 1: Line 1:
 ===== Laboratorul 11 - Funcții de comunicare și de sincronizare în MPI ===== ===== Laboratorul 11 - Funcții de comunicare și de sincronizare în MPI =====
- +Documentația de laborator ​s-a mutat la [[https://mobylab.docs.crescdi.pub.ro/docs/parallelAndDistributed/introduction|această adresă]].
-Responsabili:​ Florin Mihalache, Radu Ciobanu, Georgiana Țăran +
-==== Funcții nonblocante ==== +
-Până acum în cadrul laboratoarelor de MPI ați lucrat cu funcții de comunicare blocante (''​MPI_Send'',​ ''​MPI_Recv''​). În cadrul comunicării blocante, funcțiile de send și de receive se blochează până când buffer-ul folosit pentru transmisia de mesaje poate fi refolosit, mai precis în felul următor: +
-  * la send (''​MPI_Send''​) se întoarce un rezultat când buffer-ul unde se pun datele pentru transmisie poate folosit din nou (până atunci trimiterea este blocată). +
-  * la receive (''​MPI_Recv''​) se întoarce un rezultat când toate datele transmise prin buffer pot fi prelucrate (până atunci primirea este blocată). +
- +
-Comunicarea mesajelor este împărțită în două mari categorii:​ +
-  * **blocantă**,​ care este **sincronă** +
-  * **non-blocantă**,​ care este **asincronă** +
- +
-Trimiterea blocantă este în patru moduri: +
-  * standard (''​MPI_Send''​) +
-  * sincronizată (''​MPI_Ssend''​) +
-  * buffered (''​MPI_Bsend''​) +
-  * ready (''​MPI_Rsend''​) +
- +
-În ceea ce privește comunicarea non-blocantă,​ funcțiile de trimitere (''​MPI_Isend''​) și de primire (''​MPI_Irecv''​) a datelor întorc imediat un rezultat. Astfel, nu avem rezultate sigure legate de terminarea trimiterii de date, așadar ca să ne asigurăm că datele au fost trimise și primite corect și complet putem folosi funcțiile ''​MPI_Test''​ și ''​MPI_Wait'',​ despre care vom vorbi în detaliu mai jos. +
- +
-Comunicarea non-blocantă este utilă pentru situații în care avem deadlock sau în care se trimit date de dimensiuni mari. +
- +
-=== MPI_Isend === +
-Semnătura funcției:​ +
-<code c> +
-int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request) +
-</​code>​ +
- +
-Parametrii funcției ''​MPI_Isend''​ se comportă la fel ca parametrii funcției ''​MPI_Send'',​ însă ce este în plus este parametrul ''​MPI_Request *request'',​ ''​MPI_Request''​ fiind o structură folosită pentru testarea trimiterii și primirii datelor. +
- +
-=== MPI_Irecv === +
-Semnătura funcției:​ +
-<code c> +
-int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request) +
-</​code>​ +
- +
-Spre deosebire de ''​MPI_Recv'',​ ''​MPI_Irecv''​ nu are parametru de ''​MPI_Status'',​ care este înlocuit de parametrul ''​MPI_Request''​. În rest totul este identic ca la ''​MPI_Recv''​. +
- +
-=== MPI_Test === +
-Semnătura funcției:​ +
-<code c> +
-int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status) +
-</​code>​ +
- +
-unde: +
-  * ''​request''​ este cel de la funcția de send sau de receive, al cărui rezultat este testat +
-  * ''​flag''​ arată dacă operația de send sau de receive ​s-a terminat cu succes +
-  * ''​status''​ conține date legate de mesaj (relevante ​la operația de receive) +
- +
-=== MPI_Wait === +
-Semnătura funcției:​ +
-<code c> +
-int MPI_Wait(MPI_Request *request, MPI_Status *status) +
-</​code>​ +
- +
-unde: +
-  * ''​request''​ este cel de la funcția de send sau de receive, al cărui rezultat este testat +
-  * ''​status''​ conține date legate de mesaj (relevante la operația de receive) +
- +
-Mai întâi se testează folosind ''​MPI_Test''​ dacă o funcție (send sau receive) a terminat de trimis / primit datele. Dacă nu s-a completat operația de send / receive, atunci se va folosi ''​MPI_Wait''​. +
- +
-{{ :​apd:​laboratoare:​nonblocking.png?​700 |}} +
- +
-Exemplu de send-receive folosind funcții non-blocante:​ +
-<code c> +
-#include <​mpi.h>​ +
-#include <​stdio.h>​ +
-#include <​string.h>​ +
-#include <​unistd.h>​ +
- +
-#define MAX_LEN 10 +
- +
-int main(int argc, char *argv[]) ​ { +
-    int numtasks, rank, dest, source, count, flag, tag = 1; +
-    char inmsg[MAX_LEN],​ outmsg[] = "​Hello";​ +
-    MPI_Status status; +
-    MPI_Request request; +
- +
-    MPI_Init(&​argc,&​argv);​ +
-    MPI_Comm_size(MPI_COMM_WORLD,​ &​numtasks);​ +
-    MPI_Comm_rank(MPI_COMM_WORLD,​ &​rank);​ +
- +
-    if (rank == 0) { +
-        // procesul 0 trimite catre procesul 1 +
-        dest = 1; +
-        source = 1; +
- +
-        sleep(3); +
- +
-        MPI_Isend(outmsg,​ strlen(outmsg) + 1, MPI_CHAR, dest, tag, MPI_COMM_WORLD,​ &​request);​ +
-        MPI_Test(&​request,​ &flag, &​status);​ +
- +
-        if (flag) { +
-            printf("​[P0] The send operation is over\n"​);​ +
-        } else { +
-            printf("​[P0] The send operation is not over yet\n"​);​ +
-            MPI_Wait(&​request,​ &​status);​ +
-        } +
- +
-        printf("​[P0] The send operation is definitely over\n"​);​ +
-    } else if (rank == 1) { +
-        // procesul 1 asteapta mesaj de la procesul 0 +
-        dest = 0; +
-        source = 0; +
- +
-        sleep(1); +
- +
-        MPI_Irecv(inmsg,​ MAX_LEN, MPI_CHAR, source, tag, MPI_COMM_WORLD,​ &​request);​ +
-        MPI_Test(&​request,​ &flag, &​status);​ +
- +
-        if (flag) { +
-            printf("​[P1] The receive operation is over\n"​);​ +
-        } else { +
-            printf("​[P1] The receive operation is not over yet\n"​);​ +
-            MPI_Wait(&​request,​ &​status);​ +
-        } +
-         +
-        MPI_Get_count(&​status,​ MPI_CHAR, &​count);​ +
-        printf("​[P1] Received %d char(s) from process %d with tag %d: %s\n", count, status.MPI_SOURCE,​ status.MPI_TAG,​ inmsg); +
-    } +
- +
-    MPI_Finalize();​ +
-+
-</​code>​ +
- +
-==== Alte funcții de schimb de mesaje ==== +
-=== MPI_Ssend și MPI_Issend === +
-Funcția ''​MPI_Ssend''​ reprezintă o variantă sincronizată a funcției ''​MPI_Send'',​ care poate debloca comunicarea înainte ca procesul destinație să confirme că a primit cu succes toate datele trimise de către procesul sursă. +
- +
-''​MPI_Ssend''​ garantează că va fi deblocată comunicarea atunci când procesul destinație confirmă că a primit cu succes toate datele trimise de către procesul sursă, deci se poate considera că ''​MPI_Ssend''​ este o variantă mai sigură a funcției ''​MPI_Send''​. +
- +
-De notat faptul că ''​MPI_Send''​ se comportă ca ''​MPI_Ssend''​ atunci când se trimit date de dimensiuni mari. +
- +
-Un dezavantaj al acestei funcții față de ''​MPI_Send''​ este că ''​MPI_Ssend''​ este mai predispusă la situații de deadlock. +
- +
-Un exemplu de deadlock este următoarea situație:​ +
-<code c> +
-if (rank == 0) { +
-        MPI_Send(&​num1,​ SIZE, MPI_INT, 1, 0, MPI_COMM_WORLD);​ +
- // MPI_Ssend(&​num1,​ SIZE, MPI_INT, 1, 0, MPI_COMM_WORLD);​ +
-        MPI_Recv(&​num2,​ SIZE, MPI_INT, 1, 0, MPI_COMM_WORLD,​ MPI_STATUS_IGNORE);​ +
-} else { +
-        MPI_Send(&​num2,​ SIZE, MPI_INT, 0, 0, MPI_COMM_WORLD);​ +
-        // MPI_Ssend(&​num2,​ SIZE, MPI_INT, 1, 0, MPI_COMM_WORLD);​ +
-        MPI_Recv(&​num1,​ SIZE, MPI_INT, 0, 0, MPI_COMM_WORLD,​ MPI_STATUS_IGNORE);​ +
-+
-</​code>​ +
- +
-''​MPI_Issend''​ este varianta non-blocantă a funcției ''​MPI_Ssend''​. +
- +
-=== MPI_Bsend și MPI_Ibsend === +
-Funcția ''​MPI_Bsend''​ reprezintă o variantă a funcției ''​MPI_Send'',​ unde utilizatorul creează un buffer (folosind funcția ''​MPI_Buffer_attach''​),​ prin intermediul căruia sunt schimbate mesajele. În acest buffer ajung doar mesajele care au fost trimise folosind ''​MPI_Bsend''​. +
- +
-Această funcție este utilă pentru situațiile când avem deadlock și când se trimit date de dimensiuni mari, similar ca la comunicarea non-blocantă. Diferența față de comunicarea non-blocantă este că la ''​MPI_Bsend''​ se garantează,​ atunci când funcția întoarce un rezultat, că datele au fost copiate integral în buffer, în timp ce ''​MPI_Isend''​ nu garantează acest lucru. +
- +
-''​MPI_BSEND_OVERHEAD''​ reprezintă un overhead de memorie, care este creat atunci când se apelează ''​MPI_Bsend''​ sau ''​MPI_Ibsend''​. +
- +
-''​MPI_Ibsend''​ este varianta non-blocantă a funcției ''​MPI_Bsend''​. +
- +
-Exemplu de folosire: +
-<code c> +
-#include "​mpi.h"​ +
-#include <​stdio.h>​ +
-#include <​stdlib.h>​ +
-  +
-int main (int argc, char *argv[]) +
-+
-    int numtasks, rank; +
-    int size = 100; +
-    int arr[size];​ +
-  +
-    MPI_Init(&​argc,​ &​argv);​ +
-    MPI_Comm_size(MPI_COMM_WORLD,​ &​numtasks);​ +
-    MPI_Comm_rank(MPI_COMM_WORLD,​ &​rank);​ +
-  +
-    if (rank == 0) { +
-        for (int i = 0; i < size; i++) { +
-            arr[i] = i; +
-        } +
-  +
-        printf("​Process with rank [%d] has the following array:​\n",​ rank); +
-        for (int i = 0; i < size; i++) { +
-            printf("​%d ", arr[i]); +
-        } +
-        printf("​\n"​);​ +
- +
-   // declarăm mărimea buffer-ului +
-        int buffer_attached_size = MPI_BSEND_OVERHEAD + size * sizeof(int);​ +
-   // se creează spațiul folosit pentru buffer +
-        char* buffer_attached = malloc(buffer_attached_size);​ +
-   // se creează buffer-ul MPI folosit pentru trimiterea mesajelor +
-        MPI_Buffer_attach(buffer_attached,​ buffer_attached_size);​ +
-  +
-        MPI_Bsend(&​arr,​ size, MPI_INT, 1, 1, MPI_COMM_WORLD);​ +
-        printf("​Process with rank [%d] sent the array.\n",​ rank); +
- +
-   // se detașează buffer-ul folosit pentru trimiterea mesajelor și este distrus +
-        MPI_Buffer_detach(&​buffer_attached,​ &​buffer_attached_size);​ +
-        free(buffer_attached);​ +
-    } else { +
-        MPI_Status status; +
-        MPI_Recv(&​arr,​ size, MPI_INT, 0, 1, MPI_COMM_WORLD,​ &​status);​ +
-        printf("​Process with rank [%d], received array with tag %d.\n",​ +
-                rank, status.MPI_TAG);​ +
-  +
-        printf("​Process with rank [%d] has the following array:​\n",​ rank); +
-        for (int i = 0; i < size; i++) { +
-            printf("​%d ", arr[i]); +
-        } +
-        printf("​\n"​);​ +
-    } +
-  +
-    MPI_Finalize();​ +
-+
-</​code>​ +
- +
-=== MPI_Rsend și MPI_Irsend === +
-''​MPI_Rsend''​ reprezintă o variantă a funcției ''​MPI_Send'',​ care poate să fie folosită după execuția funcției de receive (doar atunci poate fi folosită această funcție, deși putem folosi atunci și ''​MPI_Send''​). +
- +
-Un exemplu de use case al acestei funcții este atunci când un proces A apelează ''​MPI_Recv''​ sau ''​MPI_Irecv''​ înainte de o barieră, iar un alt proces B apelează ''​MPI_Rsend''​ (unde B îi trimite date procesului A). +
- +
-''​MPI_Irsend''​ este varianta non-blocantă a funcției ''​MPI_Rsend''​. +
- +
-Exemplu de folosire: +
-<code c> +
-#include <​stdio.h>​ +
-#include <​stdlib.h>​ +
-#include <​mpi.h>​ +
-  +
-int main(int argc, char* argv[]) { +
-    int size, rank, value; +
- +
-    MPI_Init(&​argc,​ &​argv);​ +
-    MPI_Comm_size(MPI_COMM_WORLD,​ &​size);​ +
-    MPI_Comm_rank(MPI_COMM_WORLD,​ &​rank);​ +
-    if (rank == 0) { +
-        MPI_Barrier(MPI_COMM_WORLD);​ +
-  +
-        value = 12345; +
-        printf("​[P0] MPI process sends value %d.\n",​ value); +
-        MPI_Rsend(&​value,​ 1, MPI_INT, 1, 0, MPI_COMM_WORLD);​ +
-    } else { +
-        MPI_Request request; +
-        MPI_Status status; +
-        int flag; +
-        MPI_Irecv(&​value,​ 1, MPI_INT, 0, 0, MPI_COMM_WORLD,​ &​request);​ +
-  +
-        MPI_Barrier(MPI_COMM_WORLD);​ +
-  +
-        MPI_Test(&​request,​ &flag, &​status);​ +
- +
-        if (flag) { +
-            printf("​[P1] The receive operation is over\n"​);​ +
-        } else { +
-            printf("​[P1] The receive operation is not over yet\n"​);​ +
-            MPI_Wait(&​request,​ &​status);​ +
-        } +
-        printf("​[P1] MPI process received value %d.\n",​ value); +
-    } +
-  +
-    MPI_Finalize();​ +
-+
-</​code>​ +
- +
-=== MPI_Sendrecv === +
-În cadrul funcției ''​MPI_Sendrecv''​ se execută combinat operațiile de send și de receive, care sunt blocante în acest caz, unde mai precis se trimite un mesaj către un proces și se primește un alt mesaj de la un proces (poate să fie același proces căruia i s-a trimis mesajul sau un proces diferit). +
- +
-''​MPI_Sendrecv''​ este util în situații în care poate apărea deadlock, de exemplu trimiterea înlănțuită sau în ciclu de mesaje, unde fiecare proces să facă mai întâi send, apoi receive, fapt ce duce la dependență ciclică de date, care rezultă în deadlock. +
- +
-Exemplu de folosire: +
-<code c> +
-#include <​mpi.h>​ +
-#include <​stdio.h>​ +
-#include <​string.h>​ +
- +
-int main(int argc, char *argv[]) ​ { +
-    int numtasks, rank, dest, source, count, tag = 1; +
-    char inmsg, outmsg; +
-    MPI_Status status; +
- +
-    MPI_Init(&​argc,​ &​argv);​ +
-    MPI_Comm_size(MPI_COMM_WORLD,​ &​numtasks);​ +
-    MPI_Comm_rank(MPI_COMM_WORLD,​ &​rank);​ +
- +
-    if (rank == 0) { +
-        // procesul 0 trimite către procesul 1 și apoi așteaptă răspuns +
-        dest = 1; +
-        source = 1; +
- +
-        outmsg = '​0';​ +
-        MPI_Sendrecv(&​outmsg,​ 1, MPI_CHAR, dest, tag, +
-                        &inmsg, 1, MPI_CHAR, source, tag, MPI_COMM_WORLD,​ &​status);​ +
-    } else if (rank == 1) { +
-        // procesul 1 așteaptă mesaj de la procesul 0, apoi trimite răspuns +
-        dest = 0; +
-        source = 0; +
- +
-        outmsg = '​1';​ +
-        MPI_Sendrecv(&​outmsg,​ 1, MPI_CHAR, dest, tag, +
-                        &inmsg, 1, MPI_CHAR, source, tag, MPI_COMM_WORLD,​ &​status);​ +
-    } +
- +
-    // se folosește variabila de status pentru a afla detalii despre schimbul de date +
-    MPI_Get_count(&​status,​ MPI_CHAR, &​count);​ +
-    printf("​Process %d received %d char(s) from process %d with tag %d: %c\n",​ +
-            rank, count, status.MPI_SOURCE,​ status.MPI_TAG,​ inmsg); +
- +
-    MPI_Finalize();​ +
-+
-</​code>​ +
- +
-==== MPI_Barrier ==== +
-În MPI există conceptul de barieră, care este similar ca funcționalitate cu cea din pthreads și din Java threads. Mai precis, bariera din MPI asigură faptul că niciun proces din cadrul comunicatorului nu poate trece mai departe de punctul în care este plasată bariera decât atunci când toate procesele din comunicator ajung în acel punct. +
- +
-Semnătura funcției (varianta blocantă):​ +
-<code c> +
-int MPI_Barrier(MPI_Comm comm) +
-</​code>​ +
- +
-unde parametrul comm reprezintă comunicatorul MPI în care rulează procesele. +
- +
-De asemenea, există o versiune non-blocantă a barierei în MPI: +
-<code c> +
-int MPI_Ibarrier(MPI_Comm comm, MPI_Request *request) +
-</​code>​ +
- +
-Use case: Vreau să mă asigur că un proces a terminat de scris înainte ca altul să citească. Exemplu de folosire: +
- +
-<code c> +
-#include <​stdio.h>​ +
-#include <​mpi.h>​ +
-#include <​stdlib.h>​ +
-     +
-int main(int argc, char **argv) { +
-     +
-    MPI_File out; +
-    int rank, numtasks; +
-    int ierr; +
-     +
-    MPI_Init(&​argc,​ &​argv);​ +
-    MPI_Comm_rank(MPI_COMM_WORLD,​ &​rank);​ +
-    MPI_Comm_size(MPI_COMM_WORLD,​ &​numtasks);​ +
-     +
-    remove("​out.txt"​);​ +
- +
-    ierr = MPI_File_open(MPI_COMM_WORLD,​ "​out.txt",​ MPI_MODE_CREATE | MPI_MODE_RDWR,​ MPI_INFO_NULL,​ &​out);​ +
-    if (ierr) { +
-        if (rank == 0) fprintf(stderr,​ "%s: Couldn'​t open output file %s\n", argv[0], argv[2]); +
-        MPI_Finalize();​ +
-        exit(1); +
-    } +
-     +
-     +
-    if (rank == 0) { +
-        char message_to_write[5] = "​hello";​ +
-    MPI_File_write_at(out,​ 0, message_to_write,​ 5, MPI_CHAR, MPI_STATUS_IGNORE);​ +
-    } +
-     +
-    MPI_Barrier(MPI_COMM_WORLD);​ +
-     +
-    if (rank == 1) { +
-    char message_to_read[5];​ +
-    MPI_File_read_at(out,​ 0, message_to_read,​ 5, MPI_CHAR, MPI_STATUS_IGNORE);​ +
-    printf("​\nMesajul citit este: "); +
-        for (int i = 0; i < 5; i++) +
-        printf("​%c",​ message_to_read[i]);​ +
-        printf("​\n"​);​ +
-    } +
- +
-    MPI_File_close(&​out);​ +
-     +
-    MPI_Finalize();​ +
-    return 0; +
-+
-</​code>​ +
- +
-Pentru citirea și scrierea în fișier am folosit funcțiile ''​MPI_File_read_at''​ și ''​MPI_File_write_at''​. Amândouă citesc din fișier de la un offset specificat. +
- +
-<code c> +
-int MPI_File_read_at(MPI_File fh, MPI_Offset offset, void *buf, int count, MPI_Datatype datatype, MPI_Status *status) +
-</​code>​ +
- +
- +
-<note tip> +
-Mai multe despre lucrul cu fișiere în MPI puteți găsi aici: [[http://​wgropp.cs.illinois.edu/​courses/​cs598-s16/​lectures/​lecture32.pdf|MPI I/O]]. +
-</​note>​ +
- +
-==== Structuri în MPI ==== +
-În MPI putem să schimbăm date de tipul struct. Putem să facem acest lucru creând mai întâi un nou tip de date MPI (''​MPI_Datatype''​),​ folosind ''​MPI_Type_create_struct''​ căruia îi precizăm numărul câmpurilor de fiecare tip și mărimea lor din structură, așezarea câmpurilor în memorie (folosind //offsets// și ''​MPI_Aint''​). +
- +
-Semnătura funcției ''​MPI_Type_create_struct''​ este următoarea:​ +
- +
-<code c> +
-int MPI_Type_create_struct(int count, const int array_of_blocklengths[],​ const MPI_Aint array_of_displacements[],​ const MPI_Datatype array_of_types[],​ MPI_Datatype *newtype) +
-</​code>​ +
- +
-Și are următorii parametri:​ +
-  * ''​count''​ (↓) - număr de blocuri (de asemenea, numărul de intrări în vectorii array_of_types,​ array_of_displacements și array_of_blocklengths) +
-  * ''​array_of_blocklengths[]''​ (↓) - numărul de elemente din fiecare bloc +
-  * ''​MPI_Aint array_of_displacements[]''​ (↓) - deplasarea octeților pentru fiecare bloc +
-  * ''​array_of_types[]''​ (↓) - tipul de elemente din fiecare bloc +
-  * ''​*newtype''​ (↑) - noul tip de date +
- +
-<​note>​ +
-**Convenție**:​ parametrii de tip input sunt marcați cu ↓, iar parametrii de tip output cu ↑. +
-</​note>​ +
- +
-<note tip> +
-Deplasarea octeților pentru fiecare bloc se calculează cu ajutorul funcției ''​offsetof''​. Mai multe detalii despre folosirea ei puteți găsi aici: [[https://www.tutorialspoint.com/​c_standard_library/​c_macro_offsetof.htm|tutorialspoint]]. +
-</note> +
- +
- +
-Exemplu de folosire: +
-<code c> +
-#include <​mpi.h>​ +
-#include <​stdio.h>​ +
-#include <​stddef.h>​ +
- +
-// structura aflata la baza tipului custom +
-typedef struct { +
-    float f1, f2; +
-    char c; +
-    int i[2]; +
-} custom_type;​ +
- +
-int main(int argc, char *argv[]) ​ { +
-    int numtasks, rank, source = 0, dest = 1, tag = 1; +
- +
-    custom_type t; +
-    MPI_Datatype customtype, oldtypes[4];​ +
-    int blockcounts[4];​ +
-    MPI_Aint offsets[4];​ +
-    MPI_Status status; +
- +
-    MPI_Init(&​argc,​ &​argv);​ +
-    MPI_Comm_rank(MPI_COMM_WORLD,​ &​rank);​ +
-    MPI_Comm_size(MPI_COMM_WORLD,​ &​numtasks);​ +
- +
-    // campul f1 +
-    offsets[0] = offsetof(custom_type,​ f1); +
-    oldtypes[0] = MPI_FLOAT;​ +
-    blockcounts[0] = 1; +
- +
-    // campul f2 +
-    offsets[1] = offsetof(custom_type,​ f2); +
-    oldtypes[1] = MPI_FLOAT;​ +
-    blockcounts[1] = 1; +
- +
-    // campul c +
-    offsets[2] = offsetof(custom_type,​ c); +
-    oldtypes[2] = MPI_CHAR; +
-    blockcounts[2] = 1; +
- +
-    // campul i +
-    offsets[3] = offsetof(custom_type,​ i); +
-    oldtypes[3] = MPI_INT; +
-    blockcounts[3] = 2; +
- +
-    // se defineste tipul nou si se comite +
-    MPI_Type_create_struct(4,​ blockcounts,​ offsets, oldtypes, &​customtype);​ +
-    MPI_Type_commit(&​customtype);​ +
- +
-    if (rank == 0) { +
-        t.f1 = 0.5; +
-        t.f2 = -1.2; +
-        t.c = '​a';​ +
-        t.i[0] = 0; +
-        t.i[1] = 1; +
-        MPI_Send(&​t,​ 1, customtype, dest, tag, MPI_COMM_WORLD);​ +
-    } else if (rank == 1) { +
-        MPI_Recv(&​t,​ 1, customtype, source, tag, MPI_COMM_WORLD,​ &​status);​ +
-        printf("​Received custom type with f1=%.1f, f2=%.1f, c=%c, i[0]=%d, i[1]=%d\n",​ t.f1, t.f2, t.c, t.i[0], t.i[1]); +
-    } +
- +
-    // se elibereaza tipul nou cand nu se mai foloseste +
-    MPI_Type_free(&​customtype);​ +
- +
-    MPI_Finalize();​ +
-+
-</​code>​ +
- +
-==== Exerciții ==== +
-[[https://​github.com/​APD-UPB/​APD/​tree/​master/​laboratoare/​lab11 ​Scheletul de cod]] +
-  - Implementați algoritmul inel folosind folosind funcții non-blocante,​ folosind scheletul din ''​ring.c'',​ unde procesul cu id-ul 0 trimite un număr aleatoriu către procesul 1 (vecinul său), iar apoi celelalte noduri vor primi numărul de la procesul precedent, îl incrementează cu 2 și îl trimit la următorul proces (de exemplu procesul 2 primește valoarea de la procesul 1, o incrementează și o trimite mai departe procesului 3), totul terminându-se când valoarea ajunge la procesul 0. Pentru fiecare proces trebuie să afișați rangul acestuia și valoarea primită (hint: primul exercițiu din laboratorul 8). +
-  - Pornind de la schelet, folosiți bariera în fișierul ''​barrier.c''​ pentru a vă asigura că output-ul programului este mereu **1\n2\n3**. +
-  - Rezolvați deadlock-ul din fișierul ''​deadlock.c''​ din scheletul de laborator în 3 variante (verificați și hint-ul de mai jos): +
-     * folosind ''​MPI_Sendrecv''​ +
-     * folosind ''​MPI_Bsend''​ +
-     * folosind funcții non-blocante - aici în loc de ''​MPI_Test''​ și ''​MPI_Wait''​ folosiți [[https://​www.rookiehpc.com/​mpi/​docs/​mpi_waitall.php | MPI_Waitall]] +
-  - Plecând de la scheletul de cod din ''​queue.c'',​ unde rulează procesele în cadrul unei topologii inel, creați un nou tip de date în MPI, plecând de la structura definită în cod. Fiecare proces va genera un număr random, care va fi adăugat în structura respectivă,​ la final procesul 0 având fiecare număr generat de fiecare proces. După aceea, procesul 0 va afișa ce elemente se află în structura respectivă,​ care este o structură de tip coadă. +
- +
-<​note>​ +
-Pentru **exercițiul 3** puteți să vă folosiți de [[http://​www.idris.fr/​eng/​su/​shared/​mpi_send_recv-eng.html | acest hint]]. +
-</​note>​ +
- +
-<note tip> +
-Adăugarea în coadă se face în felul următor: ''​q.arr[q.size++] = element;''​ +
-</​note>​ +
apd/laboratoare/11.1642527486.txt.gz · Last modified: 2022/01/18 19:38 by elena.taran
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