Paralèlisme : cours
Liste des travaux pratiques / dirigés
On s'intéresse à la parallèlisation du calcul des courbes (ou ensembles) de Julia. Il s'agit d'un exemple classique où chaque calcul lié à un point est indépendant des autres.
Récupérez l'archive jula_cpu_etudiants.tgz qui contient le code de base qui devra être modifié par la suite.
L'implantation de base utilise une fenêtre par défaut entre $x ∊ [-1.4, +1.4]$ et $y ∊ [-1.5, +1.5]$
Dans ces intervalles on place par défaut 1024 pixels ce qui va nous permettre de constituer une image de $1024 × 1024$ pixels. Cette image sera affichée si on utilise l'option en ligne de commande -v, sinon on effectuera un test de performance du calcul de l'image pendant 200 itérations.
Chaque point de l'image est identifié par un nombre complexe $z_1 = x + y {\text i}$ et pour lequel on calcule la suite :
$$ z_{n+1} = z_n^2 + z_0 $$où la constante par défaut $z_0 = 0.3 + 0.5 {\text i}$.
On cherche à savoir si la suite converge grâce à la fonction julia(...). Celle-ci calcule la norme de $z_{n+1}$ pour $n$ variant de 1 à 400. Si elle devient supérieure à $4.0$ on s'arrête en considérant que la suite ne convergera pas.
Effectuez un premier test de performance et noter le temps de calcul en monothread :
/usr/bin/time -f "time=%U" bin/julia_cpu.exe
image_width=1024
image_height=1024
max_images=200
max_terms=400
constant_real=0.3
constant_imag=0.5
timer.computation.ms=30156
time=30.14
cat /proc/cpuinfo | grep "model name" | uniq
model name : AMD Ryzen 5 5600G with Radeon Graphics
Dans l'exemple précédent le test s'est exécuté en $30,14$ secondes sur un AMD Ryzen 5 5600G.
Parallélisez le code de l'archive. Comparer les temps d'exécution des différentes méthodes qui suivent.
On modifiera le programme de manière à pouvoir choisir grâce à l'option -m la méthode adéquate pour effectuer le calcul parmi :
On effectuera les tests avec les paramètres par défaut.
On pourra éventuellement modifier les paramètres -a si le nombre de générations donne des temps de calcul trop importants sur PC portable.
Remplir le tableau suivant avec les temps de calcul des différentes méthodes en modifiant le nombre de threads. On écrira un script bash afin d'automatiser les calculs.
Voici les temps de calcul et des graphiques obtenus pour différentes architectures :
Méthode / Threads | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 |
méthode 2 | 15.06 | 11.22 | 8.22 | 7.02 | 5.85 | 5.33 | 4.76 | 4.38 | 4.21 | 4.24 | 4.25 | 4.12 | 4.18 | 4.04 | 3.96 | 3.89 |
méthode 3 | 20.47 | 17.74 | 16.05 | 13.54 | 12.43 | 11.19 | 19.01 | 16.15 | 14.55 | 13.69 | 13.76 | 13.64 | 14.08 | 14.71 | 14.88 | 15.27 |
méthode 4 | 15.07 | 11.21 | 8.26 | 7.03 | 5.91 | 5.37 | 4.77 | 4.43 | 4.21 | 4.15 | 4.32 | 4.14 | 4.22 | 4.11 | 3.96 | 3.89 |
Méthode / Threads | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 |
méthode 2 | 21.66 | 16.16 | 11.83 | 9.95 | 8.08 | 7.12 | 6.22 | 5.68 | 5.54 | 5.05 | 4.94 | 4.70 | 4.87 | 4.50 | 4.48 | 4.43 |
méthode 3 | 29.95 | 25.88 | 22.84 | 19.64 | 17.90 | 16.06 | 13.84 | 12.71 | 27.69 | 28.21 | 29.09 | 31.72 | 34.80 | 38.75 | 39.30 | 41.13 |
méthode 4 | 22.04 | 16.48 | 12.19 | 10.29 | 8.29 | 7.56 | 6.53 | 6.12 | 5.68 | 5.24 | 5.07 | 4.81 | 4.94 | 4.83 | 4.75 | 4.73 |
On obtient un temps minimal de 1,65s pour $k=70$ ou $72$.
Que remarque t-on ?
Analyser les résultats de la méthode 2 par rapport à la loi de Amdahl en considérant que le temps de calcul passé en parallèle est de 98%, soit $Par = 0,98$.
K | Temps (s) | Acc_K (Amdahl) |
Acc_R | KP |
1 | 30.14 | - | - | - |
2 | 15.06 | 1.96 | 2.00 | -0.0007 |
4 | 11.22 | 3.77 | 2.69 | 0.1630 |
6 | 8.22 | 5.45 | 3.67 | 0.1273 |
8 | 7.02 | 7.02 | 4.29 | 0.1233 |
10 | 5.85 | 8.47 | 5.15 | 0.1045 |
12 | 5.33 | 9.84 | 5.65 | 0.1020 |
14 | 4.76 | 11.11 | 6.33 | 0.0932 |
16 | 4.38 | 12.31 | 6.88 | 0.0883 |
18 | 4.21 | 13.43 | 7.16 | 0.0891 |
20 | 4.24 | 14.49 | 7.11 | 0.0954 |
22 | 4.25 | 15.49 | 7.09 | 0.1001 |
24 | 4.12 | 16.44 | 7.32 | 0.0992 |
26 | 4.18 | 17.33 | 7.21 | 0.1042 |
28 | 4.04 | 18.18 | 7.46 | 0.1020 |
30 | 3.96 | 18.99 | 7.61 | 0.1014 |
32 | 3.8 | 19.75 | 7.93 | 0.0979 |
On ne considère que les valeurs positives et dans ce cas c'est pour $k = 16$ que l'on obtient le meilleur résultat.
Pour $k = 2$, l'accélération théorique (${\text acc}_K$) est sensiblement égale à l'accélération réelle (${\text acc}_R$)
Par contre, à partir de $k = 4$, on note une différence importante entre ces valeurs.
Modifiez le programme précédent pour en donner une version MPI pour laquelle chaque CPU / thread se voit attribuer un nombre de lignes à traiter et renvoie le résultat au processus maître.
Il se peut que le compilateur mpic++ affiche des erreurs liées au type Status défini pour MPI sous forme d'une classe mais également pour OpenGL sous forme d'un entier. Pour supprimer le problème introduire les lignes suivantes avant d'inclure la librairie MPI :
#ifdef Status
#undef Status
#endif
#include <mpi.h>
Donner les temps d'exécution pour $k$ (nombre de CPU) variant de 2 à 8 par exemple soit sur la même machine soit sur plusieurs machines différentes.