Commit 36a67e8a authored by Martin Khannouz's avatar Martin Khannouz Committed by Berenger Bramas

Add new stuff in the orgmode.

parent f1b1771a
......@@ -16,7 +16,325 @@
# spack install scalfmm@src+mpi+starpu \^starpu@svn-trunk+mpi+fxt \^openmpi
# #+END_SRC
* Implémentation mpi implicite très naïve
* Abstract
* Introduction
* Background
** Fast Multipole Method
** Task based FMM
*** Sequential Task Flow
*** Runtime
*** Group tree
*** Distributed FMM
* Implicit MPI FMM
** Sequential Task Flow with implicit communication
** Data Mapping
*** Level Split Mapping
*** Leaf Load Balancing
*** TreeMatch Balancing
** Result
#+BEGIN_SRC
#!/bin/sh
export SCALFMM_SIMGRIDOUT='scalfmm.out'
export GROUP_SIZE=500
export TREE_HEIGHT=5
export NB_NODE=16
export NB_PARTICLE_PER_NODE=15000
echo "GROUP_SIZE=$GROUP_SIZE"
echo "TREE_HEIGHT=$TREE_HEIGHT"
echo "NB_NODE=$NB_NODE"
echo "NB_PARTICLE_PER_NODE=$NB_PARTICLE_PER_NODE"
#Compile only what we need
make testBlockedImplicitChebyshev testBlockedMpiChebyshev testBlockedImplicitAlgorithm testBlockedMpiAlgorithm compareDAGmapping -j $((`nproc`*2))
if [ $? -ne 0 ]; then
exit
fi
#Execute explicit mpi version
sleep 10
mpiexec -n $NB_NODE ./Tests/Release/testBlockedMpiAlgorithm -nb $NB_PARTICLE_PER_NODE -bs $GROUP_SIZE -h $TREE_HEIGHT 2>/dev/null
if [ $? -ne 0 ]; then
echo
echo " /!\\Error on explicit"
echo
exit
fi
#Aggregate task information from explicit execution
a=`ls $SCALFMM_SIMGRIDOUT\_*`
rm -f $SCALFMM_SIMGRIDOUT
for i in $a; do
cat $i >> $SCALFMM_SIMGRIDOUT
done
#Get task information
cp -f $SCALFMM_SIMGRIDOUT scalfmm_explicit.out
#Execute implicit version
sleep 10
mpiexec -n $NB_NODE ./Tests/Release/testBlockedImplicitAlgorithm -f canard.fma -bs $GROUP_SIZE -h $TREE_HEIGHT 2>/dev/null
if [ $? -ne 0 ]; then
echo
echo " /!\\Error on implicit"
echo
exit
fi
#Get task information
cp -f scalfmm.out_0 scalfmm_implicit.out
#Compare DAGs
./Tests/Release/compareDAGmapping -e scalfmm_explicit.out -i scalfmm_implicit.out -h $TREE_HEIGHT > output
sleep 10
mpiexec -n $NB_NODE ./Tests/Release/testBlockedMpiChebyshev -nb $NB_PARTICLE_PER_NODE -bs $GROUP_SIZE -h $TREE_HEIGHT 2>/dev/null
if [ $? -ne 0 ]; then
echo
echo " /!\\Error on explicit Chebyshev"
echo
exit
fi
sleep 10
mpiexec -n $NB_NODE ./Tests/Release/testBlockedImplicitChebyshev -f canard.fma -bs $GROUP_SIZE -h $TREE_HEIGHT 2>/dev/null
if [ $? -ne 0 ]; then
echo
echo " /!\\Error on implicit Chebyshev"
echo
exit
fi
#+END_SRC
<<sec:result>>
The script of the job:
#+BEGIN_SRC
#!/usr/bin/env bash
## name of job
#SBATCH -J Implicit_MPI_time
#SBATCH -p special
## Resources: (nodes, procs, tasks, walltime, ... etc)
#SBATCH -N 40
# # standard output message
#SBATCH -o batch%j.out
# # output error message
#SBATCH -e batch%j.err
module purge
module load slurm
module add compiler/gcc/5.3.0 tools/module_cat/1.0.0 intel/mkl/64/11.2/2016.0.0
. /home/mkhannou/spack/share/spack/setup-env.sh
spack load fftw
spack load hwloc
spack load openmpi
spack load starpu@svn-trunk
## modules to load for the job
export GROUP_SIZE=500
export TREE_HEIGHT=5
export NB_NODE=$SLURM_JOB_NUM_NODES
export NB_PARTICLE_PER_NODE=100000
echo "=====my job informations ===="
echo "Node List: " $SLURM_NODELIST
echo "my jobID: " $SLURM_JOB_ID
echo "Nb node: " $NB_NODE
echo "Particle per node: " $NB_PARTICLE_PER_NODE
echo "In the directory: `pwd`"
rm -f canard.fma > /dev/null 2> /dev/null
mpiexec -n $NB_NODE ./Build/Tests/Release/testBlockedMpiAlgorithm -nb $NB_PARTICLE_PER_NODE -bs $GROUP_SIZE -h $TREE_HEIGHT > loutre
cat loutre | grep Executing
cat loutre | grep Average
sleep 10
mpiexec -n $NB_NODE ./Build/Tests/Release/testBlockedImplicitAlgorithm -f canard.fma -bs $GROUP_SIZE -h $TREE_HEIGHT > loutre
cat loutre | grep Executing
cat loutre | grep Average
rm -f canard.fma > /dev/null 2> /dev/null
sleep 10
mpiexec -n $NB_NODE ./Build/Tests/Release/testBlockedMpiChebyshev -nb $NB_PARTICLE_PER_NODE -bs $GROUP_SIZE -h $TREE_HEIGHT > loutre
cat loutre | grep Executing
cat loutre | grep Average
sleep 10
mpiexec -n $NB_NODE ./Build/Tests/Release/testBlockedImplicitChebyshev -f canard.fma -bs $GROUP_SIZE -h $TREE_HEIGHT > loutre
cat loutre | grep Executing
cat loutre | grep Average
#+END_SRC
The result given by the script after few minutes executing:
#+BEGIN_EXAMPLE
=====my job informations ====
Node List: miriel[038-077]
my jobID: 108825
Nb node: 40
Particle per node: 100000
In the directory: /home/mkhannou/scalfmm
Executing time node 0 (explicit) : 0.886289s
Executing time node 1 (explicit) : 12.689s
Executing time node 2 (explicit) : 12.6714s
Executing time node 3 (explicit) : 12.6539s
Executing time node 4 (explicit) : 12.6373s
Executing time node 5 (explicit) : 12.599s
Executing time node 6 (explicit) : 12.5816s
Executing time node 7 (explicit) : 12.5721s
Executing time node 8 (explicit) : 12.5626s
Executing time node 9 (explicit) : 12.5458s
Executing time node 10 (explicit) : 12.5198s
Executing time node 11 (explicit) : 12.519s
Executing time node 12 (explicit) : 12.5141s
Executing time node 13 (explicit) : 12.5045s
Executing time node 14 (explicit) : 12.4958s
Executing time node 15 (explicit) : 12.4322s
Executing time node 16 (explicit) : 12.4149s
Executing time node 17 (explicit) : 12.416s
Executing time node 18 (explicit) : 12.3991s
Executing time node 19 (explicit) : 12.3865s
Executing time node 20 (explicit) : 12.3445s
Executing time node 21 (explicit) : 12.3269s
Executing time node 22 (explicit) : 12.3089s
Executing time node 23 (explicit) : 12.3107s
Executing time node 24 (explicit) : 12.2928s
Executing time node 25 (explicit) : 12.2555s
Executing time node 26 (explicit) : 12.2461s
Executing time node 27 (explicit) : 12.2409s
Executing time node 28 (explicit) : 12.2237s
Executing time node 29 (explicit) : 12.2064s
Executing time node 30 (explicit) : 12.1672s
Executing time node 31 (explicit) : 12.1504s
Executing time node 32 (explicit) : 12.1326s
Executing time node 33 (explicit) : 12.1156s
Executing time node 34 (explicit) : 12.1058s
Executing time node 35 (explicit) : 12.0725s
Executing time node 36 (explicit) : 12.0558s
Executing time node 37 (explicit) : 12.0507s
Executing time node 38 (explicit) : 12.0376s
Executing time node 39 (explicit) : 12.0198s
Average time per node (explicit) : 12.0666s
Executing time node 0 (implicit) : 1.3918s
Executing time node 1 (implicit) : 1.1933s
Executing time node 2 (implicit) : 0.808328s
Executing time node 3 (implicit) : 0.773344s
Executing time node 4 (implicit) : 1.25819s
Executing time node 5 (implicit) : 1.18945s
Executing time node 6 (implicit) : 1.27529s
Executing time node 7 (implicit) : 1.22866s
Executing time node 8 (implicit) : 1.26839s
Executing time node 9 (implicit) : 1.25121s
Executing time node 10 (implicit) : 0.337148s
Executing time node 11 (implicit) : 1.4247s
Executing time node 12 (implicit) : 1.41725s
Executing time node 13 (implicit) : 1.48044s
Executing time node 14 (implicit) : 1.5094s
Executing time node 15 (implicit) : 1.50355s
Executing time node 16 (implicit) : 1.55565s
Executing time node 17 (implicit) : 1.40483s
Executing time node 18 (implicit) : 1.57896s
Executing time node 19 (implicit) : 1.63332s
Executing time node 20 (implicit) : 1.13418s
Executing time node 21 (implicit) : 1.66588s
Executing time node 22 (implicit) : 1.75309s
Executing time node 23 (implicit) : 1.75407s
Executing time node 24 (implicit) : 1.77763s
Executing time node 25 (implicit) : 1.80734s
Executing time node 26 (implicit) : 1.84635s
Executing time node 27 (implicit) : 1.91082s
Executing time node 28 (implicit) : 1.92222s
Executing time node 29 (implicit) : 1.96819s
Executing time node 30 (implicit) : 1.995s
Executing time node 31 (implicit) : 2.03309s
Executing time node 32 (implicit) : 2.04957s
Executing time node 33 (implicit) : 2.08208s
Executing time node 34 (implicit) : 2.10419s
Executing time node 35 (implicit) : 2.17535s
Executing time node 36 (implicit) : 2.19764s
Executing time node 37 (implicit) : 1.48737s
Executing time node 38 (implicit) : 2.20165s
Executing time node 39 (implicit) : 2.23154s
Average time per node (implicit) : 1.58951s
Executing time node 0 (explicit Cheby) : 14.9724s
Executing time node 1 (explicit Cheby) : 28.1361s
Executing time node 2 (explicit Cheby) : 28.8268s
Executing time node 3 (explicit Cheby) : 29.5679s
Executing time node 4 (explicit Cheby) : 30.3545s
Executing time node 5 (explicit Cheby) : 26.4163s
Executing time node 6 (explicit Cheby) : 28.3624s
Executing time node 7 (explicit Cheby) : 28.8427s
Executing time node 8 (explicit Cheby) : 29.4445s
Executing time node 9 (explicit Cheby) : 29.8502s
Executing time node 10 (explicit Cheby) : 27.1067s
Executing time node 11 (explicit Cheby) : 27.2506s
Executing time node 12 (explicit Cheby) : 28.3568s
Executing time node 13 (explicit Cheby) : 29.5386s
Executing time node 14 (explicit Cheby) : 28.5243s
Executing time node 15 (explicit Cheby) : 27.455s
Executing time node 16 (explicit Cheby) : 27.439s
Executing time node 17 (explicit Cheby) : 28.1895s
Executing time node 18 (explicit Cheby) : 28.8084s
Executing time node 19 (explicit Cheby) : 27.5662s
Executing time node 20 (explicit Cheby) : 26.8049s
Executing time node 21 (explicit Cheby) : 28.8124s
Executing time node 22 (explicit Cheby) : 28.2384s
Executing time node 23 (explicit Cheby) : 27.5266s
Executing time node 24 (explicit Cheby) : 27.5838s
Executing time node 25 (explicit Cheby) : 27.3604s
Executing time node 26 (explicit Cheby) : 28.8181s
Executing time node 27 (explicit Cheby) : 28.0987s
Executing time node 28 (explicit Cheby) : 27.5754s
Executing time node 29 (explicit Cheby) : 27.8695s
Executing time node 30 (explicit Cheby) : 28.1235s
Executing time node 31 (explicit Cheby) : 27.9892s
Executing time node 32 (explicit Cheby) : 27.8463s
Executing time node 33 (explicit Cheby) : 27.744s
Executing time node 34 (explicit Cheby) : 26.5374s
Executing time node 35 (explicit Cheby) : 28.3493s
Executing time node 36 (explicit Cheby) : 28.1228s
Executing time node 37 (explicit Cheby) : 28.1991s
Executing time node 38 (explicit Cheby) : 28.021s
Executing time node 39 (explicit Cheby) : 27.5317s
Average time per node (explicit Cheby) : 27.804s
Executing time node 0 (implicit Cheby) : 7.97802s
Executing time node 1 (implicit Cheby) : 15.1593s
Executing time node 2 (implicit Cheby) : 22.7339s
Executing time node 3 (implicit Cheby) : 30.1029s
Executing time node 4 (implicit Cheby) : 38.0297s
Executing time node 5 (implicit Cheby) : 44.84s
Executing time node 6 (implicit Cheby) : 51.8852s
Executing time node 7 (implicit Cheby) : 58.7032s
Executing time node 8 (implicit Cheby) : 65.5961s
Executing time node 9 (implicit Cheby) : 72.6259s
Executing time node 10 (implicit Cheby) : 73.0871s
Executing time node 11 (implicit Cheby) : 76.8398s
Executing time node 12 (implicit Cheby) : 83.7107s
Executing time node 13 (implicit Cheby) : 91.0522s
Executing time node 14 (implicit Cheby) : 97.4556s
Executing time node 15 (implicit Cheby) : 103.77s
Executing time node 16 (implicit Cheby) : 110.615s
Executing time node 17 (implicit Cheby) : 116.897s
Executing time node 18 (implicit Cheby) : 123.433s
Executing time node 19 (implicit Cheby) : 129.222s
Executing time node 20 (implicit Cheby) : 121.964s
Executing time node 21 (implicit Cheby) : 129.865s
Executing time node 22 (implicit Cheby) : 131.474s
Executing time node 23 (implicit Cheby) : 137.668s
Executing time node 24 (implicit Cheby) : 144.047s
Executing time node 25 (implicit Cheby) : 150.888s
Executing time node 26 (implicit Cheby) : 157.931s
Executing time node 27 (implicit Cheby) : 164.466s
Executing time node 28 (implicit Cheby) : 170.164s
Executing time node 29 (implicit Cheby) : 175.757s
Executing time node 30 (implicit Cheby) : 176.22s
Executing time node 31 (implicit Cheby) : 180.678s
Executing time node 32 (implicit Cheby) : 187.144s
Executing time node 33 (implicit Cheby) : 193.305s
Executing time node 34 (implicit Cheby) : 198.414s
Executing time node 35 (implicit Cheby) : 205.278s
Executing time node 36 (implicit Cheby) : 211.486s
Executing time node 37 (implicit Cheby) : 217.305s
Executing time node 38 (implicit Cheby) : 222.823s
Executing time node 39 (implicit Cheby) : 227.275s
Average time per node (implicit Cheby) : 122.947s
#+END_EXAMPLE
* State of the art
Nothing for now ...
* Journal
** Implémentation mpi implicite très naïve
Cette première version avait pour principal but de découvrir et à prendre en main les fonctions de StarPU MPI.
Les premières étant starpu_mpi_init et starpu_mpi_shutdown. Mais rapidement ont suivies les fonctions pour /tagger/ les /handles/ de StarPU et les ajouter à des nœuds MPI.
À cela c'est ajouté la transformation de tous les appels à starpu_insert_task ou starpu_task_submit par starpu_mpi_insert_task.
......@@ -25,19 +343,19 @@ Par soucis de simplicité chaque nœud MPI possède l'intégralité de l'arbre,
Pour vérifier que tout fonctionnait correctement, je me suis amusé à /mapper/ toutes les données sur un premier nœud MPI et toutes les tâches sur un second.
J'ai ensuite pu valider que l'arbre du premier nœud avait les bons résultats et que le second nœud n'avait que des erreurs.
* Implémentation moins naïve
** Implémentation moins naïve
Dans l'idée de créer une version 0 un brin potable qui puisse faire du calcul avec plus de deux nœuds MPI, j'ai créé une fonction de /mapping/ des données.
Elle consistait à partager chaque niveau entre tous les processus de la manière la plus équitable possible.
#+CAPTION: Division de chaque niveau entre chaque processus. Groupe de l'arbre de taille 4.
[[./naive_split.png]]
* Reproduction du mapping mpi explicite
** Reproduction du mapping mpi explicite
Pour pouvoir effectuer des comparaisons il était nécessaire de reproduire le même /mapping/ de tâches la version MPI explicite.
Dans le cas de la version implicite telle qu'elle est actuellement implémentée, le /mapping/ des données infère le /mapping/ de tâches.
La façon la plus simple de procéder est de faire en sorte que les particules se retrouvent sur les mêmes nœuds MPI.
** Premier problème des groupes
*** Premier problème des groupes
La disposition des particules sur les nœuds MPI étant décidé par un tri distribué, il était plus judicieux de sauvegarder le /mapping/ des particules dans un fichier puis de le charger (dans la version implicite) et d'utiliser ce /mapping/ pour influer le /mapping/ au niveau de la version implicite.
Le soucis du tri distribué est qu'il essaye d'équilibrer les particules sur les nœuds sans tenir compte des groupes de l'arbre groupé (/group tree/).
......@@ -50,7 +368,7 @@ Or le /mapping/ des données est fait avec la granularité des groupes de l'arbr
Une première solution serait de modifier un peu l'algorithme de l'arbre pour le forcer à faire des groupes un peu plus petit de telle sorte qu'ils correspondent aux groupes de la version MPI explicite.
Soucis, quand il faudra remonter dans l'arbre, que faire des cellules qui sont présentes sur plusieurs nœuds MPI, que faire de la racine ?
** Solution retenue
*** Solution retenue
Plutôt que d'essayer de reproduire un /mapping/ de données identique à celui de la version explicite quel que soit les particules, nous avons choisi de limiter le nombre de cas reproductibles et de ségmenter ce /mapping/ par niveau.
Ainsi avec un arbre parfait où chaque indice de morton possède le même nombre de particules, il est possible de reproduire le même /mapping/ de données sur un certain de nombre de niveaux.
Ce nombre varie en fonction de la taille des groupes de l'arbre groupé.
......@@ -59,25 +377,81 @@ Ce nombre varie en fonction de la taille des groupes de l'arbre groupé.
#+NAME: fig:SED-HR4049
[[./morton_box_center.png]]
** Validation des résultats
*** Solution apportée par la suite
Après discussion avec Bérenger il s'avèra qu'il n'était pas si difficile de reproduire le tri parrallèle. Ce à quoi je me suis attelé durant les jours qui on suivi.
Ainsi un constructeur a été ajouté à l'arbre bloqué pour décrire la taille de chaque bloque à chaque étage.
Cela requière un un pré-calcul qui est effectué par une fonction intermédiaire.
Cela revient à:
- Trier les particules selon leur indice de Morton.
- Compter le nombre de feuilles différentes.
- Répartir les feuilles en utilisant l'objet FLeafBalance.
- Créer les groupe des étages supérieurs en se basant sur l'interval de travail fourni par l'algorithme 13 de la thèse de Bérenger.
*** Validation des résultats
Pour valider ces résultats, j'ai réutilisé le système de nom de tâches fait pour simgrid. Ainsi j'ai pu indiquer, dans un fichier des informations à propos de chaque tâche.
Les indices de Morton ainsi que les nœuds MPI sur lesquels elles s'exécutent.
*** Observation
**** Observation
Si l'on fait exception des niveaux où l'on sait que des erreurs de tâches se trouveront, on a :
- Plus de tâches dans la version explicite car elle a des tâches (P2P, M2L) symetriques.
- Toutes les tâches issuent de l'algorithme implicite se retrouvent dans l'ensemble des tâches explicite.
- Toutes les tâches sont au moins mapper sur le même nœud MPI. Les tâches symetriques étant parfois mappé sur deux nœuds différents.
* Et après ?
*** Comparaison des performances
Pour comparer les performances entre l'approche explicite et implicite, il a été décidé d'ajouté un nouveau test judicieusement nommé testBlockedImplicitChebyshev. Ainsi les comparaisons se font sur la base d'un véritable noyaux de calcul et non un noyaux de test peu réaliste. Les résultats sont déroulés dans la section [[sec:result]]. Notez que les temps indiqués ne correspondent qu'au temps de création des noyaux ainsi que de l'objet correspondant à l'algorithme de la FMM. N'est pas compris tout le temps passé à construire l'arbre, à stocker les particules ou a les lire dans un fichier et à vérifier le résultats.
Le temps passé est compté de la manière suivante :
#+BEGIN_SRC C
//Start the timer
FTic timerExecute;
//Creating some useful object
const MatrixKernelClass MatrixKernel;
GroupKernelClass groupkernel(NbLevels, loader.getBoxWidth(), loader.getCenterOfBox(), &MatrixKernel);
GroupAlgorithm groupalgo(&groupedTree,&groupkernel, distributedMortonIndex);
//Executing the algorithm
groupalgo.execute();
//Stop the timer
double elapsedTime = timerExecute.tacAndElapsed();
//Sum the result
timeAverage(mpi_rank, nproc, elapsedTime);
#+END_SRC
Les résultats dénotent deux choses :
- L'algorithme implicite répartis mal les calculs.
- Une situation curieuse : Avec le noyaux de test, l'implicite est 10x plus rapide, avec le noyau de Chebyshev, il est 5x plus lent.
*** Erreurs rencontrées
Un /bug/ a fait son apparition dans la version MPI explicit où des segfaults apparaissent si l'arbre n'a pas au moins une particule dans chaque indice de Morton.
Cette erreur n'impacte pas encore la bonne progression du stage, car dans la pratique, il y a suffisament de particules pour remplir l'arbre.
** Autre /mapping/
*** Treematch
Suite à la présentation par Emmanuel Jeannot de l'outil TreeMatch qui permettrait de proposer des /mapping/ intéressant, il serait bon de profiter dudit outil.
Une structure de fichier pour communiquer avec TreeMatch serait la suivante :
#+BEGIN_EXAMPLE
123 7
124:6000
45:3000
23:400
#+END_EXAMPLE
Cette structure (simpliste) se lirait de la manière suivante :
- Le groupe 123 est situé sur le nœud 7.
- Le groupe 123 échange 6000 octets avec le groupe 124.
- Le groupe 123 échange 3000 octets avec le groupe 45.
- Le groupe 123 échange 400 octets avec le groupe 23.
Les groupes correspondent aux /handles/ de Starpu qui correspondent aux groupes de l'arbre bloqué.
** Et après ?
- Comparaison des performances
- Répartition des GFlop
- Répartition du temps de calcul
- Mémoire utilisée par nœud
- Symétriser l'algorithme implicite au niveau des P2P
- Étude d'autres /mapping/
- Proposer un formalisme simple pour transmettre le graphe de flux de données (Treematch)
- Proposer un formalisme simple pour transmettre la topologie (Treematch)
- Limiter l'empreinte mémoire
- Ne pas allouer les cellules numériques si ce n'est pas necessaire (/up/ et /down/)
- Ne pas allouer les cellules symboliques si ce n'est pas necessaire
- Distribuer l'arbre
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment