pcbnew: Remove OpenMP

OpenMP is not available for macos, so moving to a std::threads
implementation brings platforms into shared code.

This also reduces the OpenMP overhead when computing connectivity and
ratsnests.

Fixes: lp:1780130
* https://bugs.launchpad.net/kicad/+bug/1780130
This commit is contained in:
Seth Hillbrand 2018-09-19 19:10:12 -07:00
parent 3e45483798
commit c0f067bf90
3 changed files with 67 additions and 48 deletions

View File

@ -33,9 +33,6 @@
#include <profile.h>
#endif
#ifdef USE_OPENMP
#include <omp.h>
#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<int> nextItem( 0 );
std::atomic<size_t> 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<size_t>(
std::max<size_t>( 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
}

View File

@ -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 <profile.h>
#endif
#include <thread>
#include <connectivity_data.h>
#include <connectivity_algo.h>
#include <ratsnest_data.h>
#ifdef USE_OPENMP
#include <omp.h>
#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<BOARD_ITEM*>& 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<size_t> nextNet( 1 );
std::atomic<size_t> 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<size_t>(
std::max<size_t>( 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();

View File

@ -32,6 +32,7 @@
#include <class_zone.h>
#include <profile.h>
#include <thread>
#include <unordered_set>
#include <utility>