diff --git a/tp5/tp5.md b/tp5/tp5.md
new file mode 100644
index 0000000000000000000000000000000000000000..78515c8e3e8c52e7a37a52b4c8dc070561519bbd
--- /dev/null
+++ b/tp5/tp5.md
@@ -0,0 +1,303 @@
+# Introduction
+
+## Appels systèmes et fonctions utiles
+
+Deux appels systèmes permettent de manipuler directement la table des
+pages d'un processus :
+
+  - `mmap` : ajoute une ou plusieurs pages à l'espace d'adressage
+    virtuelle d'un processus. Les pages ajoutées peuvent être
+    initialisées à partir d'un fichier (p.ex. pour lire depuis/écrire
+    vers ce fichier), ou être anonyme (pages « vides », mises à 0). Ces
+    pages peuvent être marquées privées (*copy on write*), ou partagées.
+    Une page partagée reste commune au processus parent et ses éventuels
+    enfants **même en cas de modification de son contenu**. Lors de
+    l'appel à `mmap`, la taille de la zone doit être connue et ne peut
+    ensuite plus être modifiée.
+  - `munmap` : efface une ou plusieurs entrées de la table des pages
+    d'un processus.
+
+# Travail à réaliser
+
+## *Memory-mapped-ios*
+
+En partant du fichier suivant, comparer les performances des
+entrées-sorties utilisant des appels systèmes (ici `read` et `write`),
+et des entrées-sorties exploitant directement le système de mémoire
+virtuelle.
+
+Pour cela, vous devez dans un premier temps compléter le fichier source
+ci-dessous en donnant le code de la fonction `copy_with_mmap`. Cette
+fonction doit copier le contenu du fichier `in.bin` vers le fichier
+`out.bin`. Pour cela, elle doit créer des pages associées à ces fichiers
+dans son espace de mémoire virtuel, puis utiliser la fonction standard
+`memcpy` pour effectuer la copie. Enfin, les pages doivent être
+supprimées de l'espace virtuel et les fichiers sources et destinations
+doivent être fermées. Pour connaître la taille du fichier à copier, et
+ainsi déterminer le nombre de page à créer, il est possible d'utiliser
+l'appel système `fstat`.
+
+Une fois que la fonction est codée, vous pourrez comparez les
+performances des deux approches pour différentes tailles de fichier
+source. Pour allouer rapidement un fichier d'une taille donnée, vous
+pouvez utiliser la commande `fallocate` comme ci-dessous (dans
+l'exemple, un fichier de 16MiB est alloué). À noter qu'il faut d'abord
+effacer le fichier pour que la taille demandée soit effectivement prise
+en considération.
+
+``` bash
+rm in.txt
+fallocate -l $((16 * 1024 * 1024)) in.txt
+```
+
+Si la commande `fallocate` n'est pas disponible, vous pouvez utiliser la
+commande `dd` qui est un peu plus lente :
+
+``` bash
+dd if=/dev/urandom of=in.txt bs=1024 count=$$((16 * 1024))
+```
+
+Enfin, un dernier point important : pour que vos tests soient
+pertinents, sur les machines du parc pédagogique de l'IUT, assurez vous
+que les fichiers sources et destinations se situent sur un dossier local
+de la machine. Dans le cas contraire, les performances seront dominées
+par les latences du réseau et ne permettront pas d'observer la
+différence entre les deux techniques d'entrées-sorties.
+
+``` c
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+/**
+ * copy the file using systems io
+ */
+void copy_with_read()
+{
+    int src = open("in.bin", O_RDONLY, S_IRUSR|S_IWUSR);
+    int dst = open("out.bin", O_WRONLY|O_TRUNC|O_CREAT, S_IRUSR|S_IWUSR);
+
+    char buff[4096];
+    ssize_t nread;
+
+    while((nread = read(src, buff, 4096)) > 0)
+    {
+        write(dst, buff, nread);
+    }
+
+    close(src);
+    close(dst);
+}
+
+/**
+ * copy the file without transfer to user space
+ */
+void copy_with_mmap()
+{
+    // TODO
+
+    return;
+}
+
+int main(void)
+{
+    clock_t begin, end;
+    const int LOOPS = 100;
+
+    begin = clock();
+    for(int i=0; i<LOOPS; i++)
+    {
+        copy_with_read();
+    }
+    end = clock();
+    fprintf(stdout, "with std io: %e\n", (double)(end-begin) / CLOCKS_PER_SEC);
+
+    begin = clock();
+    for(int i=0; i<LOOPS; i++)
+    {
+        copy_with_mmap();
+    }
+    end = clock();
+    fprintf(stdout, "with mapped io: %e\n", (double)(end-begin) / CLOCKS_PER_SEC);
+
+    fprintf(stdout, "done.\n");
+    exit(0);
+}
+```
+
+## Calcul parallèle et mémoire partagée
+
+L'ensemble de Mandelbrot est le sous-ensembe des points *c* du plan
+complexe pour lesquels la suite *z* converge, où *z(i)* est défini par :
+
+  - *z(0) = 0 + i0*
+  - *z(n+1) = z(n)² + c*
+
+C'est un ensemble fractal, c'est-à-dire que sa structure est invariante
+par changement d'échelle. Sa définition a été formulée par Adrien
+Douadi, qui l'a nommé ainsi en hommage à Benoît Mandelbrot, l'un des
+pionniers de la théorie des fractals.
+
+Un exercice classique en algorithmique consiste à calculer et visualiser
+une approximation discrète de cet ensemble. Étant donnée une matrice
+dont les cellules sont associées à des pixels, il s'agit de calculer si
+le pixel appartient ou non à l'ensemble. Pour cela, on associe à chaque
+pixel les coordonnées d'un des points du plan qu'il représente, et on
+applique un algorithme d'approximation pour déterminer si ce point
+appartient ou non à l'ensemble. Cet algorithme est paramétré par une
+précision *p*. Il consiste, étant donné un point *c*, à calculer la
+suite des valeurs *z(n)* jusqu'à *n=p*, ou jusqu'à ce que *|z(n)| \> 2*
+(car on sait qu'alors la suite *z* diverge). Le pixel est marqué comme
+appartenant à l'ensemble si *z(p)* est inférieur ou égal à 2. Pour les
+points n'appartenant pas à l'ensemble, il est possible de choisir une
+couleur en fonction de l'itération *k* à laquelle *z(k)* devient
+supérieur à 2.
+
+Cet algorithme est implanté dans le fichier source ci-dessous. Votre
+travail consiste à paralléliser ce calcul, c'est-à-dire à répartir le
+travail entre plusieurs processus. Sur une machine disposant de
+plusieurs processeurs, cela permet d'effectuer le calcul plus
+rapidement.
+
+Pour cela, suivre les étapes suivantes :
+
+1.  Étudier le code existant.
+2.  Faire en sorte que la variable `set` soit accessible depuis
+    plusieurs processus.
+3.  Créer plusieurs processus et leur répartir le travail. Pour
+    l'exercice, répartir le travail entre quatre processus enfants, le
+    processus parent ne s'occupant que de l'affichage.
+4.  Faire en sorte que l'affichage de l'image ne se fasse qu'une fois
+    qu'on est certain que le calcul est terminé.
+
+Le programme affiche les ressources consommées. Selon la valeur de *p*
+et le nombre de cœur de calcul de la machine, la version parallèle est
+plus rapide ou plus lente que la version séquentielle. Expliquer
+pourquoi.
+
+``` c
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <string.h>
+
+const int WIDTH      = 5400; /* x resolution in pixels */
+const int HEIGHT     = 3600; /* y resolution in pixels, y = (2/3)x */
+const unsigned short PRECISION  = 1000;
+
+/* distance between two pixels */
+double deltax;
+double deltay;
+
+/* viewport */
+const double xmin    = -2.0;
+const double xmax    = 1.0;
+const double ymin    = -1.0 ;
+const double ymax    = 1.0;
+
+unsigned short * set;
+time_t stamp;
+
+void compute_lines(int start, int end)
+{
+    /* loop counters */
+    int i, j, iteration;
+
+    for (i=start; i<end; i++)
+    {
+        double yc = ymin + i*deltay;
+
+        for (j=0; j<WIDTH; j++)
+        {
+            double xc = xmin + j*deltax;
+
+            double x = 0.0;
+            double y = 0.0;
+            iteration = 0;
+            while((iteration < PRECISION) && ((x*x + y*y) <= 4.0))
+            {
+                iteration++;
+                double newx = x*x - y*y + xc;
+                double newy = 2.0*x*y + yc;
+                x = newx;
+                y = newy;
+            }
+            set[i*WIDTH+j] = iteration;
+        }
+    }
+}
+
+void save_to_file (void)
+{
+    FILE *image;
+    unsigned short buf[3];
+    const unsigned short COLOR_COEFFICIENT = USHRT_MAX / PRECISION;
+    unsigned short color;
+    unsigned short iteration;
+
+    image = fopen("output.ppm", "wb");
+    if (image == NULL)
+    {
+        fprintf(stderr, "Cannot open output file: %s\n", strerror(errno));
+        exit(3);
+    }
+
+    fprintf(image, "P6\n"); // binary
+    fprintf(image, "%d %d\n", WIDTH, HEIGHT); // image dimension
+    fprintf(image, "%u\n",USHRT_MAX); // color depth: 32 bits
+
+    for(int i=0; i<HEIGHT; i++)
+    {
+        for(int j=0; j<WIDTH; j++)
+        {
+            iteration = set[i*WIDTH+j];
+
+            if (iteration == PRECISION) color = USHRT_MAX;
+            else color = iteration * COLOR_COEFFICIENT;
+
+            buf[0] = color;
+            buf[1] = color;
+            buf[2] = color;
+            fwrite(buf, sizeof(short), 3, image) ;
+        }
+    }
+    fclose(image);
+}
+
+int main ()
+{
+
+    struct rusage stats;
+
+    deltax = (xmax - xmin)/(double)WIDTH;
+    deltay = (ymax - ymin)/(double)HEIGHT;
+
+    set = (unsigned short*)malloc(WIDTH*HEIGHT*sizeof(short));
+
+    compute_lines(0, HEIGHT);
+
+    getrusage(RUSAGE_SELF, &stats);
+
+    printf("user time: %ld:%.6ld\n", stats.ru_utime.tv_sec, stats.ru_utime.tv_usec);
+    printf("system time: %ld:%.6ld\n", stats.ru_stime.tv_sec, stats.ru_stime.tv_usec);
+
+    save_to_file();
+
+    return (0);
+}
+```