Paralèlisme : cours

Liste des travaux pratiques / dirigés

6. Courbes de Julia

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.

6.1. L'implantation mono thread

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.

6.2. Partie OpenMP

6.2.1. Améliorations

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.

6.2.2. Résultats

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 
Julia - Temps de calcul sur AMD Ryzen 5 5600G
 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 
Julia - Temps de calcul sur AMD Ryzen 7 1700X


6.2.2.a  Ryzen 9 7950X3D (Mathis SAUVAGE)

On obtient un temps minimal de 1,65s pour $k=70$ ou $72$.

6.2.3. Analyse

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 
Julia - Amdhal / Karp-Flatt pour la méthode 2 sur Ryzen 5600G

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.

6.3. Partie MPI

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.