Attention une mise à jour du serveur va être effectuée le lundi 17 mai entre 13h et 13h30. Cette mise à jour va générer une interruption du service de quelques minutes.

Commit 10185739 authored by BRAMAS Berenger's avatar BRAMAS Berenger

Add an parallel for each to iterate on the tree (and some utils class to hide...

Add an parallel for each to iterate on the tree (and some utils class to hide complexity to the user)
parent 7dd59e98
#ifndef FPARFOREACHOCTREE_HPP
#define FPARFOREACHOCTREE_HPP
#include "FOctree.hpp"
#include <functional>
namespace FParForEachOctree {
/////////////////////////////////////////////////////////
// Lambda function to apply to all member
/////////////////////////////////////////////////////////
/**
* @brief forEachLeaf iterate on the leaf and apply the function
* @param function
*/
template< template< class CellClass, class ContainerClass, class LeafClass, class CellAllocatorClass > class FOctree,
class CellClass, class ContainerClass, class LeafClass, class CellAllocatorClass,
class FunctionTemplate>
void forEachLeaf(FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>* tree, FunctionTemplate function){
#pragma omp parallel
{
#pragma omp single
{
typename FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>::Iterator octreeIterator(tree);
octreeIterator.gotoBottomLeft();
do{
LeafClass* lf = octreeIterator.getCurrentLeaf();
#pragma omp task firstprivate(lf)
{
function(lf);
}
} while(octreeIterator.moveRight());
#pragma omp taskwait
}
}
}
/**
* @brief forEachLeaf iterate on the cell and apply the function
* @param function
*/
template< template< class CellClass, class ContainerClass, class LeafClass, class CellAllocatorClass > class FOctree,
class CellClass, class ContainerClass, class LeafClass, class CellAllocatorClass,
class FunctionTemplate>
void forEachCell(FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>* tree, FunctionTemplate function){
#pragma omp parallel
{
#pragma omp single
{
typename FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>::Iterator octreeIterator(tree);
octreeIterator.gotoBottomLeft();
typename FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>::Iterator avoidGoLeft(octreeIterator);
for(int idx = tree->getHeight()-1 ; idx >= 1 ; --idx ){
do{
CellClass* cell = octreeIterator.getCurrentCell();
#pragma omp task firstprivate(cell)
{
function(cell);
}
} while(octreeIterator.moveRight());
avoidGoLeft.moveUp();
octreeIterator = avoidGoLeft;
}
#pragma omp taskwait
}
}
}
/**
* @brief forEachLeaf iterate on the cell and apply the function
* @param function
*/
template< template< class CellClass, class ContainerClass, class LeafClass, class CellAllocatorClass > class FOctree,
class CellClass, class ContainerClass, class LeafClass, class CellAllocatorClass,
class FunctionTemplate>
void forEachCellWithLevel(FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>* tree, FunctionTemplate function){
#pragma omp parallel
{
#pragma omp single
{
typename FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>::Iterator octreeIterator(tree);
octreeIterator.gotoBottomLeft();
typename FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>::Iterator avoidGoLeft(octreeIterator);
for(int idx = tree->getHeight()-1 ; idx >= 1 ; --idx ){
do{
CellClass* cell = octreeIterator.getCurrentCell();
#pragma omp task firstprivate(cell, idx)
{
function(cell,idx);
}
} while(octreeIterator.moveRight());
avoidGoLeft.moveUp();
octreeIterator = avoidGoLeft;
}
#pragma omp taskwait
}
}
}
/**
* @brief forEachLeaf iterate on the cell and apply the function
* @param function
*/
template< template< class CellClass, class ContainerClass, class LeafClass, class CellAllocatorClass > class FOctree,
class CellClass, class ContainerClass, class LeafClass, class CellAllocatorClass,
class FunctionTemplate>
void forEachCellLeaf(FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>* tree, FunctionTemplate function){
#pragma omp parallel
{
#pragma omp single
{
typename FOctree<CellClass,ContainerClass,LeafClass,CellAllocatorClass>::Iterator octreeIterator(tree);
octreeIterator.gotoBottomLeft();
do{
CellClass* cell = octreeIterator.getCurrentCell();
LeafClass* lf = octreeIterator.getCurrentLeaf();
#pragma omp task firstprivate(cell, lf)
{
function(cell,lf);
}
} while(octreeIterator.moveRight());
#pragma omp taskwait
}
}
}
}
#endif // FPARFOREACHOCTREE_HPP
#ifndef FPAROBJECT_HPP
#define FPAROBJECT_HPP
#include <omp.h>
#include <functional>
/**
* This class is a way to hide concurent access to the user.
* Especially with the FParForEachOctree functions.
* Please refer to the testOctreeParallelFuncteur to see an example.
*/
template <class SharedClass>
class FParObject{
const int nbThreads;
SharedClass* objects;
FParObject(const FParObject&) = delete;
FParObject& operator=(const FParObject&) = delete;
public:
template <class... ArgsClass>
explicit FParObject(ArgsClass... args) : nbThreads(omp_get_max_threads()), objects(nullptr) {
objects = reinterpret_cast<SharedClass*>(new unsigned char[sizeof(SharedClass)*nbThreads]);
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
new (&objects[idxThread]) SharedClass(args...);
}
}
~FParObject(){
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
objects[idxThread].~SharedClass();
}
delete[] reinterpret_cast<unsigned char*>(objects);
}
SharedClass& getMine(){
return objects[omp_get_thread_num()];
}
const SharedClass& getMine() const {
return objects[omp_get_thread_num()];
}
void applyToAll(std::function<void(SharedClass&)> func){
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
func(objects[idxThread]);
}
}
void applyToAllPar(std::function<void(SharedClass&)> func){
#pragma omp parallel for num_threads(nbThreads) schedule(static)
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
func(objects[idxThread]);
}
}
SharedClass reduce(std::function<SharedClass(const SharedClass&, const SharedClass&)> func){
if(nbThreads == 0){
return SharedClass();
}
else if(nbThreads == 1){
return objects[0];
}
else{
SharedClass res = func(objects[0], objects[1]);
for(int idxThread = 2 ; idxThread < nbThreads ; ++idxThread){
res = func(res, objects[idxThread]);
}
return res;
}
}
void set(const SharedClass& val){
#pragma omp parallel for num_threads(nbThreads) schedule(static)
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
objects[idxThread] = val;
}
}
FParObject& operator=(const SharedClass& val){
set(val);
return *this;
}
};
template <class SharedClass>
class FParArray{
const int nbThreads;
SharedClass** arrays;
size_t arraySize;
FParArray(const FParArray&) = delete;
FParArray& operator=(const FParArray&) = delete;
public:
explicit FParArray(const size_t inArraySize = 0)
: nbThreads(omp_get_max_threads()), arrays(nullptr), arraySize(inArraySize) {
arrays = new SharedClass*[nbThreads];
#pragma omp parallel for schedule(static)
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
arrays[idxThread] = new SharedClass[inArraySize];
if(std::is_pod<SharedClass>::value){
memset(arrays[idxThread], 0, sizeof(SharedClass)*inArraySize);
}
}
}
~FParArray(){
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
delete[] arrays[idxThread];
}
delete[] arrays;
}
void resize(const size_t inArraySize){
if(inArraySize != arraySize){
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
delete[] arrays[idxThread];
}
arraySize = inArraySize;
#pragma omp parallel for schedule(static)
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
arrays[idxThread] = new SharedClass[inArraySize];
if(std::is_pod<SharedClass>::value){
memset(arrays[idxThread], 0, sizeof(SharedClass)*inArraySize);
}
}
}
}
SharedClass* getMine(){
return arrays[omp_get_thread_num()];
}
const SharedClass* getMine() const {
return arrays[omp_get_thread_num()];
}
void applyToAll(std::function<void(SharedClass*)> func){
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
func(arrays[idxThread]);
}
}
void applyToAllPar(std::function<void(SharedClass*)> func){
#pragma omp parallel for num_threads(nbThreads) schedule(static)
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
func(arrays[idxThread]);
}
}
void reduceArray(SharedClass* resArray, std::function<SharedClass(const SharedClass&, const SharedClass&)> func){
if(nbThreads == 0){
}
else if(nbThreads == 1){
if(std::is_pod<SharedClass>::value){
memcpy(resArray, arrays[0], sizeof(SharedClass)*arraySize);
}
else{
for(int idxVal = 0 ; idxVal < arraySize ; ++idxVal){
resArray = arrays[0][idxVal];
}
}
}
else{
for(int idxVal = 0 ; idxVal < arraySize ; ++idxVal){
resArray[idxVal] = func(arrays[0][idxVal], arrays[1][idxVal]);
}
for(int idxThread = 2 ; idxThread < nbThreads ; ++idxThread){
for(int idxVal = 0 ; idxVal < arraySize ; ++idxVal){
resArray[idxVal] = func(resArray[idxVal], arrays[idxThread][idxVal]);
}
}
}
}
void copyArray(const SharedClass* array){
#pragma omp parallel for num_threads(nbThreads) schedule(static)
for(int idxThread = 0 ; idxThread < nbThreads ; ++idxThread){
if(std::is_pod<SharedClass>::value){
memcpy(arrays[idxThread], array, sizeof(SharedClass)*arraySize);
}
else{
for(int idxVal = 0 ; idxVal < arraySize ; ++idxVal){
arrays[idxThread][idxVal] = array[idxVal];
}
}
}
}
};
#endif // FPAROBJECT_HPP
// ===================================================================================
// Copyright ScalFmm 2011 INRIA, Olivier Coulaud, Bérenger Bramas, Matthias Messner
// olivier.coulaud@inria.fr, berenger.bramas@inria.fr
// This software is a computer program whose purpose is to compute the FMM.
//
// This software is governed by the CeCILL-C and LGPL licenses and
// abiding by the rules of distribution of free software.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <time.h>
#include "../../Src/Utils/FTic.hpp"
#include "../../Src/Utils/FParameters.hpp"
#include "../../Src/Containers/FOctree.hpp"
#include "../../Src/Containers/FParForEachOctree.hpp"
#include "../../Src/Containers/FVector.hpp"
#include "../../Src/Utils/FAssert.hpp"
#include "../../Src/Utils/FPoint.hpp"
#include "../../Src/Utils/FParObject.hpp"
#include "../../Src/Components/FBasicParticleContainer.hpp"
#include "../../Src/Components/FBasicCell.hpp"
#include "../../Src/Components/FSimpleLeaf.hpp"
#include "../../Src/Files/FRandomLoader.hpp"
#include "../../Src/Utils/FParameterNames.hpp"
/**
* In this file we show how to use octree's functeur
*/
int main(int argc, char ** argv){
FHelpDescribeAndExit(argc, argv,
"Show how to use an octree functeur parallelized (only the code is interesting)",
FParameterDefinitions::NbParticles);
typedef FBasicCell CellClass;
typedef FBasicParticleContainer<0> ContainerClass;
typedef FSimpleLeaf< ContainerClass > LeafClass;
typedef FOctree<CellClass, ContainerClass , LeafClass > OctreeClass;
///////////////////////What we do/////////////////////////////
std::cout << ">> This executable is useless to execute.\n";
std::cout << ">> It is only interesting to wath the code to understand\n";
std::cout << ">> how to use the Octree\n";
//////////////////////////////////////////////////////////////
const int NbPart = FParameters::getValue(argc,argv,FParameterDefinitions::NbParticles.options, 2000);
FTic counter;
FRandomLoader loader(NbPart, 1, FPoint(0.5,0.5,0.5), 1);
OctreeClass tree(10, 3, loader.getBoxWidth(), loader.getCenterOfBox());
// -----------------------------------------------------
std::cout << "Creating and inserting " << NbPart << " particles ..." << std::endl;
counter.tic();
{
FPoint particlePosition;
for(int idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
loader.fillParticle(&particlePosition);
tree.insert(particlePosition);
}
}
counter.tac();
std::cout << "Done " << "(" << counter.elapsed() << ")." << std::endl;
// -----------------------------------------------------
// Call a function on each leaf
FParObject<long> nbParticles(0);
FParForEachOctree::forEachLeaf(&tree, [&](LeafClass* leaf){
nbParticles.getMine() += leaf->getSrc()->getNbParticles();
});
const long totalNbParticles = nbParticles.reduce([](long v1, long v2) -> long {return v1 + v2;});
std::cout << "There are " << totalNbParticles << " particles " << std::endl;
// Call a function on each cell
FParObject<long> nbCells;
nbCells = 0;
FParForEachOctree::forEachCell(&tree, [&nbCells](CellClass* /*cell*/){
nbCells.getMine() += 1;
});
std::cout << "There are " << nbCells.reduce([](long v1, long v2) -> long {return v1 + v2;}) << " cells " << std::endl;
// To get cell and particles at leaf level
FParForEachOctree::forEachCellLeaf(&tree, [&](CellClass* cell, LeafClass* /*leaf*/){
cell->resetToInitialState();
});
// If we need an array of long
FParArray<long> arrayExample(10);
arrayExample.resize(50);
FParForEachOctree::forEachCellLeaf(&tree, [&](CellClass* /*cell*/, LeafClass* /*leaf*/){
arrayExample.getMine()[0] += 10;
});
return 0;
}
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