Commit 027ef985 authored by Sylvain Thery's avatar Sylvain Thery

// foreach & tutos

parent 1ee70274
...@@ -42,6 +42,9 @@ target_link_libraries( traverse_cells ${CGoGN_LIBS_D} ${CGoGN_EXT_LIBS} ) ...@@ -42,6 +42,9 @@ target_link_libraries( traverse_cells ${CGoGN_LIBS_D} ${CGoGN_EXT_LIBS} )
add_executable( traverse_neighbours traverse_neighbours.cpp) add_executable( traverse_neighbours traverse_neighbours.cpp)
target_link_libraries( traverse_neighbours ${CGoGN_LIBS_D} ${CGoGN_EXT_LIBS} ) 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_UI( show_traversors_ui2 show_traversors2.ui )
QT4_WRAP_CPP(show_traversors_moc2 show_traversors2.h) QT4_WRAP_CPP(show_traversors_moc2 show_traversors2.h)
add_executable( show_traversors2 show_traversors2.cpp ${show_traversors_ui2} ${show_traversors_moc2}) 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 @@ ...@@ -26,7 +26,7 @@
#include "Topology/generic/parameters.h" #include "Topology/generic/parameters.h"
#include "Topology/map/embeddedMap2.h" #include "Topology/map/embeddedMap2.h"
#include "Algo/Tiling/Surface/square.h" #include "Algo/Tiling/Surface/square.h"
#include "Algo/Geometry/area.h"
using namespace CGoGN ; using namespace CGoGN ;
...@@ -55,13 +55,11 @@ int main() ...@@ -55,13 +55,11 @@ int main()
VertexAttribute<VEC3, MAP_IMPL> position = myMap.addAttribute<VEC3, VERTEX>("position"); VertexAttribute<VEC3, MAP_IMPL> position = myMap.addAttribute<VEC3, VERTEX>("position");
// create a topo grid of 2x2 squares // 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 // and embed it using position attribute
grid.embedIntoGrid(position, 1.,1.,0.); grid.embedIntoGrid(position, 1.,1.,0.);
// ALGO: // ALGO:
// foreach vertex of the map // foreach vertex of the map
// print position of the vertex // print position of the vertex
...@@ -106,9 +104,41 @@ int main() ...@@ -106,9 +104,41 @@ int main()
{ {
std::cout << v << " : " << position[v]<< " / "; std::cout << v << " : " << position[v]<< " / ";
}); });
// warning here v is a Vertex and not a Dart (but can cast automatically into)
std::cout << std::endl; 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; return 0;
} }
...@@ -163,66 +163,15 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n ...@@ -163,66 +163,15 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n
for (unsigned int i = 0; i < nbth; ++i) for (unsigned int i = 0; i < nbth; ++i)
vd[i].reserve(SIZE_BUFFER_THREAD); vd[i].reserve(SIZE_BUFFER_THREAD);
AttributeContainer* cont = NULL; unsigned int nb=0;
DartMarker<MAP>* dmark = NULL; TraversorCell<MAP, ORBIT> trav(map);
CellMarker<MAP, ORBIT>* cmark = NULL; Cell<ORBIT> cell = trav.begin();
const AttributeMultiVector<Dart>* quickTraversal = map.template getQuickTraversal<ORBIT>() ; Cell<ORBIT> c_end = trav.end();
while ((cell.dart != c_end.dart) && (nb < nbth*SIZE_BUFFER_THREAD) )
// fill each vd buffers with SIZE_BUFFER_THREAD darts
Dart d;
unsigned int di=0;
if(quickTraversal != NULL)
{ {
cont = &(map.template getAttributeContainer<ORBIT>()) ; vd[nb%nbth].push_back(cell.dart);
nb++;
di = cont->begin(); cell = trav.next();
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);
}
}
} }
boost::barrier sync1(nbth+1); boost::barrier sync1(nbth+1);
...@@ -244,8 +193,6 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n ...@@ -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); 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( 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 // and continue to traverse the map
std::vector<Dart>* tempo = new std::vector<Dart>[nbth]; 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 ...@@ -253,79 +200,27 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n
for (unsigned int i = 0; i < nbth; ++i) for (unsigned int i = 0; i < nbth; ++i)
tempo[i].reserve(SIZE_BUFFER_THREAD); tempo[i].reserve(SIZE_BUFFER_THREAD);
while (cell.dart != c_end.dart)
if (cont)
{ {
while (di != cont->end()) for (unsigned int i = 0; i < nbth; ++i)
{ tempo[i].clear();
for (unsigned int i = 0; i < nbth; ++i) nb = 0;
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++;
cont->next(di); while ((cell.dart != c_end.dart) && (nb < nbth*SIZE_BUFFER_THREAD) )
}
sync1.wait();
for (unsigned int i = 0; i < nbth; ++i)
vd[i].swap(tempo[i]);
sync2.wait();
}
}
else if (cmark)
{
while (d != map.end())
{ {
for (unsigned int i = 0; i < nbth; ++i) tempo[nb%nbth].push_back(cell);
tempo[i].clear(); nb++;
unsigned int nb = 0; cell = trav.next();
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();
} }
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(); sync1.wait();// wait for all thread to finish its vector
finished = true; finished = true; // say finsih to everyone
sync2.wait(); sync2.wait(); //wait to everybody to say finished !
//wait for all theads to be finished //wait for all theads to be finished
for (unsigned int i = 0; i < nbth; ++i) for (unsigned int i = 0; i < nbth; ++i)
...@@ -338,12 +233,6 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n ...@@ -338,12 +233,6 @@ void foreach_cell(MAP& map, std::vector<FunctorMapThreaded<MAP>*>& funcs, bool n
delete[] threads; delete[] threads;
delete[] vd; delete[] vd;
delete[] tempo; delete[] tempo;
if (cmark != NULL)
delete cmark;
if (dmark != NULL)
delete dmark;
} }
template <typename MAP> template <typename MAP>
......
...@@ -324,6 +324,23 @@ assert(sizeof(FROM_T) == sizeof(TO_T)); ...@@ -324,6 +324,23 @@ assert(sizeof(FROM_T) == sizeof(TO_T));
::new(p) TO_T(); // use of placement new ::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 } // namespace CGoGN
#include "Topology/generic/attributeHandler.hpp" #include "Topology/generic/attributeHandler.hpp"
......
...@@ -22,6 +22,10 @@ ...@@ -22,6 +22,10 @@
* * * *
*******************************************************************************/ *******************************************************************************/
#include <boost/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <vector>
namespace CGoGN namespace CGoGN
{ {
...@@ -263,4 +267,116 @@ inline void AttributeHandler<T, ORBIT, MAP_IMPL>::next(unsigned int& iter) const ...@@ -263,4 +267,116 @@ inline void AttributeHandler<T, ORBIT, MAP_IMPL>::next(unsigned int& iter) const
m_map->template getAttributeContainer<ORBIT>().next(iter) ; 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 } //namespace CGoGN
...@@ -65,6 +65,12 @@ typedef Cell<EDGE> Edge; ...@@ -65,6 +65,12 @@ typedef Cell<EDGE> Edge;
typedef Cell<FACE> Face; typedef Cell<FACE> Face;
typedef Cell<VOLUME> Vol; // not Volume because of the namespace Volume typedef Cell<VOLUME> Vol; // not Volume because of the namespace Volume
namespace Parallel
{
const unsigned int SIZE_BUFFER_THREAD = 8192;
}
} }
#endif /* CELLS_H_ */ #endif /* CELLS_H_ */
...@@ -87,7 +87,11 @@ inline void foreach_cell_until(const MAP& map, FUNC f, bool forceDartMarker = fa ...@@ -87,7 +87,11 @@ inline void foreach_cell_until(const MAP& map, FUNC f, bool forceDartMarker = fa
break; 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> template <typename MAP>
class TraversorV : public TraversorCell<MAP, VERTEX> class TraversorV : public TraversorCell<MAP, VERTEX>
...@@ -121,6 +125,9 @@ public: ...@@ -121,6 +125,9 @@ public:
{} {}
}; };
} // namespace CGoGN } // namespace CGoGN
#include "Topology/generic/traversor/traversorCell.hpp" #include "Topology/generic/traversor/traversorCell.hpp"
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
* Contact information: cgogn@unistra.fr * * Contact information: cgogn@unistra.fr *
* * * *
*******************************************************************************/ *******************************************************************************/
#include <boost/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <vector>