diff --git a/Makefile b/Makefile index 42f0455a546a8f971018d499a121af9c9ea8e8c6..2538dc08b24c75b6ac12dd9a30951122cd886321 100644 --- a/Makefile +++ b/Makefile @@ -1,36 +1,38 @@ -all : run +all : fact -run : run.o test.o - gcc -g -std=c99 -o run run.o test.o -lgmp -lpthread -I${HOME}/local/include -lcunit -L${HOME}/local/lib +fact : run.o test.o + gcc -g -std=c99 -o fact run.o test.o -lpthread -I${HOME}/local/include -lcunit -L${HOME}/local/lib run.o : run.c - gcc -g -std=c99 -o run.o -c run.c -W -Wall -lpthread -lgmp + gcc -g -std=c99 -o run.o -c run.c -W -Wall -lpthread test.o : test.c run.h - gcc -g -std=c99 -o test.o -c test.c -I${HOME}/local/include -W -Wall -lcunit -lpthread -lgmp + gcc -g -std=c99 -o test.o -c test.c -I${HOME}/local/include -W -Wall -lcunit -lpthread clean : - rm -rf *.o *.xml "actual_output.txt" + rm -rf fact *.o *.xml "actual_output.txt" -mrproper: clean - rm -rf run -prog : run - ./run +test : fact + ./fact Test -val_make : run - valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./run - -cpp_make : run.c +cpp : run.c cppcheck --enable=all run.c +cpp_xml : run.c + cppcheck --enable=all --inconclusive --xml --xml-version=2 run.c 2> cppcheck.xml + +val : fact + valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./fact Test_files/input.txt actual_output.txt + val_xml : run - valgrind --xml=yes --xml-file="valgrind.xml" --leak-check=yes ./run + valgrind --xml=yes --xml-file="valgrind.xml" --leak-check=yes ./fact Test_files/input.txt actual_output.txt + + + -cpp_xml : run.c - cppcheck --enable=all --inconclusive --xml --xml-version=2 run.c 2> cppcheck.xml \ No newline at end of file diff --git a/Projet_M2/Makefile b/Projet_M2/Makefile deleted file mode 100644 index 8ffd1d6bbb77b05e9e494e5bd7ec17f9c72e343d..0000000000000000000000000000000000000000 --- a/Projet_M2/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -all : fact - -fact : run.o test.o - gcc -g -std=c99 -o fact run.o test.o -lpthread -I${HOME}/local/include -lcunit -L${HOME}/local/lib - - - - -run.o : run.c - gcc -g -std=c99 -o run.o -c run.c -W -Wall -lpthread - - -test.o : test.c run.h - gcc -g -std=c99 -o test.o -c test.c -I${HOME}/local/include -W -Wall -lcunit -lpthread - - -clean : - rm -rf fact *.o *.xml "actual_output.txt" - - -test : fact - ./fact Test - -cpp : run.c - cppcheck --enable=all run.c - -val : fact - valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./fact Test_files/input.txt output.txt - - - - diff --git a/Projet_M2/README.md b/Projet_M2/README.md deleted file mode 100644 index e39f9e63e99905f39bdf66608693e21b380f223d..0000000000000000000000000000000000000000 --- a/Projet_M2/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# lepl1503-2020-groupe-M2 - -Pour compiler le programme : make fact - -Pour exécuter le fichier exécutable "fact" : ./fact [-N nombre_de_threads] input output - -Pour compiler et tester (suite de tests unitaires) le programme : make test - -Pour compiler et effectuer une analyse avec "Valgrind" : make val - -Pour effectuer une analyse avec "cppcheck" : make cpp - -Pour nettoyer les fichiers auxiliaires générés et l'exécutable : make clean - - -Architecture du programme: - -Le travail est décomposé en 3 sections coordonnées via un double problème du producteur-consommateur : - - -> 1 thread s'occupe de: - § lire le fichier input - - § stocker chacune des lignes sous forme de chaine de charactère dans un 1er tableau - - -> N threads s'occupent de : - § récupérer les chaines de caractères dans le premier tableau - - § les convertir en 'unsigned long long' et calculer leur liste de diviseurs premiers - - § Stocker ces listes dans un 2e tableau - - -> 1 thread s'occupe de : - § récupérer les listes de diviseurs dans le 2e tableau - - § Retranscrire dans le bon format le nombre à factoriser et ses diviseurs premiers dans le fichier output - -Note : - § Les accès aux tableaux sont coordonnés par des mutex (1 par tableau) et des sémaphores - - § Les diviseurs premiers d'un même nombre sont stockés dans une circular linked list - - -Architecture des tests : - -6 tests sont réalisés afin de tester: - - § La fonction is_div - § La fonction is_prime (2 tests) - § Le fonctionnement complet pour un fichier vide (N = 4) - § Le fonctionnement complet pour un fichier d'une ligne : check du format et des diviseurs (N = 4) - § Le fonctionnement complet pour un fichier de 100 lignes : check du nombre de lignes (réalisé avec N = 4 puis N = 1) - -# lepl1503-2020-groupe-M2 \ No newline at end of file diff --git a/Projet_M2/Test_files/empty_input.txt b/Projet_M2/Test_files/empty_input.txt deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/Projet_M2/Test_files/expected_output.txt b/Projet_M2/Test_files/expected_output.txt deleted file mode 100644 index ad8abbbd930238ad85a22ce807370392ecf04b65..0000000000000000000000000000000000000000 --- a/Projet_M2/Test_files/expected_output.txt +++ /dev/null @@ -1,100 +0,0 @@ -666343 7487 89 -463698 277 31 3 2 -1021406 7193 71 2 -506156 18077 7 2 -913231 1361 61 11 -268205 97 79 7 5 -982865 15121 13 5 -917451 101939 3 -499176 2311 3 2 -529973 -746782 5573 67 2 -276324 23027 3 2 -435465 9677 5 3 -352649 32059 11 -104121 503 23 3 -981518 113 101 43 2 -413102 206551 2 -880413 283 61 17 3 -676364 13007 13 2 -804603 4003 67 3 -1012028 2239 113 2 -364381 787 463 -780260 3001 13 5 2 -907169 -142193 -408465 313 29 5 3 -266175 13 7 5 3 -171413 15583 11 -518652 14407 3 2 -770297 293 239 11 -134273 191 37 19 -638327 -826830 9187 5 3 2 -220605 191 11 7 5 3 -162237 1319 41 3 -53202 8867 3 2 -494421 5683 29 3 -309475 12379 5 -361113 120371 3 -1033840 12923 5 2 -319499 -981506 1367 359 2 -404743 10939 37 -897560 1181 19 5 2 -1023027 3187 107 3 -354480 211 7 5 3 2 -793492 1667 17 7 2 -102802 1049 7 2 -843491 6971 11 -983760 4099 5 3 2 -404152 1031 7 2 -283682 881 23 7 2 -526652 2687 7 2 -1018 509 2 -324508 2617 31 2 -103308 8609 3 2 -9422 673 7 2 -793590 3779 7 5 3 2 -241316 61 43 23 2 -132914 66457 2 -978150 6521 5 3 2 -725819 38201 19 -828636 347 199 3 2 -224489 7741 29 -431210 107 31 13 5 2 -705190 727 97 5 2 -470751 4241 37 3 -182145 12143 5 3 -728190 31 29 5 3 2 -3574 1787 2 -813793 1933 421 -17035 3407 5 -795384 11047 3 2 -534134 5039 53 2 -498463 71209 7 -385529 197 103 19 -624262 683 457 2 -697671 89 67 13 3 -613191 204397 3 -866262 409 353 3 2 -58631 -290417 3499 83 -901545 60103 5 3 -86993 -607222 3943 11 7 2 -437288 1163 47 2 -122029 -840703 -647460 109 11 5 3 2 -42875 7 5 -135229 499 271 -1033268 258317 2 -361034 1861 97 2 -916343 39841 23 -739080 2053 5 3 2 -975089 -82667 6359 13 -670049 -640632 26693 3 2 -950453 163 17 7 diff --git a/Projet_M2/Test_files/input.txt b/Projet_M2/Test_files/input.txt deleted file mode 100644 index 752347539f6c0f52b7ab17164090538496e58ee5..0000000000000000000000000000000000000000 --- a/Projet_M2/Test_files/input.txt +++ /dev/null @@ -1,100 +0,0 @@ -666343 -463698 -1021406 -506156 -913231 -268205 -982865 -917451 -499176 -529973 -746782 -276324 -435465 -352649 -104121 -981518 -413102 -880413 -676364 -804603 -1012028 -364381 -780260 -907169 -142193 -408465 -266175 -171413 -518652 -770297 -134273 -638327 -826830 -220605 -162237 -53202 -494421 -309475 -361113 -1033840 -319499 -981506 -404743 -897560 -1023027 -354480 -793492 -102802 -843491 -983760 -404152 -283682 -526652 -1018 -324508 -103308 -9422 -793590 -241316 -132914 -978150 -725819 -828636 -224489 -431210 -705190 -470751 -182145 -728190 -3574 -813793 -17035 -795384 -534134 -498463 -385529 -624262 -697671 -613191 -866262 -58631 -290417 -901545 -86993 -607222 -437288 -122029 -840703 -647460 -42875 -135229 -1033268 -361034 -916343 -739080 -975089 -82667 -670049 -640632 -950453 diff --git a/Projet_M2/Test_files/short_expected_output.txt b/Projet_M2/Test_files/short_expected_output.txt deleted file mode 100644 index a0778ebfc98ae2779aa5d573883fb4c932f307a6..0000000000000000000000000000000000000000 --- a/Projet_M2/Test_files/short_expected_output.txt +++ /dev/null @@ -1 +0,0 @@ -981518 113 101 43 2 diff --git a/Projet_M2/Test_files/short_input.txt b/Projet_M2/Test_files/short_input.txt deleted file mode 100644 index aec1a34deb029de383a74552885b885bb7bcc561..0000000000000000000000000000000000000000 --- a/Projet_M2/Test_files/short_input.txt +++ /dev/null @@ -1 +0,0 @@ -981518 diff --git a/Projet_M2/run.c b/Projet_M2/run.c deleted file mode 100755 index 7c279fe4d7f23920aee61bc092e0bb63c0e62037..0000000000000000000000000000000000000000 --- a/Projet_M2/run.c +++ /dev/null @@ -1,441 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <pthread.h> -#include <semaphore.h> - -int N; -//travailler avec des linkendList -typedef struct node{ - unsigned long long value; - struct node *next; -}node_t; - -typedef struct queue{ - struct node *tail; - int size; - int final; -}queue_t; - -struct buffer_rc{ - char **tab; - int size; - int len; - int head; - int tail; - int stop; - FILE *file1; -}; - - -struct buffer_cw -{ - queue_t **tab; - int size; - int len; - int head; - int tail; - int stop; - FILE *file2; -}; - -struct buffer_rccw{ - struct buffer_rc *struct1; - struct buffer_cw *struct2; -}; - -/* sémaphore est une structure de donné qui contient : - *un entier qui stocke la valeur, positive ou nulle du sémaphore. - *une queue qui contient les pointeurs vers les threads -*/ -pthread_mutex_t mutex1; -sem_t empty1; -sem_t full1; - -pthread_mutex_t mutex2; -sem_t empty2; -sem_t full2; - - -void put_in_buffer_1(char *c, struct buffer_rc *ptr){ //ajouter un element dans le buffer 1 - - ptr->tab[ptr->head] = malloc(sizeof(c)); // on stoxke de espace - //ptr->tab[ptr->head] = c; - strcpy(ptr->tab[ptr->head],c); //copie - - ptr->len++; - ptr->head = (ptr->head + 1)%ptr->size; //chaque fois qu'un élément est ajouté, - //on augmente le pointeur de 1 mais l'espace du buffer est de size donc faire un modulo - -} - -char *get_from_buffer_1(struct buffer_rc *ptr){ // chercher dans le buffer 1 - char *result; - result = ptr->tab[ptr->tail]; // donne un valeur a result - //free(ptr->tab[ptr->tail]); - ptr->tab[ptr->tail] = NULL; - ptr->len--; //diminue l'espace occupé dans le buffer - ptr->tail = (ptr->tail + 1)%ptr->size; - - return result; -} - -void put_in_buffer_2(struct queue *ptr, struct buffer_cw *buf){ //ajouter un element dans le buffer 2 - buf->tab[buf->head] = malloc(sizeof(*ptr)); - buf->tab[buf->head] = ptr; - buf->len++; //augmente l'espace occupé dans le buffer - buf->head = (buf->head + 1)%buf->size; -} - -queue_t *get_from_buffer_2(struct buffer_cw *buf){ // trouver un element - - struct queue *result; - result = buf->tab[buf->tail]; //donne une valeur a result - buf->tab[buf->tail] = NULL; - buf->len--; //diminue l'espace occupé par le buffer - buf->tail = (buf->tail + 1)%buf->size; - - return result; -} - - -int is_div(unsigned long long number, unsigned long long i) { // Vérifie si i est un diviseur de number. - return (number % i == 0) ; // renvoie 0 si le nombre n'est pas divisible par i et 1 si il est divisible -} - - -int is_prime(unsigned long long number) { // Vérifie si number est un nombre premier. Return 1 si il est premier, 0 sinon - if (number != 2) { - if (number % 2 == 0) { - return 0 ; - } - } - for (unsigned long long i = 3 ; i <= (number/2); i = i + 2) { //regarde les differents nombres pouvant etre diviser number - if (is_div(number,i) != 0) { // si i peut diviser number - return 0 ; //renvoi 0 => FAUX - } - } - return 1 ; //sinon => VRAI -} - - -void enqueue(queue_t* q, unsigned long long val){ - - struct node new_node; - new_node.value = val; - new_node.next = malloc(sizeof(node_t)); - - struct node *ptr; - ptr = malloc(sizeof(node_t)); - if (ptr == NULL){ - free(ptr); - return;} - *ptr = new_node; - - if (q->size == 0) - { - *q->tail = *ptr; - *ptr->next = *ptr; - } - else{ - *ptr->next = *q->tail->next; - *q->tail->next = *ptr; - } - q->size++; - - //free(ptr->next); - free(ptr); - -} - - -queue_t* prime_divs(unsigned long long number){ - - struct queue new_queue; - new_queue.size = 0; - new_queue.final = 0; - new_queue.tail = malloc(sizeof(node_t)); - if(new_queue.tail==NULL){return NULL;} - - struct queue *ptr; - ptr = malloc(sizeof(queue_t)); - if (ptr == NULL){ - free(new_queue.tail); - free(ptr); - return NULL;} - *ptr = new_queue; - - for (unsigned long long i = 2; i <= number/2; i++){ - if (is_div(number, i) && is_prime(i) == 1){ - enqueue(ptr,i); - } - } - enqueue(ptr,number); - - return ptr; - -} - -void *writing(void *param){ - - struct buffer_cw *param1 = (struct buffer_cw *) param; - int stop = 0; - - while(param1->stop == 0){ - - sem_wait(&full2); - pthread_mutex_lock(&mutex2); - queue_t *pr_divs = get_from_buffer_2(param); - pthread_mutex_unlock(&mutex2); - sem_post(&empty2); - - if (pr_divs->final == 1) - { - - if (stop == N-1){ - for (int i = 0; i < param1->size; i++) - { - param1->tab[i] = NULL; - } - free(param1->tab); - free(pr_divs); - return NULL; - } - free(pr_divs); - stop++; - } - else{ - FILE *file2 = param1->file2; - - struct node *current; - current = malloc(sizeof(node_t)); - if (current == NULL){return NULL;} - *current = *pr_divs->tail; - current = current->next; - - fprintf(file2,"%llu",current->value); - current = current->next; - - for (int i = 1; i < pr_divs->size; i++) - { - fprintf(file2," %llu",current->value); - current = current->next; - } - fputc('\n',file2); - - //free(current); - } - - - } - - return NULL; -} - -void *calculating(void *param){ - - struct buffer_rccw *param1 = (struct buffer_rccw *) param; - - struct buffer_rc *buffer_1 = param1->struct1; - struct buffer_cw *buffer_2 = param1->struct2; - - while(buffer_1->stop == 0){ - - sem_wait(&full1); - pthread_mutex_lock(&mutex1); - char *chaine = get_from_buffer_1(buffer_1); - pthread_mutex_unlock(&mutex1); - sem_post(&empty1); - - if (strcmp("stop",chaine) == 0) - { - struct queue *final; - final = malloc(sizeof(queue_t)); - if (final == NULL){return NULL;} - - final->final = 1; - - sem_wait(&empty2); - pthread_mutex_lock(&mutex2); - put_in_buffer_2(final,buffer_2); - pthread_mutex_unlock(&mutex2); - sem_post(&full2); - - return NULL; - } - - - struct queue *pr_divs; - pr_divs = malloc(sizeof(queue_t)); - if (pr_divs == NULL){return NULL;} - - pr_divs = prime_divs(strtoll(chaine,NULL,0)); - - sem_wait(&empty2); - pthread_mutex_lock(&mutex2); - put_in_buffer_2(pr_divs,buffer_2); - pthread_mutex_unlock(&mutex2); - sem_post(&full2); - - } - - return NULL; -} - -void *reading (void *param){ - - struct buffer_rc *param1= (struct buffer_rc *) param; - - char chaine[30]; - - FILE *input; - input = param1->file1; - - while (fgets(chaine,30,input) != NULL){ - - sem_wait(&empty1); - pthread_mutex_lock(&mutex1); - - put_in_buffer_1(chaine,param1); //put each line in the buffer #1 - - pthread_mutex_unlock(&mutex1); - sem_post(&full1); - } - - for (int i = 0; i < N; i++) - { - sem_wait(&empty1); - pthread_mutex_lock(&mutex1); - - put_in_buffer_1("stop\0",param1); //put each stop line in the buffer #1 - - pthread_mutex_unlock(&mutex1); - sem_post(&full1); - } - - - return NULL; - -} - -void sem_1_initializer(struct buffer_rc *buf){ - pthread_mutex_init(&mutex1,NULL); - sem_init(&empty1,0,buf->size); - sem_init(&full1,0,0); - -} - -void sem_2_initializer (struct buffer_cw *buf){ - - pthread_mutex_init(&mutex2,NULL); - sem_init(&empty2,0,buf->size); - sem_init(&full2,0,0); - -} - -struct buffer_rc * buff_init_1(FILE *file1){ - - struct buffer_rc *ptr1; - ptr1 = malloc(sizeof(struct buffer_rc)); - if (ptr1 == NULL){ - free(ptr1); - return NULL;} - ptr1->tab = malloc(2*N*sizeof(char*)); - ptr1->size = 2*N; - ptr1->len = 0; - ptr1->head = 0; - ptr1->tail = 0; - ptr1->stop = 0; - ptr1->file1 = file1; - - return ptr1; -} - -struct buffer_cw * buff_init_2(FILE *file2){ - - struct buffer_cw *ptr2; - ptr2 = malloc(sizeof(struct buffer_cw)); - if (ptr2 == NULL){ - return NULL;} - - ptr2->tab = malloc(2*N*sizeof(struct queue*)); - ptr2->size = 2*N; - ptr2->len = 0; - ptr2->head = 0; - ptr2->tail = 0; - ptr2->stop = 0; - ptr2->file2 = file2; - - return ptr2; -} - -struct buffer_rccw *buff_init_12(struct buffer_rc *ptr1,struct buffer_cw *ptr2){ - struct buffer_rccw buffer_12; - buffer_12.struct1 = ptr1; - buffer_12.struct2 = ptr2; - - struct buffer_rccw *ptr3; - ptr3 = malloc(sizeof(struct buffer_rccw)); - if (ptr3 == NULL){return NULL;} - *ptr3 = buffer_12; - return ptr3; -} - -void thread_create_join(struct buffer_rc *ptr1,struct buffer_cw *ptr2,struct buffer_rccw *ptr3){ - pthread_t reader; - pthread_t calculators[N]; - pthread_t writer; - pthread_create(&reader,NULL,&reading,ptr1); - for (int i = 0; i < N; i++) - { - pthread_create(&calculators[i],NULL,&calculating,ptr3); - } - pthread_create(&writer,NULL,&writing,ptr2); - - pthread_join(reader,NULL); - for (int i = 0; i < N; i++) - { - pthread_join(calculators[i],NULL); - } - pthread_join(writer,NULL); -} - -int run (char *input,char *output, int n_threads){ - - N = n_threads; - - - FILE *file1 = NULL; - FILE *file2 = NULL; - - file1 = fopen(input,"r"); - if (file1 == NULL){ - printf("Sorry, file %s doesn't exist ): \n",input); - return -1;} - - file2 = fopen(output,"w+"); - if (file2 == NULL){ - fclose(file1); - return -1; - } - - struct buffer_rc *ptr1 = buff_init_1(file1); - struct buffer_cw *ptr2 = buff_init_2(file2); - struct buffer_rccw *ptr3 = buff_init_12(ptr1,ptr2); - - - sem_1_initializer(ptr1); - sem_2_initializer(ptr2); - - thread_create_join(ptr1,ptr2,ptr3); - - fclose(file1); - fclose(file2); - free(ptr1); - free(ptr2); - free(ptr3); - - return EXIT_SUCCESS; - -} diff --git a/Projet_M2/run.h b/Projet_M2/run.h deleted file mode 100644 index 1abc27782d04ff1cb8e791a968d5edd7e4640167..0000000000000000000000000000000000000000 --- a/Projet_M2/run.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef RUN -#define RUN -#include <pthread.h> -#include <semaphore.h> - -int N; - -typedef struct node{ - unsigned long long value; - struct node *next; -}node_t; - -typedef struct queue{ - struct node *tail; - int size; -}queue_t; - -struct buffer_rc{ - char **tab; - int size; - int len; - int head; - int tail; -}; - -struct buffer_cw -{ - queue_t **tab; - int size; - int len; - int head; - int tail; -}; - -struct buffer_rccw{ - struct buffer_rc *struct1; - struct buffer_cw *struct2; -}; - -pthread_mutex_t mutex1; -sem_t empty1; -sem_t full1; - -pthread_mutex_t mutex2; -sem_t empty2; -sem_t full2; - - -void put_in_buffer_1(char *c); -char *get_from_buffer_1(void); -void put_in_buffer_2(struct queue *ptr); -queue_t *get_from_buffer_2(void); - -int is_div(unsigned long long number, unsigned long long i); -int is_prime(unsigned long long number); - -void enqueue(queue_t* q, unsigned long long val); -queue_t* prime_divs(unsigned long long number); - -void *reading (void *param); -void *calculating(void *param); -void *writing(void *param); - -void sem_1_initializer(struct buffer_rc *buf); -void sem_2_initializer (struct buffer_cw *buf); - -struct buffer_rc * buff_init_1(FILE *file1); -struct buffer_cw * buff_init_2(FILE *file2); -struct buffer_rccw *buff_init_12(struct buffer_rc *ptr1,struct buffer_cw *ptr2); - -void thread_create_join(struct buffer_rc *ptr1,struct buffer_cw *ptr2,struct buffer_rccw *ptr3); - -int run (char *input,char *output,int n_threads); - -#endif \ No newline at end of file diff --git a/Projet_M2/test.c b/Projet_M2/test.c deleted file mode 100644 index 400695f394ee0d8e1397b081d23007f9dc47ccf3..0000000000000000000000000000000000000000 --- a/Projet_M2/test.c +++ /dev/null @@ -1,247 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include "run.h" -#include <CUnit/CUnit.h> -#include <CUnit/TestRun.h> -#include <CUnit/CUError.h> -#include <CUnit/Basic.h> -#include <CUnit/Automated.h> - -void test_is_div(void){ - CU_ASSERT_TRUE(is_div(14,7)); -} - -void test_is_prime(void){ - CU_ASSERT_TRUE(is_prime(13)); -} -void test_is_not_prime(void){ - CU_ASSERT_FALSE(is_prime(14)); -} -void empty_file_test(void){ - - FILE *file1 = NULL; - - int err = run("Test_files/empty_input.txt","actual_output.txt",4); - if (err == -1){ - CU_FAIL("method run failed"); - return; - } - - file1 = fopen("actual_output.txt","r"); - if (file1 == NULL){ - CU_FAIL("actual_output opening fail"); - return; - } - - char chaine1[20]; - CU_ASSERT_EQUAL(fgets(chaine1,20,file1),NULL); - - fclose(file1); - - -} -void short_file_test(void){ - FILE *file1 = NULL; - FILE *file2 = NULL; - - file1 = fopen("Test_files/short_expected_output.txt","r"); - if (file1 == NULL){ - CU_FAIL("short_expected_output opening fail"); - return; - } - - int err = run("Test_files/short_input.txt","actual_output.txt",4); - if (err == -1){ - CU_FAIL("method run failed"); - fclose(file1); - return; - } - - file2 = fopen("actual_output.txt","r"); - if (file2 == NULL){ - CU_FAIL("actual_output opening fail"); - fclose(file1); - - return; - } - - char chaine1[50]; - char chaine2[50]; - - while (fgets(chaine1,50,file1) != NULL && fgets(chaine2,50,file2) != NULL) - { - //printf("%s\n",chaine1); - //printf("%s\n",chaine2); - CU_ASSERT_STRING_EQUAL(chaine1,chaine2); - - } - - fclose(file1); - fclose(file2); -} - -void file_test_N_4(void){ - FILE *file1 = NULL; - FILE *file2 = NULL; - - file1 = fopen("Test_files/expected_output.txt","r"); - if (file1 == NULL){ - CU_FAIL("expected_output opening fail"); - return; - } - - clock_t start, end; - double time; - start = clock(); - - int err = run("Test_files/input.txt","actual_output.txt",4); - - end = clock(); - time = (double) (end - start) / CLOCKS_PER_SEC; - printf("Temps pour 4 threads de calculs = %.2f secondes \n",time); - if (err == -1){ - CU_FAIL("method run failed"); - fclose(file1); - return; - } - - file2 = fopen("actual_output.txt","r"); - if (file2 == NULL){ - CU_FAIL("actual_output opening fail"); - fclose(file1); - return; - } - - char chaine2[50]; - - int n = 0; - - while (fgets(chaine2,50,file2) != NULL) - { - n++; - } - CU_ASSERT_EQUAL(n,100); - - fclose(file1); - fclose(file2); - -} - -void file_test_N_1(void){ - FILE *file1 = NULL; - FILE *file2 = NULL; - - file1 = fopen("Test_files/expected_output.txt","r"); - if (file1 == NULL){ - CU_FAIL("expected_output opening fail"); - return; - } - - clock_t start, end; - double time; - start = clock(); - - int err = run("Test_files/input.txt","actual_output.txt",1); - - end = clock(); - time = (double) (end - start) / CLOCKS_PER_SEC; - printf("Temps pour 1 thread de calcul = %.2f secondes \n",time); - if (err == -1){ - CU_FAIL("method run failed"); - fclose(file1); - return; - } - - file2 = fopen("actual_output.txt","r"); - if (file2 == NULL){ - CU_FAIL("actual_output opening fail"); - fclose(file1); - return; - } - - char chaine2[50]; - - int n = 0; - - while (fgets(chaine2,50,file2) != NULL) - { - n++; - } - CU_ASSERT_EQUAL(n,100); - - fclose(file1); - fclose(file2); - -} - -int setup(void){ - return 0; - } - - int teardown(void) - { - return 0; - } - -int main(int argc, char *argv[]){ - - if (argc == 2 && strcmp(argv[1],"Test")==0){ - - if (CUE_SUCCESS != CU_initialize_registry()) - { - return CU_get_error(); - } - - - CU_pSuite pSuite = NULL; - - pSuite = CU_add_suite("ma_suite",setup,teardown); - - if (NULL == pSuite) - { - CU_cleanup_registry(); - return CU_get_error(); - } - - if (NULL == CU_add_test(pSuite,"test_is_div",test_is_div) || - NULL == CU_add_test(pSuite, "test_is_prime",test_is_prime) || - NULL == CU_add_test(pSuite, "test_is_not_prime",test_is_not_prime) || - NULL == CU_add_test(pSuite,"empty_file_test",empty_file_test) || - NULL == CU_add_test(pSuite,"short_file_test",short_file_test) || - NULL == CU_add_test(pSuite,"file_test : N = 4",file_test_N_4) || - NULL == CU_add_test(pSuite,"file_test N = 1",file_test_N_1)) - { - CU_cleanup_registry(); - return CU_get_error(); - } - - - CU_basic_run_tests(); - //CU_automated_run_tests(); - CU_basic_show_failures(CU_get_failure_list()); - } - else - { - if (argc == 5 && strcmp("-N",argv[1])==0){ - int err = run(argv[3],argv[4],atoi(argv[2])); - if (err == -1){return EXIT_FAILURE;} - - - } - else - { - if (argc == 3){ - - int err = run(argv[1],argv[2],4); - if (err == -1){return EXIT_FAILURE;} - } - else{ - printf("Invalid type of number of arguments, please try again with the right format\n"); - return EXIT_FAILURE; - } - } - return EXIT_SUCCESS; - } - return EXIT_SUCCESS; - -} \ No newline at end of file diff --git a/README.md b/README.md index 978d5077bdc018292249836c91848e415aedf3e5..8d3b946e2b3617f1ec094be92c532b28227852be 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,57 @@ # lepl1503-2020-groupe-M2 -Pour compiler et exécuter (tester) le programme : make prog +Pour compiler le programme : make fact -Pour compiler et effectuer une analyse avec "Valgrind" : make val_make +Pour exécuter le fichier exécutable "fact" : ./fact [-N nombre_de_threads] input output -Pour compiler et obtenir l'analyse .xml de "Valgrind" : make val_xml +Pour compiler et tester (suite de tests unitaires) le programme : make test -Pour compiler et effctuer une analyse avec "cppcheck" : make cpp_make +Pour compiler et effectuer une analyse avec "Valgrind" : make val -Pour compiler et obtenir l'analyse .xml de "cppcheck" : make cpp_xml +Pour compiler, et obtenir le rapport d'analyse .xml de "Valgrind" : make val_xml -Pour nettoyer les fichiers .o et .xml : make mrproper +Pour effectuer une analyse avec "cppcheck" : make cpp + +Pour compiler et obtenir le rapport d'analyse .xml de "cppcheck" : make cpp_xml + +Pour nettoyer les fichiers auxiliaires générés et l'exécutable : make clean + + +Architecture du programme: + +Le travail est décomposé en 3 sections coordonnées via un double problème du producteur-consommateur : + + -> 1 thread s'occupe de: + § lire le fichier input + + § stocker chacune des lignes sous forme de chaine de charactère dans un 1er tableau + + -> N threads s'occupent de : + § récupérer les chaines de caractères dans le premier tableau + + § les convertir en 'unsigned long long' et calculer leur liste de diviseurs premiers + + § Stocker ces listes dans un 2e tableau + + -> 1 thread s'occupe de : + § récupérer les listes de diviseurs dans le 2e tableau + + § Retranscrire dans le bon format le nombre à factoriser et ses diviseurs premiers dans le fichier output + +Note : + § Les accès aux tableaux sont coordonnés par des mutex (1 par tableau) et des sémaphores + + § Les diviseurs premiers d'un même nombre sont stockés dans une circular linked list + + +Architecture des tests : + +6 tests sont réalisés afin de tester: + + § La fonction is_div + § La fonction is_prime (2 tests) + § Le fonctionnement complet pour un fichier vide (N = 4) + § Le fonctionnement complet pour un fichier d'une ligne : check du format et des diviseurs (N = 4) + § Le fonctionnement complet pour un fichier de 100 lignes : check du nombre de lignes (réalisé avec N = 4 puis N = 1) + +# lepl1503-2020-groupe-M2 \ No newline at end of file diff --git a/run.c b/run.c index 6d38097f2730570984bf6e94dfb06cf02fffc909..7c279fe4d7f23920aee61bc092e0bb63c0e62037 100755 --- a/run.c +++ b/run.c @@ -1,14 +1,11 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <fcntl.h> #include <unistd.h> -#include <sys/stat.h> - #include <pthread.h> #include <semaphore.h> -#define N 4 +int N; //travailler avec des linkendList typedef struct node{ unsigned long long value; @@ -22,7 +19,7 @@ typedef struct queue{ }queue_t; struct buffer_rc{ - char *tab[2*N]; + char **tab; int size; int len; int head; @@ -34,7 +31,7 @@ struct buffer_rc{ struct buffer_cw { - queue_t *tab[2*N]; + queue_t **tab; int size; int len; int head; @@ -66,9 +63,10 @@ void put_in_buffer_1(char *c, struct buffer_rc *ptr){ //ajouter un element dans ptr->tab[ptr->head] = malloc(sizeof(c)); // on stoxke de espace //ptr->tab[ptr->head] = c; strcpy(ptr->tab[ptr->head],c); //copie - ptr->len++; // augmente l'espace occupé par le buffer + + ptr->len++; ptr->head = (ptr->head + 1)%ptr->size; //chaque fois qu'un élément est ajouté, - //on augmente le pointeur de 1 mais l'espace du buffer est de 8 donc faire un modulo + //on augmente le pointeur de 1 mais l'espace du buffer est de size donc faire un modulo } @@ -77,23 +75,24 @@ char *get_from_buffer_1(struct buffer_rc *ptr){ // chercher dans le buffer 1 result = ptr->tab[ptr->tail]; // donne un valeur a result //free(ptr->tab[ptr->tail]); ptr->tab[ptr->tail] = NULL; - ptr->len--; //diminue l'espace occupé par le buffer + ptr->len--; //diminue l'espace occupé dans le buffer ptr->tail = (ptr->tail + 1)%ptr->size; return result; } void put_in_buffer_2(struct queue *ptr, struct buffer_cw *buf){ //ajouter un element dans le buffer 2 - + buf->tab[buf->head] = malloc(sizeof(*ptr)); buf->tab[buf->head] = ptr; - buf->len++; //augmenté l'espace occupé par le buffer + buf->len++; //augmente l'espace occupé dans le buffer buf->head = (buf->head + 1)%buf->size; } queue_t *get_from_buffer_2(struct buffer_cw *buf){ // trouver un element - //printf("%d\n",buf->len); + struct queue *result; result = buf->tab[buf->tail]; //donne une valeur a result + buf->tab[buf->tail] = NULL; buf->len--; //diminue l'espace occupé par le buffer buf->tail = (buf->tail + 1)%buf->size; @@ -102,7 +101,7 @@ queue_t *get_from_buffer_2(struct buffer_cw *buf){ // trouver un element int is_div(unsigned long long number, unsigned long long i) { // Vérifie si i est un diviseur de number. - return (number % i == 0) ; // revoi 0 si le nombre n'est pas divisible par i et 1 si il est divisible + return (number % i == 0) ; // renvoie 0 si le nombre n'est pas divisible par i et 1 si il est divisible } @@ -123,14 +122,16 @@ int is_prime(unsigned long long number) { // Vérifie si number est un nombre pr void enqueue(queue_t* q, unsigned long long val){ - + struct node new_node; + new_node.value = val; + new_node.next = malloc(sizeof(node_t)); + struct node *ptr; ptr = malloc(sizeof(node_t)); if (ptr == NULL){ free(ptr); return;} - ptr -> value = val; - ptr -> next = malloc(sizeof(node_t)); + *ptr = new_node; if (q->size == 0) { @@ -142,7 +143,8 @@ void enqueue(queue_t* q, unsigned long long val){ *q->tail->next = *ptr; } q->size++; - //return q; + + //free(ptr->next); free(ptr); } @@ -190,15 +192,20 @@ void *writing(void *param){ if (pr_divs->final == 1) { - //printf("final : %d\n",pr_divs->final); + if (stop == N-1){ + for (int i = 0; i < param1->size; i++) + { + param1->tab[i] = NULL; + } + free(param1->tab); + free(pr_divs); return NULL; } + free(pr_divs); stop++; } else{ - - FILE *file2 = param1->file2; struct node *current; @@ -216,8 +223,10 @@ void *writing(void *param){ current = current->next; } fputc('\n',file2); + + //free(current); } - + } @@ -252,6 +261,7 @@ void *calculating(void *param){ put_in_buffer_2(final,buffer_2); pthread_mutex_unlock(&mutex2); sem_post(&full2); + return NULL; } @@ -261,14 +271,13 @@ void *calculating(void *param){ if (pr_divs == NULL){return NULL;} pr_divs = prime_divs(strtoll(chaine,NULL,0)); - + sem_wait(&empty2); pthread_mutex_lock(&mutex2); put_in_buffer_2(pr_divs,buffer_2); pthread_mutex_unlock(&mutex2); sem_post(&full2); - } return NULL; @@ -281,9 +290,7 @@ void *reading (void *param){ char chaine[30]; FILE *input; - //input = malloc(sizeof(FILE*)); input = param1->file1; - while (fgets(chaine,30,input) != NULL){ @@ -295,14 +302,13 @@ void *reading (void *param){ pthread_mutex_unlock(&mutex1); sem_post(&full1); } - //param1->stop = 1; for (int i = 0; i < N; i++) { sem_wait(&empty1); pthread_mutex_lock(&mutex1); - put_in_buffer_1("stop\0",param1); //put each line in the buffer #1 + put_in_buffer_1("stop\0",param1); //put each stop line in the buffer #1 pthread_mutex_unlock(&mutex1); sem_post(&full1); @@ -335,6 +341,7 @@ struct buffer_rc * buff_init_1(FILE *file1){ if (ptr1 == NULL){ free(ptr1); return NULL;} + ptr1->tab = malloc(2*N*sizeof(char*)); ptr1->size = 2*N; ptr1->len = 0; ptr1->head = 0; @@ -352,6 +359,7 @@ struct buffer_cw * buff_init_2(FILE *file2){ if (ptr2 == NULL){ return NULL;} + ptr2->tab = malloc(2*N*sizeof(struct queue*)); ptr2->size = 2*N; ptr2->len = 0; ptr2->head = 0; @@ -393,13 +401,18 @@ void thread_create_join(struct buffer_rc *ptr1,struct buffer_cw *ptr2,struct buf pthread_join(writer,NULL); } -int run (char *input,char *output){ +int run (char *input,char *output, int n_threads){ + + N = n_threads; + FILE *file1 = NULL; FILE *file2 = NULL; file1 = fopen(input,"r"); - if (file1 == NULL){return -1;} + if (file1 == NULL){ + printf("Sorry, file %s doesn't exist ): \n",input); + return -1;} file2 = fopen(output,"w+"); if (file2 == NULL){ @@ -410,6 +423,7 @@ int run (char *input,char *output){ struct buffer_rc *ptr1 = buff_init_1(file1); struct buffer_cw *ptr2 = buff_init_2(file2); struct buffer_rccw *ptr3 = buff_init_12(ptr1,ptr2); + sem_1_initializer(ptr1); sem_2_initializer(ptr2); @@ -422,6 +436,6 @@ int run (char *input,char *output){ free(ptr2); free(ptr3); - return 0; + return EXIT_SUCCESS; } diff --git a/run.h b/run.h index 1fb783e404e32734d6d837d3653c190881bf2b2a..1abc27782d04ff1cb8e791a968d5edd7e4640167 100644 --- a/run.h +++ b/run.h @@ -3,6 +3,8 @@ #include <pthread.h> #include <semaphore.h> +int N; + typedef struct node{ unsigned long long value; struct node *next; @@ -14,7 +16,7 @@ typedef struct queue{ }queue_t; struct buffer_rc{ - char *tab[8]; + char **tab; int size; int len; int head; @@ -23,7 +25,7 @@ struct buffer_rc{ struct buffer_cw { - queue_t *tab[8]; + queue_t **tab; int size; int len; int head; @@ -49,7 +51,7 @@ char *get_from_buffer_1(void); void put_in_buffer_2(struct queue *ptr); queue_t *get_from_buffer_2(void); -int is_div(unsigned long long number, long i); +int is_div(unsigned long long number, unsigned long long i); int is_prime(unsigned long long number); void enqueue(queue_t* q, unsigned long long val); @@ -68,6 +70,6 @@ struct buffer_rccw *buff_init_12(struct buffer_rc *ptr1,struct buffer_cw *ptr2); void thread_create_join(struct buffer_rc *ptr1,struct buffer_cw *ptr2,struct buffer_rccw *ptr3); -int run (char *input,char *output); +int run (char *input,char *output,int n_threads); -#endif +#endif \ No newline at end of file diff --git a/test.c b/test.c index bef6de0a1dd9236a1f3717ff2152809504f78f0b..400695f394ee0d8e1397b081d23007f9dc47ccf3 100644 --- a/test.c +++ b/test.c @@ -18,9 +18,10 @@ void test_is_not_prime(void){ CU_ASSERT_FALSE(is_prime(14)); } void empty_file_test(void){ + FILE *file1 = NULL; - int err = run("Test_files/empty_input.txt","actual_output.txt"); + int err = run("Test_files/empty_input.txt","actual_output.txt",4); if (err == -1){ CU_FAIL("method run failed"); return; @@ -36,7 +37,7 @@ void empty_file_test(void){ CU_ASSERT_EQUAL(fgets(chaine1,20,file1),NULL); fclose(file1); - + } void short_file_test(void){ @@ -48,16 +49,19 @@ void short_file_test(void){ CU_FAIL("short_expected_output opening fail"); return; } - - int err = run("Test_files/short_input.txt","actual_output.txt"); + + int err = run("Test_files/short_input.txt","actual_output.txt",4); if (err == -1){ CU_FAIL("method run failed"); + fclose(file1); return; } - + file2 = fopen("actual_output.txt","r"); if (file2 == NULL){ CU_FAIL("actual_output opening fail"); + fclose(file1); + return; } @@ -76,7 +80,7 @@ void short_file_test(void){ fclose(file2); } -void file_test(void){ +void file_test_N_4(void){ FILE *file1 = NULL; FILE *file2 = NULL; @@ -89,36 +93,80 @@ void file_test(void){ clock_t start, end; double time; start = clock(); - - int err = run("Test_files/input.txt","actual_output.txt"); + + int err = run("Test_files/input.txt","actual_output.txt",4); end = clock(); time = (double) (end - start) / CLOCKS_PER_SEC; - printf("Temps = %.2f secondes \n",time); + printf("Temps pour 4 threads de calculs = %.2f secondes \n",time); if (err == -1){ CU_FAIL("method run failed"); + fclose(file1); + return; + } + + file2 = fopen("actual_output.txt","r"); + if (file2 == NULL){ + CU_FAIL("actual_output opening fail"); + fclose(file1); + return; + } + + char chaine2[50]; + + int n = 0; + + while (fgets(chaine2,50,file2) != NULL) + { + n++; + } + CU_ASSERT_EQUAL(n,100); + + fclose(file1); + fclose(file2); + +} + +void file_test_N_1(void){ + FILE *file1 = NULL; + FILE *file2 = NULL; + + file1 = fopen("Test_files/expected_output.txt","r"); + if (file1 == NULL){ + CU_FAIL("expected_output opening fail"); return; } + clock_t start, end; + double time; + start = clock(); + + int err = run("Test_files/input.txt","actual_output.txt",1); + + end = clock(); + time = (double) (end - start) / CLOCKS_PER_SEC; + printf("Temps pour 1 thread de calcul = %.2f secondes \n",time); + if (err == -1){ + CU_FAIL("method run failed"); + fclose(file1); + return; + } + file2 = fopen("actual_output.txt","r"); if (file2 == NULL){ CU_FAIL("actual_output opening fail"); + fclose(file1); return; } - //char chaine1[50]; char chaine2[50]; int n = 0; while (fgets(chaine2,50,file2) != NULL) { - //printf("%s\n",chaine1); - //printf("%s\n",chaine2); - //CU_ASSERT_STRING_EQUAL(chaine1,chaine2); n++; } - //printf("%d",n); CU_ASSERT_EQUAL(n,100); fclose(file1); @@ -135,37 +183,65 @@ int setup(void){ return 0; } -int main(){ +int main(int argc, char *argv[]){ - if (CUE_SUCCESS != CU_initialize_registry()) - { - return CU_get_error(); - } + if (argc == 2 && strcmp(argv[1],"Test")==0){ + if (CUE_SUCCESS != CU_initialize_registry()) + { + return CU_get_error(); + } - CU_pSuite pSuite = NULL; - pSuite = CU_add_suite("ma_suite",setup,teardown); + CU_pSuite pSuite = NULL; - if (NULL == pSuite) - { - CU_cleanup_registry(); - return CU_get_error(); - } + pSuite = CU_add_suite("ma_suite",setup,teardown); - if (NULL == CU_add_test(pSuite,"test_is_div",test_is_div) || - NULL == CU_add_test(pSuite, "test_is_prime",test_is_prime) || - NULL == CU_add_test(pSuite, "test_is_not_prime",test_is_not_prime) || - NULL == CU_add_test(pSuite,"empty_file_test",empty_file_test) || - NULL == CU_add_test(pSuite,"short_file_test",short_file_test) || - NULL == CU_add_test(pSuite,"file_test",file_test)) - { - CU_cleanup_registry(); - return CU_get_error(); - } + if (NULL == pSuite) + { + CU_cleanup_registry(); + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite,"test_is_div",test_is_div) || + NULL == CU_add_test(pSuite, "test_is_prime",test_is_prime) || + NULL == CU_add_test(pSuite, "test_is_not_prime",test_is_not_prime) || + NULL == CU_add_test(pSuite,"empty_file_test",empty_file_test) || + NULL == CU_add_test(pSuite,"short_file_test",short_file_test) || + NULL == CU_add_test(pSuite,"file_test : N = 4",file_test_N_4) || + NULL == CU_add_test(pSuite,"file_test N = 1",file_test_N_1)) + { + CU_cleanup_registry(); + return CU_get_error(); + } - CU_basic_run_tests(); - CU_automated_run_tests(); - CU_basic_show_failures(CU_get_failure_list()); + + CU_basic_run_tests(); + //CU_automated_run_tests(); + CU_basic_show_failures(CU_get_failure_list()); + } + else + { + if (argc == 5 && strcmp("-N",argv[1])==0){ + int err = run(argv[3],argv[4],atoi(argv[2])); + if (err == -1){return EXIT_FAILURE;} + + + } + else + { + if (argc == 3){ + + int err = run(argv[1],argv[2],4); + if (err == -1){return EXIT_FAILURE;} + } + else{ + printf("Invalid type of number of arguments, please try again with the right format\n"); + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; + } + return EXIT_SUCCESS; + } \ No newline at end of file