- imbastimento del multiThread per il calcolo del tree.

This commit is contained in:
Daniele Bariletti
2025-03-26 17:51:49 +01:00
parent 851c053f7c
commit 3b9be09b4b
2 changed files with 154 additions and 43 deletions
+149 -40
View File
@@ -29,9 +29,18 @@
#include "/EgtDev/Include/EGkSfrCreate.h"
#include <algorithm>
#include <numeric>
#include <thread>
#include <atomic>
#include <execution>
#include <queue>
#include <condition_variable>
#include <functional>
#include <future>
using namespace std ;
atomic<int> CellCounter( 0) ;
//----------------------------------------------------------------------------
Tree::Tree( void)
: m_pSrfBz( nullptr), m_bTrimmed( false), m_bBilinear( false), m_bMulti( false), m_bClosedU( false), m_bClosedV( false), m_vbPole( { false, false, false, false}),
@@ -255,7 +264,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
for ( int i = 1 ; i < nSplit ; ++i) {
m_mTree[nId].SetSplitDirVert( true) ;
double dSplit = bSplitInHalf ? i * SBZ_TREG_COEFF / 2 : i * SBZ_TREG_COEFF ;
if ( Split( nId, dSplit)) {
if ( Split( nId, dSplit, m_mTree)) {
//++ nId ;
//++ nId ;
nId = m_mTree[nId].m_nChild2 ;
@@ -274,7 +283,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
for ( int j = nSplit ; j > 0 ; --j) {
m_mTree[nId].SetSplitDirVert( false) ;
double dSplit = bSplitInHalf ? j * SBZ_TREG_COEFF / 2 : j * SBZ_TREG_COEFF ;
if ( Split( nId, dSplit))
if ( Split( nId, dSplit, m_mTree))
nId = m_mTree[nId].m_nChild2 ;
}
}
@@ -295,7 +304,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
m_bClosedV = true ;
}
m_mTree[-1].SetSplitDirVert( false) ;
Split( -1) ;
Split( -1, m_mTree) ;
}
////////
@@ -316,9 +325,9 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
m_vbPole[3] = bPole1 ;
if ( bPole0 && bPole1 && int( m_mTree.size() == 3)) {
m_mTree[0].SetSplitDirVert( true) ;
Split( 0) ;
Split( 0, m_mTree) ;
m_mTree[1].SetSplitDirVert( true) ;
Split( 1) ;
Split( 1, m_mTree) ;
}
}
// nella condizione di questo if non controllo eventuali divisioni preliminari, perché ne tengo conto dopo
@@ -332,7 +341,7 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
m_bClosedU = true ;
}
m_mTree[-1].SetSplitDirVert( true) ;
Split( -1) ;
Split( -1, m_mTree) ;
}
////////
@@ -352,9 +361,9 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
m_vbPole[2] = bPole0 ;
if ( bPole0 && bPole1 && int( m_mTree.size()) == 3) {
m_mTree[0].SetSplitDirVert( false) ;
Split( 0) ;
Split( 0, m_mTree) ;
m_mTree[1].SetSplitDirVert( false) ;
Split( 1) ;
Split( 1, m_mTree) ;
}
// se ho fatto solo 1 split orizzontale e ho due celle foglie nId = 0 e nId = 1
if ( int( m_mTree.size() == 3) && ! m_mTree.at(-1).IsSplitVert()) {
@@ -363,9 +372,9 @@ Tree::SetSurf( const SurfBezier* pSrfBz, bool bSplitPatches, const Point3d& ptMi
m_mTree[1].m_nLeft = -1 ;
m_mTree[1].m_nRight = -1 ;
m_mTree[0].SetSplitDirVert( true) ;
Split( 0) ;
Split( 0, m_mTree) ;
m_mTree[1].SetSplitDirVert( true) ;
Split( 1) ;
Split( 1, m_mTree) ;
}
}
}
@@ -489,9 +498,9 @@ Tree::GetIndependentTrees( BIPNTVECTOR& vTrees)
//----------------------------------------------------------------------------
bool
Tree::Split( int nId, double dSplitValue)
Tree::Split( int nId, double dSplitValue, unordered_map<int, Cell>& mBranch)
{
Cell& cToSplit = m_mTree.at(nId) ;
Cell& cToSplit = mBranch.at(nId) ;
// controllo che lo split non venga fatto sul lato della cella
if ( ( cToSplit.IsSplitVert() && dSplitValue > cToSplit.GetBottomLeft().x + EPS_SMALL &&
dSplitValue < cToSplit.GetTopRight().x - EPS_SMALL) ||
@@ -502,11 +511,10 @@ Tree::Split( int nId, double dSplitValue)
Cell cChild1, cChild2 ;
cChild1.m_nDepth = cToSplit.m_nDepth + 1 ;
cChild2.m_nDepth = cToSplit.m_nDepth + 1 ;
int nNodes = (int) m_mTree.size() ;
cChild1.m_nId = nNodes - 1 ;
cToSplit.m_nChild1 = nNodes - 1 ;
cChild2.m_nId = nNodes ;
cToSplit.m_nChild2 = nNodes ;
cChild1.m_nId = CellCounter.fetch_add( 1) ;
cToSplit.m_nChild1 = cChild1.m_nId ;
cChild2.m_nId = CellCounter.fetch_add( 1) ;
cToSplit.m_nChild2 = cChild2.m_nId ;
Point3d ptVert1, ptVert2 ;
if ( ! cToSplit.IsSplitVert()) {
// la cella figlio 1 è quella sopra
@@ -553,8 +561,8 @@ Tree::Split( int nId, double dSplitValue)
cChild1.SetParent( nId) ;
cChild2.SetParent( nId) ;
// inserisco nell'albero
m_mTree.insert( pair<int, Cell>( nNodes - 1, cChild1)) ;
m_mTree.insert( pair<int, Cell>( nNodes, cChild2)) ;
mBranch.insert( pair<int, Cell>( cChild1.m_nId, cChild1)) ;
mBranch.insert( pair<int, Cell>( cChild2.m_nId, cChild2)) ;
return true ;
}
return false ;
@@ -562,15 +570,15 @@ Tree::Split( int nId, double dSplitValue)
//----------------------------------------------------------------------------
bool
Tree::Split( int nId)
Tree::Split( int nId, unordered_map<int, Cell>& mBranch)
{
double dValue ;
Cell& cCell = m_mTree.at(nId) ;
Cell& cCell = mBranch.at(nId) ;
if ( cCell.IsSplitVert())
dValue = ( cCell.GetBottomLeft().x + cCell.GetTopRight().x) / 2 ;
else
dValue = ( cCell.GetBottomLeft().y + cCell.GetTopRight().y) / 2 ;
return Split( nId, dValue) ;
return Split( nId, dValue, mBranch) ;
}
//----------------------------------------------------------------------------
@@ -583,25 +591,25 @@ Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax)
//celle 0,1
m_mTree[-1].SetSplitDirVert( true) ;
Split( -1) ;
Split( -1, m_mTree) ;
//celle 2,3
m_mTree[0].SetSplitDirVert( false) ;
Split( 0) ;
Split( 0, m_mTree) ;
//celle 4,5
m_mTree[2].SetSplitDirVert( false) ;
Split( 2) ;
Split( 2, m_mTree) ;
//celle 6,7
m_mTree[3].SetSplitDirVert( true) ;
Split( 3) ;
Split( 3, m_mTree) ;
//celle 8,9
m_mTree[1].SetSplitDirVert( false) ;
Split( 1) ;
Split( 1, m_mTree) ;
//celle 10,11
m_mTree[8].SetSplitDirVert( true) ;
Split( 8) ;
Split( 8, m_mTree) ;
//celle 12,13
m_mTree[9].SetSplitDirVert( false) ;
Split( 9) ;
Split( 9, m_mTree) ;
m_vnLeaves.push_back( 4) ;
//m_vnLeaves.push_back( 5) ;
m_vnLeaves.push_back( 6) ;
@@ -614,22 +622,22 @@ Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax)
// aggiunta di split
//celle 14,15
m_mTree[5].SetSplitDirVert( true) ;
Split( 5) ;
Split( 5, m_mTree) ;
m_vnLeaves.push_back( 14) ;
m_vnLeaves.push_back( 15) ;
//celle 16,17
m_mTree[7].SetSplitDirVert( false) ;
Split( 7) ;
Split( 7, m_mTree) ;
m_vnLeaves.push_back( 16) ;
m_vnLeaves.push_back( 17) ;
//celle 18,19
m_mTree[12].SetSplitDirVert( true) ;
Split( 12) ;
Split( 12, m_mTree) ;
m_vnLeaves.push_back( 18) ;
m_vnLeaves.push_back( 19) ;
//celle 20,21
m_mTree[10].SetSplitDirVert( false) ;
Split( 10) ;
Split( 10, m_mTree) ;
m_vnLeaves.push_back( 20) ;
m_vnLeaves.push_back( 21) ;
// riempio anche la lista dei parent delle celle
@@ -638,16 +646,115 @@ Tree::BuildTree_test( double dLinTol, double dSideMin, double dSideMax)
return true ;
}
//----------------------------------------------------------------------------
void
Tree::BranchManager( queue<function<void()>>& tasks, 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; });
if (tasks.empty() && done) {
return;
}
task = move(tasks.front());
tasks.pop();
}
task(); // Execute the task
}
}
//----------------------------------------------------------------------------
bool
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() ;
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)) ;
}
queue<function<void()>> tasks;
// Add tasks to the queue
{
std::lock_guard<std::mutex> lock(queueMutex);
for (int i = 0; i < nStartingLeaves; ++i) {
tasks.emplace([this]() {});
}
}
// Notify threads that tasks are available
cv.notify_all();
// Mark work as done and notify all threads to exit
{
std::lock_guard<std::mutex> lock(queueMutex);
done = true;
}
cv.notify_all();
// Wait for all threads to finish
for (auto& t : threads) {
t.join();
}
vector<vector<pair<int, Cell>>> vectorBranches( nStartingLeaves);
// 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()));
});
// 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 (size_t 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() ;
m_mTree.insert( pair<int, Cell>(cRoot.m_nId, cRoot)) ;
m_mTree.insert( mergedVector.begin(), mergedVector.end()) ;
}
//----------------------------------------------------------------------------
bool
Tree::BuildBranch( double dLinTol, double dSideMin, double dSideMax, Cell* cBranchRoot, unordered_map<int, Cell>& mBranch)
{
// suddivido lo spazio parametrico con divisioni a metà su uno dei due parametri
int nCToSplit = -1 ;
Cell* pcToSplit = &m_mTree[nCToSplit] ;
int nCToSplit = cBranchRoot->m_nId ;
int nBranchRoot = cBranchRoot->m_nId ;
Cell* pcToSplit = cBranchRoot ;
bool bIsPlanar = m_pSrfBz->IsPlanar() ;
if ( ! m_bBilinear) {
while ( nCToSplit != -2 && pcToSplit->IsProcessed() == false) {
while ( pcToSplit->IsProcessed() == false) {
// controllo che la cella non sia già stata preliminarmente splittata
if ( pcToSplit->IsLeaf()) {
// calcolo in quale direzione ho più curvatura
@@ -906,7 +1013,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
if ( bSplit || dSideMaxVal > dSideMax) {
pcToSplit->SetSplitDirVert( bVert) ;
// effettuo lo split
Split( nCToSplit) ;
Split( nCToSplit, mBranch) ;
// procedo con lo split del Child1
nCToSplit = pcToSplit->m_nChild1 ;
@@ -919,15 +1026,17 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
// risalgo i parent finché non trovo il primo Child2 da processare
nCToSplit = pcToSplit->m_nParent ;
pcToSplit = &m_mTree[nCToSplit] ;
if ( nCToSplit == -2)
if ( nCToSplit == nBranchRoot)
return true ;
if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed())
pcToSplit->SetProcessed() ;
while ( m_mTree[pcToSplit->m_nChild2].IsProcessed()) {
if ( pcToSplit->m_nParent != -2) {
if ( pcToSplit->m_nParent != nBranchRoot) {
nCToSplit = pcToSplit->m_nParent ;
pcToSplit = &m_mTree[nCToSplit] ;
}
else
return true ;
if ( m_mTree[pcToSplit->m_nChild1].IsProcessed() && m_mTree[pcToSplit->m_nChild2].IsProcessed())
pcToSplit->SetProcessed() ;
if ( nCToSplit == -1 && m_mTree[pcToSplit->m_nChild2].IsProcessed())
@@ -1013,7 +1122,7 @@ Tree::BuildTree( double dLinTol, double dSideMin, double dSideMax)
if ( dSideMinVal / 2 >= dSideMin && dSideMaxVal < dSideMax && dErr > dLinTol) {
pcToSplit->SetSplitDirVert( bVert) ;
// effettuo lo split
Split( nCToSplit) ;
Split( nCToSplit, mBranch) ;
// procedo con lo split del Child1
nCToSplit = pcToSplit->m_nChild1 ;