Commit 01ce9ff4 authored by Pierre Kraemer's avatar Pierre Kraemer

Merge branch 'develop' of cgogn:~thery/CGoGNMR into develop

parents 950f5e11 027ef985
......@@ -42,6 +42,9 @@ target_link_libraries( traverse_cells ${CGoGN_LIBS_D} ${CGoGN_EXT_LIBS} )
add_executable( traverse_neighbours traverse_neighbours.cpp)
target_link_libraries( traverse_neighbours ${CGoGN_LIBS_D} ${CGoGN_EXT_LIBS} )
add_executable( traverse_attributes traverse_attributes.cpp)
target_link_libraries( traverse_attributes ${CGoGN_LIBS_D} ${CGoGN_EXT_LIBS} )
QT4_WRAP_UI( show_traversors_ui2 show_traversors2.ui )
QT4_WRAP_CPP(show_traversors_moc2 show_traversors2.h)
add_executable( show_traversors2 show_traversors2.cpp ${show_traversors_ui2} ${show_traversors_moc2})
......
/*******************************************************************************
* CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps *
* version 0.1 *
* Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg *
* *
* This library is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, or (at your *
* option) any later version. *
* *
* This library 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 Lesser General Public License *
* for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this library; if not, write to the Free Software Foundation, *
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
* *
* Web site: http://cgogn.unistra.fr/ *
* Contact information: cgogn@unistra.fr *
* *
*******************************************************************************/
#include "Topology/generic/parameters.h"
#include "Topology/map/embeddedMap2.h"
#include "Algo/Tiling/Surface/square.h"
using namespace CGoGN ;
/**
* Struct that contains some informations about the types of the manipulated objects
* Mainly here to be used by the algorithms that are parameterized by it
*/
struct PFP: public PFP_STANDARD
{
// definition of the type of the map
typedef EmbeddedMap2 MAP;
};
// some typedef shortcuts
typedef PFP::MAP MAP ; // map type
typedef PFP::MAP::IMPL MAP_IMPL ; // map implementation
typedef PFP::VEC3 VEC3 ; // type of R³ vector
int main()
{
// declare a map to handle the mesh
MAP myMap;
// add position attribute on vertices and get handler on it
VertexAttribute<VEC3, MAP_IMPL> position = myMap.addAttribute<VEC3, VERTEX>("position");
// create a topo grid of 2x2 squares
Algo::Surface::Tilings::Square::Grid<PFP> grid(myMap, 4, 4, true);
// and embed it using position attribute
grid.embedIntoGrid(position, 1.,1.,0.);
// traversal with begin/end/next on attribute handler
for (unsigned int id=position.begin(); id !=position.end(); position.next(id))
{
std::cout << id << " : " << position[id]<< " / ";
};
std::cout << std::endl;
//using foreach function (C++11 lambda expression)
foreach_attribute(position,[&](unsigned int id) // for each element of position
{
std::cout << id << " : " << position[id]<< " / ";
});
// using parallel foreach
// parameter position must be captured explicitly even if it used as first parameter of foreach !
Parallel::foreach_attribute(position,[&position](unsigned int id, unsigned int thread) // for each elt of the position attribute
{
position[id] *= 2.0f;
},4); // 4:4 thread, false for no need for markers in threaded code.
return 0;
}
......@@ -26,7 +26,7 @@
#include "Topology/generic/parameters.h"
#include "Topology/map/embeddedMap2.h"
#include "Algo/Tiling/Surface/square.h"
#include "Algo/Geometry/area.h"
using namespace CGoGN ;
......@@ -55,13 +55,11 @@ int main()
VertexAttribute<VEC3, MAP_IMPL> position = myMap.addAttribute<VEC3, VERTEX>("position");
// create a topo grid of 2x2 squares
Algo::Surface::Tilings::Square::Grid<PFP> grid(myMap, 2, 2, true);
Algo::Surface::Tilings::Square::Grid<PFP> grid(myMap, 4, 4, true);
// and embed it using position attribute
grid.embedIntoGrid(position, 1.,1.,0.);
// ALGO:
// foreach vertex of the map
// print position of the vertex
......@@ -106,9 +104,41 @@ int main()
{
std::cout << v << " : " << position[v]<< " / ";
});
// warning here v is a Vertex and not a Dart (but can cast automatically into)
std::cout << std::endl;
// warning here v is a Vertex and not a Dart (but can cast automatically into)
// example of parallel traversal of cells
Parallel::foreach_cell<VERTEX>(myMap,[&](Vertex v, unsigned int thread) // for each Vertex v of the MAP myMap
{
position[v] += VEC3(0.0,0.0,PFP::REAL(thread)*0.1f);
// WARNING thread vary here from 1 to 4 (and not from 0 to 3) !!!!
},4,false); // 4:4 thread, false for no need for markers in threaded code.
std::cout << "After // processing"<< std::endl;
foreach_cell<VERTEX>(myMap,[&](Vertex v) // for each Vertex v of the MAP myMap
{
std::cout << position[v]<< " / ";
});
std::cout << std::endl;
// Example with // accumulation
// computing the sum of area faces
// init nbthread values with 0
float surf[4]={0.0f,0.0f,0.0f,0.0f};
// traverse face in //
Parallel::foreach_cell<FACE>(myMap,[&](Face f, unsigned int thr)
{
// for each face add surface to accumulator (-1 because counter between 1-4 not 0-3)
surf[thr-1] += Algo::Surface::Geometry::convexFaceArea<PFP>(myMap,f,position);
},4,false);
std::cout << surf[0]<< "/"<< surf[1]<< "/"<< surf[2]<< "/"<< surf[3]<< "/"<< std::endl;
std::cout << "Total="<<surf[0]+surf[1]+surf[2]+surf[3]<< std::endl;
return 0;
}
......@@ -163,66 +163,15 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n
for (unsigned int i = 0; i < nbth; ++i)
vd[i].reserve(SIZE_BUFFER_THREAD);
AttributeContainer* cont = NULL;
DartMarker<MAP>* dmark = NULL;
CellMarker<MAP, ORBIT>* cmark = NULL;
const AttributeMultiVector<Dart>* quickTraversal = map.template getQuickTraversal<ORBIT>() ;
// fill each vd buffers with SIZE_BUFFER_THREAD darts
Dart d;
unsigned int di=0;
if(quickTraversal != NULL)
unsigned int nb=0;
TraversorCell<MAP, ORBIT> trav(map);
Cell<ORBIT> cell = trav.begin();
Cell<ORBIT> c_end = trav.end();
while ((cell.dart != c_end.dart) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
cont = &(map.template getAttributeContainer<ORBIT>()) ;
di = cont->begin();
unsigned int nb = 0;
while ((di != cont->end()) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
d = quickTraversal->operator[](di);
vd[nb%nbth].push_back(d);
nb++;
cont->next(di);
}
}
else
{
if(map.template isOrbitEmbedded<ORBIT>())
{
cmark = new CellMarker<MAP, ORBIT>(map) ;
d = map.begin();
unsigned int nb = 0;
while ((d != map.end()) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
if ((!map.template isBoundaryMarked<MAP::DIMENSION>(d)) && (!cmark->isMarked(d)))
{
cmark->mark(d);
vd[nb%nbth].push_back(d);
nb++;
}
map.next(d);
}
}
else
{
dmark = new DartMarker<MAP>(map) ;
d = map.begin();
unsigned int nb = 0;
while ((d != map.end()) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
if ((!map.template isBoundaryMarked<MAP::DIMENSION>(d)) && (!dmark->isMarked(d)))
{
dmark->template markOrbit<ORBIT>(d);
vd[nb%nbth].push_back(d);
nb++;
}
map.next(d);
}
}
vd[nb%nbth].push_back(cell.dart);
nb++;
cell = trav.next();
}
boost::barrier sync1(nbth+1);
......@@ -244,8 +193,6 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n
tfs[i] = new ThreadFunction<MAP>(funcs[i], vd[i],sync1,sync2, finished,1+i);
threads[i] = new boost::thread( boost::ref( *(tfs[i]) ) );
}
// threads[i] = new boost::thread(ThreadFunction<MAP>(funcs[i], vd[i],sync1,sync2, finished,1+i));
// and continue to traverse the map
std::vector<Dart>* tempo = new std::vector<Dart>[nbth];
......@@ -253,79 +200,27 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n
for (unsigned int i = 0; i < nbth; ++i)
tempo[i].reserve(SIZE_BUFFER_THREAD);
if (cont)
while (cell.dart != c_end.dart)
{
while (di != cont->end())
{
for (unsigned int i = 0; i < nbth; ++i)
tempo[i].clear();
unsigned int nb = 0;
while ((di != cont->end()) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
d = quickTraversal->operator[](di);
tempo[nb%nbth].push_back(d);
nb++;
for (unsigned int i = 0; i < nbth; ++i)
tempo[i].clear();
nb = 0;
cont->next(di);
}
sync1.wait();
for (unsigned int i = 0; i < nbth; ++i)
vd[i].swap(tempo[i]);
sync2.wait();
}
}
else if (cmark)
{
while (d != map.end())
while ((cell.dart != c_end.dart) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
for (unsigned int i = 0; i < nbth; ++i)
tempo[i].clear();
unsigned int nb = 0;
while ((d != map.end()) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
if (!map.template isBoundaryMarked<MAP::DIMENSION>(d) && !cmark->isMarked(d))
{
cmark->mark(d);
tempo[nb%nbth].push_back(d);
nb++;
}
map.next(d);
}
sync1.wait();
for (unsigned int i = 0; i < nbth; ++i)
vd[i].swap(tempo[i]);
sync2.wait();
}
}
else
{
while (d != map.end())
{
for (unsigned int i = 0; i < nbth; ++i)
tempo[i].clear();
unsigned int nb = 0;
while ((d != map.end()) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
if ((!map.template isBoundaryMarked<MAP::DIMENSION>(d)) && (!dmark->isMarked(d)))
{
dmark->template markOrbit<ORBIT>(d);
tempo[nb%nbth].push_back(d);
nb++;
}
map.next(d);
}
sync1.wait();
for (unsigned int i = 0; i < nbth; ++i)
vd[i].swap(tempo[i]);
sync2.wait();
tempo[nb%nbth].push_back(cell);
nb++;
cell = trav.next();
}
sync1.wait(); // wait for all thread to finish its vector
for (unsigned int i = 0; i < nbth; ++i)
vd[i].swap(tempo[i]);
sync2.wait(); // everybody refilled then go
}
sync1.wait();
finished = true;
sync2.wait();
sync1.wait();// wait for all thread to finish its vector
finished = true; // say finsih to everyone
sync2.wait(); //wait to everybody to say finished !
//wait for all theads to be finished
for (unsigned int i = 0; i < nbth; ++i)
......@@ -338,12 +233,6 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n
delete[] threads;
delete[] vd;
delete[] tempo;
if (cmark != NULL)
delete cmark;
if (dmark != NULL)
delete dmark;
}
template <typename MAP>
......
......@@ -324,6 +324,23 @@ assert(sizeof(FROM_T) == sizeof(TO_T));
::new(p) TO_T(); // use of placement new
}
/**
* apply function on each element of attribute
* Warning attr must also be captured by lambda funct
*/
template <typename ATTR, typename FUNC>
inline void foreach_attribute(ATTR& attr, FUNC func)
{
for (unsigned int id=attr.begin(); id != attr.end(); attr.next(id))
func(id);
}
namespace Parallel
{
template <typename ATTR, typename FUNC>
void foreach_attribute(ATTR& attribute, FUNC func, unsigned int nbth=0);
}
} // namespace CGoGN
#include "Topology/generic/attributeHandler.hpp"
......
......@@ -22,6 +22,10 @@
* *
*******************************************************************************/
#include <boost/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <vector>
namespace CGoGN
{
......@@ -263,4 +267,116 @@ inline void AttributeHandler<T, ORBIT, MAP_IMPL>::next(unsigned int& iter) const
m_map->template getAttributeContainer<ORBIT>().next(iter) ;
}
namespace Parallel
{
template <typename FUNC>
class ThreadFunctionAttrib
{
protected:
std::vector<unsigned int>& m_ids;
boost::barrier& m_sync1;
boost::barrier& m_sync2;
bool& m_finished;
unsigned int m_id;
FUNC m_lambda;
public:
ThreadFunctionAttrib(FUNC func, std::vector<unsigned int>& vid, boost::barrier& s1, boost::barrier& s2, bool& finished, unsigned int id):
m_ids(vid), m_sync1(s1), m_sync2(s2), m_finished(finished), m_id(id), m_lambda(func)
{
}
ThreadFunctionAttrib(const ThreadFunctionAttrib& tf):
m_ids(tf.m_ids), m_sync1(tf.m_sync1), m_sync2(tf.m_sync2), m_finished(tf.m_finished), m_id(tf.m_id), m_lambda(tf.m_lambda){}
void operator()()
{
while (!m_finished)
{
for (std::vector<unsigned int>::const_iterator it = m_ids.begin(); it != m_ids.end(); ++it)
m_lambda(*it,m_id);
m_sync1.wait();
m_sync2.wait();
}
}
};
template <typename ATTR, typename FUNC>
void foreach_attribute(ATTR& attribute, FUNC func, unsigned int nbth)
{
if (nbth==0)
nbth = boost::thread::hardware_concurrency();
std::vector< unsigned int >* vd = new std::vector< unsigned int >[nbth];
for (unsigned int i = 0; i < nbth; ++i)
vd[i].reserve(SIZE_BUFFER_THREAD);
unsigned int nb = 0;
unsigned int attIdx = attribute.begin();
while ((attIdx != attribute.end()) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
vd[nb%nbth].push_back(attIdx);
nb++;
attribute.next(attIdx);
}
boost::barrier sync1(nbth+1);
boost::barrier sync2(nbth+1);
bool finished=false;
boost::thread** threads = new boost::thread*[nbth];
ThreadFunctionAttrib<FUNC>** tfs = new ThreadFunctionAttrib<FUNC>*[nbth];
for (unsigned int i = 0; i < nbth; ++i)
{
tfs[i] = new ThreadFunctionAttrib<FUNC>(func, vd[i], sync1,sync2,finished,1+i);
threads[i] = new boost::thread( boost::ref( *(tfs[i]) ) );
}
// and continue to traverse the map
std::vector< unsigned int >* tempo = new std::vector< unsigned int >[nbth];
for (unsigned int i = 0; i < nbth; ++i)
tempo[i].reserve(SIZE_BUFFER_THREAD);
while (attIdx != attribute.end())
{
for (unsigned int i = 0; i < nbth; ++i)
tempo[i].clear();
unsigned int nb = 0;
while ((attIdx != attribute.end()) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
tempo[nb%nbth].push_back(attIdx);
nb++;
attribute.next(attIdx);
}
sync1.wait();// wait for all thread to finish its vector
for (unsigned int i = 0; i < nbth; ++i)
vd[i].swap(tempo[i]);
sync2.wait();// everybody refilled then go
}
sync1.wait();// wait for all thread to finish its vector
finished = true;// say finsih to everyone
sync2.wait(); // just wait for last barrier wait !
//wait for all theads to be finished
for (unsigned int i = 0; i < nbth; ++i)
{
threads[i]->join();
delete threads[i];
delete tfs[i];
}
delete[] tfs;
delete[] threads;
delete[] vd;
delete[] tempo;
}
}
} //namespace CGoGN
......@@ -65,6 +65,12 @@ typedef Cell<EDGE> Edge;
typedef Cell<FACE> Face;
typedef Cell<VOLUME> Vol; // not Volume because of the namespace Volume
namespace Parallel
{
const unsigned int SIZE_BUFFER_THREAD = 8192;
}
}
#endif /* CELLS_H_ */
......@@ -92,7 +92,11 @@ inline void foreach_cell_until(const MAP& map, FUNC f, bool forceDartMarker = fa
break;
}
namespace Parallel
{
template <unsigned int ORBIT, typename MAP, typename FUNC>
void foreach_cell(MAP& map, FUNC func, unsigned int nbth=0, bool needMarkers=true);
}
template <typename MAP>
class TraversorV : public TraversorCell<MAP, VERTEX>
......@@ -126,6 +130,9 @@ public:
{}
};
} // namespace CGoGN
#include "Topology/generic/traversor/traversorCell.hpp"
......
......@@ -21,6 +21,9 @@
* Contact information: cgogn@unistra.fr *
* *
*******************************************************************************/
#include <boost/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <vector>
namespace CGoGN
{
......@@ -161,4 +164,129 @@ void TraversorCell<MAP, ORBIT>::skip(Cell<ORBIT> c)
cmark->mark(c) ;
}
namespace Parallel
{
/// internal functor for boost call
template <unsigned int ORBIT, typename FUNC>
class ThreadFunction
{
protected:
typedef Cell<ORBIT> CELL;
std::vector<CELL>& m_cells;
boost::barrier& m_sync1;
boost::barrier& m_sync2;
bool& m_finished;
unsigned int m_id;
FUNC m_lambda;
public:
ThreadFunction(FUNC func, std::vector<CELL>& vd, boost::barrier& s1, boost::barrier& s2, bool& finished, unsigned int id):
m_cells(vd), m_sync1(s1), m_sync2(s2), m_finished(finished), m_id(id), m_lambda(func)
{
}
ThreadFunction(const ThreadFunction<ORBIT, FUNC>& tf):
m_cells(tf.m_cells), m_sync1(tf.m_sync1), m_sync2(tf.m_sync2), m_finished(tf.m_finished), m_id(tf.m_id), m_lambda(tf.m_lambda){}
void operator()()
{
while (!m_finished)
{
for (typename std::vector<CELL>::const_iterator it = m_cells.begin(); it != m_cells.end(); ++it)
m_lambda(*it,m_id);
m_sync1.wait(); // wait every body has finished
m_sync2.wait(); // wait vectors has been refilled
}
}
};
template <unsigned int ORBIT, typename MAP, typename FUNC>
void foreach_cell(MAP& map, FUNC func, unsigned int nbth, bool needMarkers)
{
if (nbth==0)
nbth = boost::thread::hardware_concurrency();
std::vector< Cell<ORBIT> >* vd = new std::vector< Cell<ORBIT> >[nbth];
for (unsigned int i = 0; i < nbth; ++i)
vd[i].reserve(SIZE_BUFFER_THREAD);
// TraversorCell<MAP, ORBIT> trav(map,false,th_orig);
unsigned int nb = 0;
TraversorCell<MAP, ORBIT> trav(map);
Cell<ORBIT> cell = trav.begin();
Cell<ORBIT> c_end = trav.end();
while ((cell.dart != c_end.dart) && (nb < nbth*SIZE_BUFFER_THREAD) )
{
vd[nb%nbth].push_back(cell);
nb++;
cell = trav.next();
}
boost::barrier sync1(nbth+1);
boost::barrier sync2(nbth+1);
bool finished=false;