- multithread in BuildTree
This commit is contained in:
@@ -32,9 +32,6 @@
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <execution>
|
||||
#include <queue>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
|
||||
using namespace std ;
|
||||
@@ -109,17 +106,30 @@ Tree::AdjustLoop( PolyLine& pl, POLYLINEVECTOR& vPl, BOOLVECTOR& vbOrientation)
|
||||
return true ;
|
||||
}
|
||||
|
||||
mutex map3D ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
Tree::GetPoint( double dU, double dV, Point3d& pt) const
|
||||
{
|
||||
pair<int64_t, int64_t> key (static_cast<int64_t>(dU * pow(2,15)), static_cast<int64_t>(dV * pow(2,15))) ;
|
||||
bool bOk = true ;
|
||||
if ( m_mPt3d.find( key) == m_mPt3d.end()) {
|
||||
bOk = bOk && m_pSrfBz->GetPoint( dU / SBZ_TREG_COEFF, dV / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt) ;
|
||||
m_mPt3d[key] = pt ;
|
||||
bool bCalculated = false ;
|
||||
{
|
||||
lock_guard<mutex> lock( map3D) ;
|
||||
bCalculated = m_mPt3d.find( key) != m_mPt3d.end() ;
|
||||
}
|
||||
if ( ! bCalculated) {
|
||||
bOk = bOk && m_pSrfBz->GetPoint( dU / SBZ_TREG_COEFF, dV / SBZ_TREG_COEFF, ISurfBezier::FROM_MINUS, ISurfBezier::FROM_MINUS, pt) ;
|
||||
{
|
||||
lock_guard<mutex> lock( map3D) ;
|
||||
m_mPt3d[key] = pt ;
|
||||
}
|
||||
}
|
||||
{
|
||||
lock_guard<mutex> lock( map3D) ;
|
||||
pt = m_mPt3d[key] ;
|
||||
}
|
||||
pt = m_mPt3d[key] ;
|
||||
return bOk ;
|
||||
}
|
||||
|
||||
@@ -128,8 +138,15 @@ bool
|
||||
Tree::SavePoint( double dU, double dV, Point3d& pt)
|
||||
{
|
||||
pair<int64_t, int64_t> key (static_cast<int64_t>(dU * pow(2,15)), static_cast<int64_t>(dV * pow(2,15))) ;
|
||||
if ( m_mPt3d.find( key) == m_mPt3d.end())
|
||||
bool bCalculated = true ;
|
||||
{
|
||||
lock_guard<mutex> lock( map3D) ;
|
||||
bCalculated = m_mPt3d.find( key) != m_mPt3d.end() ;
|
||||
}
|
||||
if ( ! bCalculated){
|
||||
lock_guard<mutex> lock( map3D) ;
|
||||
m_mPt3d[key] = pt ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
@@ -147,6 +164,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
|
||||
m_mChunk.clear() ;
|
||||
m_vPlApprox.clear() ;
|
||||
m_vCCLoop2D.clear() ;
|
||||
CellCounter = 0 ;
|
||||
|
||||
m_pSrfBz = pSrfBz ;
|
||||
m_bSplitPatches = bSplitPatches ;
|
||||
@@ -646,24 +664,30 @@ Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax)
|
||||
return true ;
|
||||
}
|
||||
|
||||
mutex queueMutex ;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void
|
||||
Tree::BranchManager( queue<function<void()>>& tasks, condition_variable& cv, bool& done)
|
||||
Tree::BranchManager( queue<function<void()>>& qTasks, condition_variable& cv, bool& done)
|
||||
{
|
||||
while (true) {
|
||||
function<void()> task ;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mapMutex);
|
||||
cv.wait(lock, [&tasks, &done]() { return !tasks.empty() || done; });
|
||||
std::unique_lock<std::mutex> lock( queueMutex) ;
|
||||
cv.wait(lock, [&qTasks, &done]() { return ! qTasks.empty() || done; }) ;
|
||||
|
||||
if (tasks.empty() && done) {
|
||||
return;
|
||||
if ( qTasks.empty() && done) {
|
||||
return ;
|
||||
}
|
||||
task = move(tasks.front());
|
||||
tasks.pop();
|
||||
task = std::move( qTasks.front()) ;
|
||||
qTasks.pop() ;
|
||||
|
||||
// notifico il thread principale che non ci sono più task
|
||||
if ( qTasks.empty() && ! done)
|
||||
cv.notify_all() ;
|
||||
}
|
||||
|
||||
task(); // Execute the task
|
||||
task() ; // Execute the task
|
||||
}
|
||||
}
|
||||
|
||||
@@ -673,85 +697,108 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
|
||||
{
|
||||
// lancio in parallelo vari thread in modo da calcolare separatamente i branch da ogni foglia attuale
|
||||
int nThreadMax = ( thread::hardware_concurrency()) / 2 ;
|
||||
int nStartingLeaves = m_vnLeaves.size() ;
|
||||
int nStartingLeaves = m_vnParents.size() ;
|
||||
condition_variable cv ;
|
||||
vector<unordered_map<int, Cell>> vBranches( nStartingLeaves) ;
|
||||
// ad ogni ramo, metto come cella di partenza una foglia
|
||||
for ( int i = 0 ; i < nStartingLeaves ; ++i) {
|
||||
Cell cLeaf = m_mTree.at( i) ;
|
||||
vBranches[i].insert( pair<int,Cell>( i, cLeaf)) ;
|
||||
INTVECTOR vFirstCells ;
|
||||
|
||||
// creo la coda dei task
|
||||
queue<function<void()>> qTasks ;
|
||||
bool done = false ;
|
||||
for (int i = 0; i < nStartingLeaves; ++i) {
|
||||
// ad ogni ramo, metto come cella di partenza una foglia
|
||||
Cell cLeaf = m_mTree.at( m_vnParents[i]) ;
|
||||
vBranches[i].insert( pair<int,Cell>( cLeaf.m_nId, cLeaf)) ;
|
||||
int nFirst = cLeaf.m_nId ;
|
||||
vFirstCells.push_back( nFirst) ;
|
||||
qTasks.emplace([this, i, &vBranches, dLinTol, dSideMin, dSideMax, nFirst]
|
||||
{Tree::BuildBranch( nFirst, vBranches[i], dLinTol, dSideMin, dSideMax) ;} ) ;
|
||||
}
|
||||
|
||||
// Create worker threads
|
||||
vector<thread> workers ;
|
||||
for (int i = 0 ; i < nThreadMax ; ++i)
|
||||
workers.emplace_back( &Tree::BranchManager, this, std::ref( qTasks), std::ref( cv),std::ref( done)) ;
|
||||
|
||||
queue<function<void()>> tasks;
|
||||
// Add tasks to the queue
|
||||
// dico ai thread di iniziare a lavorare
|
||||
cv.notify_all() ;
|
||||
|
||||
// Wait for all tasks to be processed
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(queueMutex);
|
||||
for (int i = 0; i < nStartingLeaves; ++i) {
|
||||
tasks.emplace([this]() {});
|
||||
}
|
||||
unique_lock<mutex> lock( queueMutex);
|
||||
cv.wait( lock, [&qTasks] { return qTasks.empty(); }) ;
|
||||
}
|
||||
|
||||
// Notify threads that tasks are available
|
||||
cv.notify_all();
|
||||
|
||||
// Mark work as done and notify all threads to exit
|
||||
// Wait for all tasks to be processed
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(queueMutex);
|
||||
done = true;
|
||||
}
|
||||
cv.notify_all();
|
||||
|
||||
// Wait for all threads to finish
|
||||
for (auto& t : threads) {
|
||||
t.join();
|
||||
unique_lock<mutex> lock( queueMutex) ;
|
||||
done = true ;
|
||||
}
|
||||
|
||||
cv.notify_all() ;
|
||||
|
||||
vector<vector<pair<int, Cell>>> vectorBranches( nStartingLeaves);
|
||||
// Join all threads
|
||||
for ( auto& t : workers)
|
||||
t.join() ;
|
||||
|
||||
// Step 1: Convert each map to a vector in parallel
|
||||
for_each(execution::par, vectorBranches.begin(), vectorBranches.end(),
|
||||
[&](auto& map) {
|
||||
size_t index = &map - &vectorBranches[0]; // Get the index of the current map
|
||||
vectorBranches[index].assign( make_move_iterator(map.begin()),
|
||||
make_move_iterator(map.end()));
|
||||
});
|
||||
// debug
|
||||
for ( int i = 0 ; i < nStartingLeaves ; ++i)
|
||||
m_mTree.erase( vFirstCells[i]) ;
|
||||
for ( int i = 0 ; i < nStartingLeaves ; ++i)
|
||||
m_mTree.insert( vBranches[i].begin(), vBranches[i].end()) ;
|
||||
|
||||
// Step 2: Precompute total size and allocate final vector
|
||||
size_t totalSize = accumulate(vectorBranches.begin(), vectorBranches.end(), 0,
|
||||
[](size_t sum, const vector<pair<int, Cell>>& v) {
|
||||
return sum + v.size();
|
||||
}) ;
|
||||
return true ;
|
||||
// debug
|
||||
|
||||
vector<pair<int, Cell>> mergedVector( totalSize) ;
|
||||
|
||||
// Step 3: Assign thread-specific ranges and move elements in parallel
|
||||
vector<size_t> offsets( nStartingLeaves + 1, 0) ;
|
||||
for (size_t i = 0; i < nStartingLeaves; ++i)
|
||||
offsets[i + 1] = offsets[i] + vectorBranches[i].size() ;
|
||||
//vector<vector<pair<int, Cell>>> vectorBranches( nStartingLeaves);
|
||||
|
||||
for_each( execution::par, vectorBranches.begin(), vectorBranches.end(),
|
||||
[&]( auto& vec) {
|
||||
size_t index = &vec - &vectorBranches[0];
|
||||
move( vec.begin(), vec.end(), mergedVector.begin() + offsets[index]) ;
|
||||
});
|
||||
//// Step 1: Convert each map to a vector in parallel
|
||||
//for_each(execution::par, vBranches.begin(), vBranches.end(),
|
||||
// [&](auto& map) {
|
||||
// size_t index = &map - &vBranches[0]; // Get the index of the current map
|
||||
// vectorBranches[index].assign( make_move_iterator(map.begin()),
|
||||
// make_move_iterator(map.end()));
|
||||
// });
|
||||
|
||||
// Step 4: Construct final unordered_map in one bulk step
|
||||
//unordered_map<int, Cell> finalMap( mergedVector.begin(), mergedVector.end()) ;
|
||||
Cell cRoot = m_mTree.at( -1) ;
|
||||
m_mTree.clear() ;
|
||||
m_mTree.insert( pair<int, Cell>(cRoot.m_nId, cRoot)) ;
|
||||
m_mTree.insert( mergedVector.begin(), mergedVector.end()) ;
|
||||
//// Step 2: Precompute total size and allocate final vector
|
||||
//size_t totalSize = accumulate(vectorBranches.begin(), vectorBranches.end(), 0,
|
||||
// [](size_t sum, const vector<pair<int, Cell>>& v) {
|
||||
// return sum + v.size();
|
||||
// }) ;
|
||||
|
||||
//vector<pair<int, Cell>> mergedVector( totalSize) ;
|
||||
|
||||
//// Step 3: Assign thread-specific ranges and move elements in parallel
|
||||
//vector<size_t> offsets( nStartingLeaves + 1, 0) ;
|
||||
//for (int i = 0; i < nStartingLeaves; ++i)
|
||||
// offsets[i + 1] = offsets[i] + vectorBranches[i].size() ;
|
||||
|
||||
//for_each( execution::par, vectorBranches.begin(), vectorBranches.end(),
|
||||
// [&]( auto& vec) {
|
||||
// size_t index = &vec - &vectorBranches[0];
|
||||
// move( vec.begin(), vec.end(), mergedVector.begin() + offsets[index]) ;
|
||||
// });
|
||||
|
||||
//// Step 4: Construct final unordered_map in one bulk step
|
||||
////unordered_map<int, Cell> finalMap( mergedVector.begin(), mergedVector.end()) ;
|
||||
//Cell cRoot = m_mTree.at( -1) ;
|
||||
//m_mTree.clear() ;
|
||||
//unordered_map<int,Cell> mContainer( mergedVector.begin(), mergedVector.end()) ;
|
||||
//m_mTree = std::move( mContainer) ;
|
||||
//m_mTree.insert( pair<int, Cell>( cRoot.m_nId, cRoot)) ;
|
||||
|
||||
//return true ;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool
|
||||
Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBranchRoot, unordered_map<int, Cell>& mBranch)
|
||||
Tree::BuildBranch( int nFirstCell, unordered_map<int, Cell>& mBranch, double dLinTol, double dSideMin, double dSideMax)
|
||||
{
|
||||
// suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri
|
||||
int nCToSplit = cBranchRoot->m_nId ;
|
||||
int nBranchRoot = cBranchRoot->m_nId ;
|
||||
Cell* pcToSplit = cBranchRoot ;
|
||||
int nCToSplit = nFirstCell ;
|
||||
Cell* pcToSplit = &mBranch.at(nFirstCell) ;
|
||||
int nBranchRoot = pcToSplit->m_nParent ;
|
||||
bool bIsPlanar = m_pSrfBz->IsPlanar() ;
|
||||
if ( ! m_bBilinear) {
|
||||
while ( pcToSplit->IsProcessed() == false) {
|
||||
@@ -1017,7 +1064,7 @@ Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBran
|
||||
|
||||
// procedo con lo split del Child1
|
||||
nCToSplit = pcToSplit->m_nChild1 ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
}
|
||||
else {
|
||||
// sono arrivato ad una cella Leaf, quindi salvo la cella
|
||||
@@ -1025,37 +1072,37 @@ Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBran
|
||||
pcToSplit->SetProcessed() ;
|
||||
// risalgo i parent finché non trovo il primo Child2 da processare
|
||||
nCToSplit = pcToSplit->m_nParent ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
if ( nCToSplit == nBranchRoot)
|
||||
return true ;
|
||||
if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed())
|
||||
if ( mBranch[pcToSplit->m_nChild1].IsProcessed() && mBranch[pcToSplit->m_nChild2].IsProcessed())
|
||||
pcToSplit->SetProcessed() ;
|
||||
while ( m_mTree[pcToSplit->m_nChild2].IsProcessed()) {
|
||||
while ( mBranch[pcToSplit->m_nChild2].IsProcessed()) {
|
||||
if ( pcToSplit->m_nParent != nBranchRoot) {
|
||||
nCToSplit = pcToSplit->m_nParent ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
}
|
||||
else
|
||||
return true ;
|
||||
if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed())
|
||||
if ( mBranch[pcToSplit->m_nChild1].IsProcessed() && mBranch[pcToSplit->m_nChild2].IsProcessed())
|
||||
pcToSplit->SetProcessed() ;
|
||||
if ( nCToSplit == -1 && m_mTree[pcToSplit->m_nChild2].IsProcessed())
|
||||
if ( nCToSplit == -1 && mBranch[pcToSplit->m_nChild2].IsProcessed())
|
||||
break ;
|
||||
}
|
||||
nCToSplit = pcToSplit->m_nChild2 ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
nCToSplit = pcToSplit->m_nChild1 ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
}
|
||||
}
|
||||
Balance() ; // da implementare quando dividerò ad un parametro a scelta e non a metà // probabilmente mi servirà salvare nella cella il livello di profondità
|
||||
}
|
||||
// bilineare
|
||||
else {
|
||||
while ( nCToSplit != -2 && pcToSplit->IsProcessed() == false) {
|
||||
while ( nCToSplit != nBranchRoot && pcToSplit->IsProcessed() == false) {
|
||||
if ( pcToSplit->IsLeaf()) {
|
||||
// vertici della cella
|
||||
Point3d ptP00, ptP10, ptP11, ptP01 ;
|
||||
@@ -1126,7 +1173,7 @@ Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBran
|
||||
|
||||
// procedo con lo split del Child1
|
||||
nCToSplit = pcToSplit->m_nChild1 ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
}
|
||||
else {
|
||||
// sono arrivato ad una cella Leaf, quindi salvo la cella
|
||||
@@ -1134,28 +1181,28 @@ Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBran
|
||||
pcToSplit->SetProcessed() ;
|
||||
// risalgo i parent finché non trovo il primo Child2 da processare
|
||||
nCToSplit = pcToSplit->m_nParent ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
if ( nCToSplit == -2)
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
if ( nCToSplit == nBranchRoot)
|
||||
return true ;
|
||||
if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed())
|
||||
if ( mBranch[pcToSplit->m_nChild1].IsProcessed() && mBranch[pcToSplit->m_nChild2].IsProcessed())
|
||||
pcToSplit->SetProcessed() ;
|
||||
while ( m_mTree[pcToSplit->m_nChild2].IsProcessed()) {
|
||||
if ( pcToSplit->m_nParent != -2) {
|
||||
while ( mBranch[pcToSplit->m_nChild2].IsProcessed()) {
|
||||
if ( pcToSplit->m_nParent != nBranchRoot) {
|
||||
nCToSplit = pcToSplit->m_nParent ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
}
|
||||
if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed())
|
||||
if ( mBranch[pcToSplit->m_nChild1].IsProcessed() && mBranch[pcToSplit->m_nChild2].IsProcessed())
|
||||
pcToSplit->SetProcessed() ;
|
||||
if ( nCToSplit == -1 && m_mTree[pcToSplit->m_nChild2].IsProcessed())
|
||||
if ( nCToSplit == -1 && mBranch[pcToSplit->m_nChild2].IsProcessed())
|
||||
break ;
|
||||
}
|
||||
nCToSplit = pcToSplit->m_nChild2 ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
}
|
||||
}
|
||||
else {
|
||||
nCToSplit = pcToSplit->m_nChild1 ;
|
||||
pcToSplit = &m_mTree[nCToSplit] ;
|
||||
pcToSplit = &mBranch[nCToSplit] ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1173,6 +1220,8 @@ Tree::Balance()
|
||||
|
||||
// al momento il problema viene bypassato in fase di generazione dei poligoni, considerando per ogni cella, oltre ai propri vertici
|
||||
// i vertici dei vicini che giacciono sui suoi lati
|
||||
// in realtà non è vero: perchè non basta avere più triangoli nella singola cella, può servire proprio spezzare la cella e avere più celle che rappresentano
|
||||
// facce diverse (quindi con pendenze diverse)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user