diff --git a/Doc/noDist/Presentation/group_issue1.png b/Doc/noDist/Presentation/group_issue1.png new file mode 100644 index 0000000000000000000000000000000000000000..5772d5f2cf42818790087667bed5d10f148e13f1 Binary files /dev/null and b/Doc/noDist/Presentation/group_issue1.png differ diff --git a/Doc/noDist/Presentation/morton_box_center.png b/Doc/noDist/Presentation/morton_box_center.png new file mode 100644 index 0000000000000000000000000000000000000000..5f5be4a59904d18717f8193c673b94fad82d2368 Binary files /dev/null and b/Doc/noDist/Presentation/morton_box_center.png differ diff --git a/Doc/noDist/Presentation/naive_split.png b/Doc/noDist/Presentation/naive_split.png new file mode 100644 index 0000000000000000000000000000000000000000..497c6172676fdaad74c52e462456a2d9887217f6 Binary files /dev/null and b/Doc/noDist/Presentation/naive_split.png differ diff --git a/Doc/noDist/Presentation/presentation.html b/Doc/noDist/Presentation/presentation.html new file mode 100644 index 0000000000000000000000000000000000000000..81c0a1633e950014ee6ef72f2cbafd30a6b4fb3f --- /dev/null +++ b/Doc/noDist/Presentation/presentation.html @@ -0,0 +1,316 @@ + + + + +Usage implicit de MPI dans ScalFmm + + + + + + + + +
+

Usage implicit de MPI dans ScalFmm

+
+

Table des matières

+ +
+ +
+

1 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. +

+ +

+Par soucis de simplicité chaque nœud MPI possède l'intégralité de l'arbre, même si ce n'est pas une solution viable sur le long terme. +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. +

+
+
+ +
+

2 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. +

+ + +
+

naive_split.png +

+

Figure 1 : Division de chaque niveau entre chaque processus. Groupe de l'arbre de taille 4.

+
+
+
+ +
+

3 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. +

+
+ +
+

3.1 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). +

+ + +
+

group_issue1.png +

+

Figure 2 : Problème issuent de la constitution des groupes.

+
+ +

+Or le mapping des données est fait avec la granularité des groupes de l'arbre groupé. +

+ +

+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 ? +

+
+
+ +
+

3.2 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é. +

+ + +
+

morton_box_center.png +

+

Figure 3 : Méthode pour générer une particule à un indice de Morton donné.

+
+
+
+ +
+

3.3 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. +

+
+ +
+

3.3.1 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. +
  • +
+
+
+
+
+ +
+

4 Et après ?

+
+
    +
  • Comparaison des performances +
      +
    • Répartition des GFlop +
    • +
    • Répartition du temps de calcul +
    • +
    • Mémoire utilisée par nœud +
    • +
    +
  • +
  • Étude d'autres mapping +
  • +
  • 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 +
    • +
    +
  • +
+
+
+
+
+

Auteur: Martin Khannouz

+

Created: 2016-03-21 lun. 15:27

+

Emacs 24.5.1 (Org mode 8.2.10)

+

Validate

