diff --git a/README.md b/README.md index d97f62e17474db7b1a898feb47b3b91b1869145d..abb5bfa5601208565dda484bf12fa8f2a014b577 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,172 @@ -# Projet 3 +# README Group Q6 +# Authors : Giovanna Stefanelli, Lucas Bosmans, Aurélien Buxant and Yohan Burignat -Welcome to project 3! +Program: "fact" +## TABLE OF CONTENTS +* [0. General Info] +* [1. Installation Steps] +* [2. Programme General Architecture] +* [3. Main Data Structures] +* [4. Function Description] -Dans ce dossier se trouvent les fichiers initiaux pour le projet du cours LEPL1503. -- `example_input.txt` : Exemple de fichier d'entrée du projet. -- `example_output.txt` : Exemple de fichier de sortie correspondant au fichier exemple d'entrée. -- `prime_divs.py` : Programme python non optimisé. - Place pour chaque nombre dans le fichier d'entrée une ligne dans le fichier de sortie - "nombre div1 div2 ..." avec à la suite du nombre la liste de ses diviseurs premiers. - Le 1er argument du programme est le nom du fichier d'entrée, - et le deuxième est le nom du fichier de sortie - (il sera créé s'il n'existe pas, sinon son contenu sera remplacé). -- `test_prime_divs.py` : Programme de tests du programme `prime_divs.py`. -- `README.md` : Ce fichier. - - - -`Aim of the program`: +## 0. General Info This program allows to determine if a number is prime otherwise its prime dividers are calculated. - -The numbers to be considered shall be in an file (*.txt) then the program +The numbers to be considered shall be in an file (*.txt) then the programme can be called with this sintax: ./fact [-N number_of_threads] input_file.txt output_file.txt Whether the number of threads is not defined, the default number of threads is 2. -The program performance could not increase with a too high number of threads +The programme performance could not increase with a too high number of threads because, above all, it will depend on the machine architecture (e.g. number of cores). -The maximum number of threads allowed by the program is 20, nevertheless -the program "fact" can be updated by changing the constant MAX_NO_THREADS +The maximum number of threads allowed by the programme is 20, nevertheless +the programme "fact" can be updated by changing the constant MAX_NO_THREADS (#define MAX_NO_THREADS 20). + + +## 1. Installation Steps +The programme directory includes several files, a list is provided herebelow: +a. The C programme file "fact.c" +b. The "Makefile" with three basic "make" operations: + - "make fact" compiles "fact.c" and create the executable "fact" + (Note: in Windows we have "fact.exe") + - "make test" compiles "Fact_UnitTest.c", the unit tests are performed + with the command "make cunit", (Note: in Windows we have "Fact_UnitTest.exe"). + - "make clean" deletes the executable "fact", all the output files + with the prefix "out" (e.g. output.txt, out_result.txt, out.txt, ...) + and the files produced by unit tests. + To these basic operations more tags are provided, in particular: + - "make cunit" prepares the environment and execute the Cunit test + on the main "fact" functions. The result is redirected into the file + "Cunit_test_file.txt" + - "make valgrind" executes the tool valgrind on "fact" and the results + are redirected into the file "valgrind_fact.txt" + - "make cppcheck" executes the tool cppcheck on "fact" and the results + are redirected into the file "cppcheck_fact.txt". + - "make valgrind_cunit" executes the tool valgrind on "Fact_UnitTest" + and the results are redirected into the file "valgrind_cunit.txt". + - "make cppcheck_cunit" executes the tool cppcheck on "Fact_UnitTest" + and the results are redirected into the file "cppcheck_cunit.txt". + +c. The input file "example_input.txt" contains the numbers to be factorized (one + per line). This file allows to verify the correct calculation by comparing the + ouput with the results stored into another file: "example_output.txt". + Note: "example_input.txt" and "example_output.txt" are the files provided by + the project specification (at the initial project stage). These files + are not deleted by "make clean". + +d. The input file "incorrect_numbers.txt" contains numbers out of the scope of the + programme fact (e.g. numbers < 2). This file can be used for testing purposes. + +e. The file "Fact_UnitTest.c" contains the unit tests code exploiting the facility + of the "CUnit" library. + +f. The files "valgrind_fact.txt", "cppcheck_fact.txt" and "Cunit_test_file.txt" +are the output of valgrind, cppcheck tools and CUnit tests. + + + +## 2. Programme General Architecture +The programme architecture exploits threads to perform parallel factoring operations. +The architecture tries to reduce to the minimum the number of zones protected by +mutex to increase the general "fact" performances. Only one area in the programme +is protected by the concurrency (i.e. only one thread at a time is allowed). +In particular the set of instructions under mutex control are dedicated to write +the results in the output file, this is to avoid the overwriting of the final results +by the various active threads. +A general overview of "fact" architecture is depichted herebelow: + +main(argc,argv[]) is_prime +\/ / +Thread[1]--> read_write|--> prime_divs +| \ +| is_div is_prime +| / +Thread[2]--------> read_write|--------> prime_divs +| \ +| is_div is_prime +| / +Thread[3]--------------> read_write|--------------> prime_divs +: \ +: is_div +: is_prime +: / +Thread[n]--------------------> read_write|--------------------> prime_divs + \ + is_div +Note: This architecture can be easily adapted to parallel machine. + + + +## 3. Main Data Structures +Two major global data structure are used by the programme: +- the first stores: the number to factorised, the prime dividers and + number of dividers. The prime dividers are saved in an array. This buffer + has a lenght of 8 places but can be increased changing the constant + "N" in "#define N 8". The structure is: + +typedef struct factorization { + unsigned long prime_dividers[N]; + unsigned int cnt; + unsigned long number; +} factor; + +- the second data structure stores the file descriptors of the + input and output files. +The structure is: + +typedef struct file_descriptors { + FILE *in; + FILE *out; +} fd; + +The programme takes care of big number for a maximum of 64 bits. This is +implemented through the "unsigned long" type, nevertheless according +the target machine, the programme can be modified with different types +such as "unsigned long long" or "int64_t". The use of "int64_t" type +needs to include in the "fact" programme: "#include <stdint.h>". + + + +## 4. Function Description +As drawn in the scheme of the "Programme General Architecture" the programme +"fact" is composed by 4 functions: +-> void *read_write() + This function is activated by each threads created in the "main". + It is responsible for reading each number from the input file, + line by line, and for the writing of the number alone if prime, + otherwise the prime dividers are recorded after the number. +-> factor *prime_divs(unsigned long numbr) + This function is charged to calculate the prime dividers by calling + first "is_div" and in case a factor of the number is found, + "is_prime" is executed. + The calling sequence of "is_div" and "is_prime" it is important + because the function "is_prime" is more cpu time demanding. +-> bool is_prime(unsigned long nbr) + This function determines if a number is prime. To speed up the + computation, the algorithm is based on the "Sieve of Eratosthenes" + (see "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes") +-> bool is_div(unsigned long numbr, unsigned long i) + This function exploits the operator "%" (modulo) to determine if + a number has a divider. + +Finally, the "main" is charged to check the programme arguments correctness +(argc and argv[]) and, in case of error, a message is provided to +the user. The "fact" programme cannot calculate numbers < 2, a warning is +provided. +The "main" performs the following sequential actions: +- the start of cpu time, +- the input and output files are opened, in case of error this is reported, +- the mutex is initialised, +- the threads are created calling the function "read_write", +- the threads are joined, +- the cpu time is stopped and calculated, +- the mutex is destroyed, +- the input and output files are closed +- the main return zero. +