diff --git a/pcbnew/connectivity_algo.cpp b/pcbnew/connectivity_algo.cpp index 17756c4224..d11ea0bb7d 100644 --- a/pcbnew/connectivity_algo.cpp +++ b/pcbnew/connectivity_algo.cpp @@ -33,9 +33,6 @@ #include #endif -#ifdef USE_OPENMP -#include -#endif /* USE_OPENMP */ using namespace std::placeholders; @@ -324,7 +321,6 @@ void CN_CONNECTIVITY_ALGO::searchConnections() #ifdef PROFILE garbage_collection.Show(); - PROF_COUNTER search_cnt( "search-connections" ); PROF_COUNTER search_basic( "search-basic" ); #endif @@ -333,49 +329,63 @@ void CN_CONNECTIVITY_ALGO::searchConnections() m_progressReporter->SetMaxProgress( m_itemList.IsDirty() ? m_itemList.Size() : 0 ); } -#ifdef USE_OPENMP - #pragma omp parallel num_threads( std::max( omp_get_num_procs(), 2 ) ) + if( m_itemList.IsDirty() ) { - if( omp_get_thread_num() == 0 && m_progressReporter ) - m_progressReporter->KeepRefreshing( true ); -#endif + std::atomic nextItem( 0 ); + std::atomic threadsFinished( 0 ); + size_t numDirty = std::count_if( m_itemList.begin(), m_itemList.end(), [] ( CN_ITEM* aItem ) + { return aItem->Dirty(); } ); - if( m_itemList.IsDirty() ) + size_t parallelThreadCount = std::min( + std::max( std::thread::hardware_concurrency(), 2 ), + numDirty ); + + for( size_t ii = 0; ii < parallelThreadCount; ++ii ) { -#ifdef USE_OPENMP - #pragma omp parallel for -#endif - for( int i = 0; i < m_itemList.Size(); i++ ) + std::thread t = std::thread( [&nextItem, &threadsFinished, this]() { - auto item = m_itemList[i]; - if( item->Dirty() ) + for( int i = nextItem.fetch_add( 1 ); + i < m_itemList.Size(); + i = nextItem.fetch_add( 1 ) ) { - CN_VISITOR visitor( item, &m_listLock ); - m_itemList.FindNearby( item, visitor ); + auto item = m_itemList[i]; + if( item->Dirty() ) + { + CN_VISITOR visitor( item, &m_listLock ); + m_itemList.FindNearby( item, visitor ); + } + + if( m_progressReporter ) + m_progressReporter->AdvanceProgress(); } - if( m_progressReporter ) - m_progressReporter->AdvanceProgress(); - } + threadsFinished++; + } ); + + t.detach(); } + // Finalize the connectivity threads + while( threadsFinished < parallelThreadCount ) + { + if( m_progressReporter ) + m_progressReporter->KeepRefreshing(); + + // This routine is called every click while routing so keep the sleep time minimal + std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) ); + } + } + #ifdef PROFILE search_basic.Show(); #endif -#ifdef USE_OPENMP - } -#endif - m_itemList.ClearDirtyFlags(); #ifdef CONNECTIVITY_DEBUG printf("Search end\n"); #endif -#ifdef PROFILE - search_cnt.Show(); -#endif } diff --git a/pcbnew/connectivity_data.cpp b/pcbnew/connectivity_data.cpp index fb5ca4b205..ba8719ea89 100644 --- a/pcbnew/connectivity_data.cpp +++ b/pcbnew/connectivity_data.cpp @@ -21,18 +21,17 @@ * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + #ifdef PROFILE #include #endif +#include + #include #include #include -#ifdef USE_OPENMP -#include -#endif /* USE_OPENMP */ - CONNECTIVITY_DATA::CONNECTIVITY_DATA() { m_connAlgo.reset( new CN_CONNECTIVITY_ALGO ); @@ -87,31 +86,40 @@ void CONNECTIVITY_DATA::Build( const std::vector& aItems ) void CONNECTIVITY_DATA::updateRatsnest() { - int lastNet = m_connAlgo->NetCount(); - #ifdef PROFILE PROF_COUNTER rnUpdate( "update-ratsnest" ); #endif - int i; + size_t numDirty = std::count_if( m_nets.begin() + 1, m_nets.end(), [] ( RN_NET* aNet ) + { return aNet->IsDirty(); } ); - #ifdef USE_OPENMP - #pragma omp parallel shared(lastNet) private(i) - { - #pragma omp for schedule(guided, 1) - #else /* USE_OPENMP */ - { - #endif + std::atomic nextNet( 1 ); + std::atomic threadsFinished( 0 ); - // Start with net number 1, as 0 stands for not connected - for( i = 1; i < lastNet; ++i ) + // We don't want to spin up a new thread for fewer than two nets (overhead costs) + size_t parallelThreadCount = std::min( + std::max( std::thread::hardware_concurrency(), 2 ), + numDirty / 2 ); + + for( size_t ii = 0; ii < parallelThreadCount; ++ii ) + { + std::thread t = std::thread( [&nextNet, &threadsFinished, this]() { - if( m_nets[i]->IsDirty() ) + for( size_t i = nextNet.fetch_add( 1 ); i < m_nets.size(); i = nextNet.fetch_add( 1 ) ) { - m_nets[i]->Update(); + if( m_nets[i]->IsDirty() ) + m_nets[i]->Update(); } - } - } /* end of parallel section */ + + threadsFinished++; + } ); + + t.detach(); + } + + // Finalize the ratsnest threads + while( threadsFinished < parallelThreadCount ) + std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) ); #ifdef PROFILE rnUpdate.Show(); diff --git a/qa/polygon_triangulation/test_polygon_triangulation.cpp b/qa/polygon_triangulation/test_polygon_triangulation.cpp index 432a323a1b..2eae35c24d 100644 --- a/qa/polygon_triangulation/test_polygon_triangulation.cpp +++ b/qa/polygon_triangulation/test_polygon_triangulation.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include