+
+ + diff --git a/Doc/noDist/Presentation/presentation.org b/Doc/noDist/Presentation/presentation.org new file mode 100644 index 0000000000000000000000000000000000000000..4f2905606b293f148d7b9ab0c60937eb78fc9aca --- /dev/null +++ b/Doc/noDist/Presentation/presentation.org @@ -0,0 +1,83 @@ +#+TITLE: Usage implicit de MPI dans ScalFmm +#+AUTHOR: Martin Khannouz +#+LANGUAGE: fr +#+STARTUP: inlineimages +#+OPTIONS: H:3 num:t toc:t \n:nil @:t ::t |:t ^:nil -:t f:t *:t <:t +#+OPTIONS: TeX:t LaTeX:t skip:nil d:nil todo:nil pri:nil tags:not-in-toc +#+EXPORT_SELECT_TAGS: export +#+EXPORT_EXCLUDE_TAGS: noexport +#+TAGS: noexport(n) + + +# #+BEGIN_SRC sh +# export SCALFMM_DIR=/home/mkhannou/scalfmm +# cd $SCALFMM_DIR +# git checkout mpi_implicit +# spack install scalfmm@src+mpi+starpu \^starpu@svn-trunk+mpi+fxt \^openmpi +# #+END_SRC + +* 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. + +Par soucis de simplicité chaque nœud MPI possède l'intégralité de l'arbre, même si ce n'est pas une solution viable sur le long terme. +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 +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 +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 +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/). + +#+CAPTION: Problème issuent de la constitution des groupes. +#+NAME: fig:SED-HR4049 +[[./group_issue1.png]] + +Or le /mapping/ des données est fait avec la granularité des groupes de l'arbre groupé. + +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 +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é. + +#+CAPTION: Méthode pour générer une particule à un indice de Morton donné. +#+NAME: fig:SED-HR4049 +[[./morton_box_center.png]] + +** 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 +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 + - Répartition des GFlop + - Répartition du temps de calcul + - Mémoire utilisée par nœud +- Étude d'autres /mapping/ +- 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 + + diff --git a/Src/GroupTree/Core/FGroupTaskStarpuImplicitAlgorithm.hpp b/Src/GroupTree/Core/FGroupTaskStarpuImplicitAlgorithm.hpp index 6cbfd9b803a8bcc937bc294fa5aa1a9cc5c925fe..9f7ad0ce0e74fb12cbafec769b385800ee71bc61 100644 --- a/Src/GroupTree/Core/FGroupTaskStarpuImplicitAlgorithm.hpp +++ b/Src/GroupTree/Core/FGroupTaskStarpuImplicitAlgorithm.hpp @@ -192,8 +192,6 @@ public: taskNames = new FStarPUTaskNameParams(mpi_rank, nproc); #endif #endif - cout << mpi_rank << "/" << nproc << endl; - starpu_malloc_set_align(32); starpu_pthread_mutex_t initMutex; diff --git a/Tests/GroupTree/compareDAGmapping.cpp b/Tests/GroupTree/compareDAGmapping.cpp index 1d00b97170eb4fa54197801b8bc08d410e1cd2e5..4347b631d2bcd013dfe7e4ddc2e969b02f946bd0 100644 --- a/Tests/GroupTree/compareDAGmapping.cpp +++ b/Tests/GroupTree/compareDAGmapping.cpp @@ -8,6 +8,7 @@ #include #include #include +#include using namespace std; #include "../../Src/Utils/FGlobal.hpp" @@ -49,6 +50,7 @@ struct Task cout << taskNames[type]; for(size_t i = 0; i < id.size(); ++i) cout << ", " << id[i]; + cout << "(mpi " << mpiNode << ")"; cout << endl; } }; @@ -66,6 +68,7 @@ struct DagData { unordered_set allTask; unordered_map performence; + int treeHeight; }; bool parseLine(DagData & dagData, deque & lineElements) @@ -84,6 +87,7 @@ bool parseLine(DagData & dagData, deque & lineElements) task.id[2] = stoll(lineElements[11]); task.id[3] = stoll(lineElements[12]); task.mpiNode = stoi(lineElements[13]); + task.level = dagData.treeHeight - 1; dagData.allTask.insert(task); } else if(lineElements.size() >= 10 && lineElements[0] == "P2P") @@ -99,6 +103,7 @@ bool parseLine(DagData & dagData, deque & lineElements) if(task.id[0] == 0 && task.id[1] == 0 && task.id[2] == 0 && task.id[3] == 0) cout << "Suricate" << endl; task.mpiNode = stoi(lineElements[9]); + task.level = dagData.treeHeight - 1; dagData.allTask.insert(task); } else if(lineElements.size() >= 10 && lineElements[0] == "M2L" ) @@ -113,6 +118,7 @@ bool parseLine(DagData & dagData, deque & lineElements) task.id[3] = stoll(lineElements[7]); task.id[4] = stoll(lineElements[8]); task.mpiNode = stoi(lineElements[9]); + task.level = task.id[0]; dagData.allTask.insert(task); } else if(lineElements.size() >= 13 && lineElements[0] == "M2L_out") @@ -127,6 +133,7 @@ bool parseLine(DagData & dagData, deque & lineElements) task.id[3] = stoll(lineElements[10]); task.id[4] = stoll(lineElements[11]); task.mpiNode = stoi(lineElements[12]); + task.level = task.id[0]; dagData.allTask.insert(task); } else if(lineElements.size() >= 13 && lineElements[0] == "M2M") @@ -141,6 +148,7 @@ bool parseLine(DagData & dagData, deque & lineElements) task.id[3] = stoll(lineElements[10]); task.id[4] = stoll(lineElements[11]); task.mpiNode = stoi(lineElements[12]); + task.level = task.id[0]; dagData.allTask.insert(task); } else if(lineElements.size() >= 13 && lineElements[0] == "L2L") @@ -155,6 +163,7 @@ bool parseLine(DagData & dagData, deque & lineElements) task.id[3] = stoll(lineElements[10]); task.id[4] = stoll(lineElements[11]); task.mpiNode = stoi(lineElements[12]); + task.level = task.id[0]; dagData.allTask.insert(task); } else if(lineElements.size() >= 8 && lineElements[0] == "L2P") @@ -166,6 +175,7 @@ bool parseLine(DagData & dagData, deque & lineElements) task.id[0] = stoll(lineElements[5]); task.id[1] = stoll(lineElements[6]); task.mpiNode = stoi(lineElements[7]); + task.level = dagData.treeHeight - 1; dagData.allTask.insert(task); } else if(lineElements.size() >= 8 && lineElements[0] == "P2M") @@ -177,6 +187,7 @@ bool parseLine(DagData & dagData, deque & lineElements) task.id[0] = stoll(lineElements[5]); task.id[1] = stoll(lineElements[6]); task.mpiNode = stoi(lineElements[7]); + task.level = 0; dagData.allTask.insert(task); } else @@ -268,37 +279,91 @@ void fillPerformanceData(const char* const filename, DagData & dagData) } fichier.close(); // on ferme le fichier } -void compareDag(DagData& dag1, DagData& dag2, int treeHeight) +void compareDag(DagData const& dag1, DagData const& dag2, int const treeHeight) { - long long int notFoundCount[treeHeight] = {0}; - bool notFound[treeHeight] = {false}; - for(Task task : dag1.allTask) + #pragma omp parallel { - bool found = false; - if(task.type == P2P || task.type == P2P_OUT || task.type == P2M || task.type == L2P) - notFound[treeHeight-1] = true; - else if(task.id[0] < treeHeight) - ++notFound[task.id[0]] = true; - for(Task task2 : dag2.allTask) + #pragma omp single nowait { - if(task == task2) + long long int notFoundCount[omp_get_num_threads()][treeHeight]; + long long int differenceMapping[omp_get_num_threads()][treeHeight]; + long long int taskCount[omp_get_num_threads()][treeHeight]; + for(int i = 0; i < omp_get_num_threads(); ++i) { - found = true; - break; + for(int j = 0; j < treeHeight; ++j) + { + notFoundCount[i][j] = 0; + taskCount[i][j] = 0; + differenceMapping[i][j] = 0; + } + } + for(Task task : dag1.allTask) + { + #pragma omp task default(shared) firstprivate(task) + { + bool found = false; + Task sameTask[2]; + int sameTaskId = 0; + if(task.level < treeHeight) + ++taskCount[omp_get_thread_num()][task.level]; + for(auto it = dag2.allTask.begin(); it != dag2.allTask.end(); ++it) + { + if(task == *it) + { + sameTask[sameTaskId++] = *it; + found = true; + if(sameTaskId == 2) + break; + } + } + if(found == false) + { + //task.print(); + if(task.level < treeHeight) + ++notFoundCount[omp_get_thread_num()][task.level]; + } + else + { + bool sameNode = false; + for(int i = 0; i < sameTaskId; ++i) + if(sameTask[i].mpiNode == task.mpiNode) + sameNode = true; + + if(!sameNode) + { + #pragma omp critical + { + task.print(); + sameTask[0].print();//Il y a au moins une tâche identique trouvée + if(sameTaskId == 2) + sameTask[1].print();//Il y a au moins une tâche identique trouvée + cout << sameTaskId << endl; + cout << endl; + } + if(task.level < treeHeight) + ++differenceMapping[omp_get_thread_num()][task.level]; + } + } + } + } + #pragma omp taskwait + for(int i = 0; i < treeHeight; ++i) + { + long long int sum = 0; + long long int sumDiffMapping = 0; + long long int sumTaskCount = 0; + for(int j = 0; j < omp_get_num_threads(); ++j) + if(taskCount[j][i] > 0) + { + sum += notFoundCount[j][i]; + sumDiffMapping += differenceMapping[j][i]; + sumTaskCount += taskCount[j][i]; + } + if(sum > 0 || sumDiffMapping > 0) + std::cout << "Diff lvl " << i << " -> " << sum << " (Mapping error : " << sumDiffMapping << "/" << sumTaskCount << ")" << std::endl; } - } - if(found == false) - { - task.print(); - if(task.type == P2P || task.type == P2P_OUT || task.type == P2M || task.type == L2P) - ++notFoundCount[treeHeight-1]; - else - ++notFoundCount[task.id[0]]; } } - for(int i = 0; i < treeHeight; ++i) - if(notFound[i] == true) - cout << "Diff lvl " << i << " -> " << notFoundCount[i] << endl; } int main(int argc, char* argv[]) { @@ -334,10 +399,12 @@ int main(int argc, char* argv[]) DagData implicitData, explicitData; bool implicitGood, explicitGood; std::thread explicitThread([&](){ + explicitData.treeHeight = treeHeight; fillPerformanceData(explicitTraceFilename, explicitData); explicitGood = fillDagData(explicitFilename, explicitData); }); std::thread implicitThread([&](){ + implicitData.treeHeight = treeHeight; fillPerformanceData(implicitTraceFilename, implicitData); implicitGood = fillDagData(implicitFilename, implicitData); }); @@ -347,7 +414,7 @@ int main(int argc, char* argv[]) { cout << explicitData.allTask.size() << " tasks in explicit." << endl; cout << implicitData.allTask.size() << " tasks in implicit." << endl; - compareDag(explicitData, implicitData, treeHeight); + compareDag(implicitData, explicitData, treeHeight); } return 0; } diff --git a/Tests/GroupTree/testBlockedImplicitAlgorithm.cpp b/Tests/GroupTree/testBlockedImplicitAlgorithm.cpp index a6c70f034b09fb4158f8080c721261cf2bb4b82a..2d4726b883ab1fd5a9ded168e213c944d7ff9bc8 100644 --- a/Tests/GroupTree/testBlockedImplicitAlgorithm.cpp +++ b/Tests/GroupTree/testBlockedImplicitAlgorithm.cpp @@ -39,6 +39,7 @@ using namespace std; #include "../../Src/Core/FFmmAlgorithm.hpp" std::vector getMortonIndex(const char* const mapping_filename); +void timeAverage(int mpi_rank, int nproc, double elapsedTime); int main(int argc, char* argv[]){ setenv("STARPU_NCPU","1",1); @@ -131,18 +132,22 @@ int main(int argc, char* argv[]){ // Run the algorithm GroupKernelClass groupkernel; GroupAlgorithm groupalgo(&groupedTree,&groupkernel, distributedMortonIndex); + FTic timerExecute; groupalgo.execute(); + double elapsedTime = timerExecute.tacAndElapsed(); + cout << "Executing time (implicit node " << groupalgo.getRank() << ") " << elapsedTime << "s\n"; + timeAverage(groupalgo.getRank(), groupalgo.getNProc(), elapsedTime); + // Usual algorithm KernelClass kernels; // FTestKernels FBasicKernels FmmClass algo(&tree,&kernels); //FFmmAlgorithm FFmmAlgorithmThread algo.execute(); int rank = groupalgo.getRank(); - for(int i = 0; i < groupedTree.getHeight(); ++i) + for(int i = 2; i < groupedTree.getHeight(); ++i)//No task at level 0 and 1 { if(groupedTree.getNbCellGroupAtLevel(i) < groupalgo.getNProc() && rank == 0) std::cout << "Error at level " << i << std::endl; } - return 0; // Validate the result for(int idxLevel = 2 ; idxLevel < groupedTree.getHeight() ; ++idxLevel){ for(int idxGroup = 0 ; idxGroup < groupedTree.getNbCellGroupAtLevel(idxLevel) ; ++idxGroup){ @@ -217,3 +222,22 @@ std::vector getMortonIndex(const char* const mapping_filename) cerr << "Impossible d'ouvrir le fichier !" << endl; return ret; } +void timeAverage(int mpi_rank, int nproc, double elapsedTime) +{ + if(mpi_rank == 0) + { + double sumElapsedTime = elapsedTime; + for(int i = 1; i < nproc; ++i) + { + double tmp; + MPI_Recv(&tmp, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, 0); + sumElapsedTime += tmp; + } + sumElapsedTime = sumElapsedTime / (double)nproc; + std::cout << "Average time per node : " << sumElapsedTime << "s" << std::endl; + } + else + { + MPI_Send(&elapsedTime, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); + } +} diff --git a/Tests/GroupTree/testBlockedMpiAlgorithm.cpp b/Tests/GroupTree/testBlockedMpiAlgorithm.cpp index 509c9c600731716cbbdbe3c697c5de566861fdd0..a58e6bac3747c2daab80ccac323cdf2c1d006c91 100644 --- a/Tests/GroupTree/testBlockedMpiAlgorithm.cpp +++ b/Tests/GroupTree/testBlockedMpiAlgorithm.cpp @@ -43,6 +43,7 @@ +void timeAverage(int mpi_rank, int nproc, double elapsedTime); int main(int argc, char* argv[]){ const FParameterNames LocalOptionBlocSize { @@ -128,15 +129,13 @@ int main(int argc, char* argv[]){ mpiComm.global().processId()+1, 0, mpiComm.global().getComm()), __LINE__); } - FLOG(std::cout << "My last index is " << leftLimite << "\n"); - FLOG(std::cout << "My left limite is " << myLeftLimite << "\n"); for(int i = 0; i < mpiComm.global().processCount(); ++i) { if(i == mpiComm.global().processId()) { - std::cout << "My last index is (" << mpiComm.global().processId() << ") " << leftLimite << "\n"; - std::cout << "My left limite is (" << mpiComm.global().processId() << ") " << myLeftLimite << "\n"; - std::cout << "Size (" << mpiComm.global().processId() << ") " << allParticles.getNbParticles() << "\n"; + FLOG(std::cout << "My last index is (" << mpiComm.global().processId() << ") " << leftLimite << "\n"); + FLOG(std::cout << "My left limite is (" << mpiComm.global().processId() << ") " << myLeftLimite << "\n"); + FLOG(std::cout << "Size (" << mpiComm.global().processId() << ") " << allParticles.getNbParticles() << "\n"); } mpiComm.global().barrier(); } @@ -144,15 +143,16 @@ int main(int argc, char* argv[]){ // Put the data into the tree GroupOctreeClass groupedTree(NbLevels, loader.getBoxWidth(), loader.getCenterOfBox(), groupSize, &allParticles, true, leftLimite); - //groupedTree.printInfoBlocks(); // Run the algorithm GroupKernelClass groupkernel; GroupAlgorithm groupalgo(mpiComm.global(), &groupedTree,&groupkernel); + FTic timerExecute; groupalgo.execute(); - - std::cout << "Wait Others... " << std::endl; + double elapsedTime = timerExecute.tacAndElapsed(); + std::cout << "Executing time (explicit node " << mpiComm.global().processId() << ") " << elapsedTime << "s\n"; mpiComm.global().barrier(); + timeAverage(mpiComm.global().processId(), mpiComm.global().processCount(), elapsedTime); groupedTree.forEachCellLeaf([&](GroupCellClass cell, GroupContainerClass* leaf){ const FSize nbPartsInLeaf = leaf->getNbParticles(); @@ -209,4 +209,22 @@ int main(int argc, char* argv[]){ return 0; } - +void timeAverage(int mpi_rank, int nproc, double elapsedTime) +{ + if(mpi_rank == 0) + { + double sumElapsedTime = elapsedTime; + for(int i = 1; i < nproc; ++i) + { + double tmp; + MPI_Recv(&tmp, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, 0); + sumElapsedTime += tmp; + } + sumElapsedTime = sumElapsedTime / (double)nproc; + std::cout << "Average time per node : " << sumElapsedTime << "s" << std::endl; + } + else + { + MPI_Send(&elapsedTime, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD); + } +} diff --git a/compile_dag_result.sh b/compile_dag_result.sh index 9a8f9e6ac0fcf26a4b54eefe23d1a2964116b816..7b49e8171000460db96f98a622e0b02c090957ca 100755 --- a/compile_dag_result.sh +++ b/compile_dag_result.sh @@ -1,6 +1,7 @@ #!/bin/sh export SCALFMM_SIMGRIDOUT='scalfmm.out' -export GROUP_SIZE=8 +export STARPU_STATS=1 +export GROUP_SIZE=32 export TREE_HEIGHT=6 export NB_NODE=8 export NB_PARTICLE_PER_NODE=$((`awk "BEGIN{print 8 ** ($TREE_HEIGHT-1)}"` / $NB_NODE)) @@ -9,28 +10,59 @@ 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 testBlockedImplicitAlgorithm generateMapping testBlockedMpiAlgorithm compareDAGmapping -j $((`nproc`*2)) if [ $? -ne 0 ]; then exit fi + +#Execute explicit mpi version mpiexec -n $NB_NODE ./Tests/Release/testBlockedMpiAlgorithm -nb $NB_PARTICLE_PER_NODE -bs $GROUP_SIZE -h $TREE_HEIGHT if [ $? -ne 0 ]; then exit fi +#Aggregate task information from explicit execution a=`ls $SCALFMM_SIMGRIDOUT\_*` rm -f $SCALFMM_SIMGRIDOUT echo $a for i in $a; do - echo $i cat $i >> $SCALFMM_SIMGRIDOUT done +#Get task information cp -f $SCALFMM_SIMGRIDOUT scalfmm_explicit.out -mpiexec -n $NB_NODE ./Tests/Release/generateMapping -nb $NB_PARTICLE_PER_NODE -bs $GROUP_SIZE -h $TREE_HEIGHT +#Get task information from fxt +#a=`ls $STARPU_FXT_PREFIX/../installprof*` +#ARG_FXT_TOO="" +#for i in $a; do + #ARG_FXT_TOO="$ARG_FXT_TOO -i $i" +#done +#$STARPU_DIR/bin/starpu_fxt_tool $ARG_FXT_TOO +#cp $STARPU_FXT_PREFIX/../trace.rec explicit.rec +#rm -f $STARPU_FXT_PREFIX/../installprof* + +#Generate mapping for implicite version +mpiexec -n $NB_NODE ./Tests/Release/generateMapping -nb $NB_PARTICLE_PER_NODE -bs $GROUP_SIZE -h $TREE_HEIGHT > /dev/null +#Execute implicit version mpiexec -n $NB_NODE ./Tests/Release/testBlockedImplicitAlgorithm -map mapping -f canard.fma -bs $GROUP_SIZE -h $TREE_HEIGHT if [ $? -ne 0 ]; then exit fi + +#Get task information cp -f scalfmm.out_0 scalfmm_implicit.out +#Get task information from fxt +a=`ls $STARPU_FXT_PREFIX/../installprof*` +#ARG_FXT_TOO="" +#for i in $a; do + #ARG_FXT_TOO="$ARG_FXT_TOO -i $i" +#done +#$STARPU_DIR/bin/starpu_fxt_tool $ARG_FXT_TOO +#cp $STARPU_FXT_PREFIX/../trace.rec implicit.rec +#rm -f $STARPU_FXT_PREFIX/../installprof* + +#Compare DAGs ./Tests/Release/compareDAGmapping -e scalfmm_explicit.out -i scalfmm_implicit.out -h $TREE_HEIGHT > output + +