ratsnest: Move ratsnest connectivity to async

This a partial pick of 59fb6d8851 but
revised for the 5.0.x branch.
This commit is contained in:
Seth Hillbrand 2018-11-04 16:42:21 -07:00
parent 839ade2c05
commit 0b5ca1a883
1 changed files with 31 additions and 22 deletions

View File

@ -27,6 +27,8 @@
#endif #endif
#include <thread> #include <thread>
#include <algorithm>
#include <future>
#include <connectivity_data.h> #include <connectivity_data.h>
#include <connectivity_algo.h> #include <connectivity_algo.h>
@ -90,37 +92,44 @@ void CONNECTIVITY_DATA::updateRatsnest()
PROF_COUNTER rnUpdate( "update-ratsnest" ); PROF_COUNTER rnUpdate( "update-ratsnest" );
#endif #endif
size_t numDirty = std::count_if( m_nets.begin() + 1, m_nets.end(), [] ( RN_NET* aNet ) std::vector<RN_NET*> dirty_nets;
{ return aNet->IsDirty(); } );
// Start with net 1 as net 0 is reserved for not-connected // Start with net 1 as net 0 is reserved for not-connected
std::atomic<size_t> nextNet( 1 ); // Nets without nodes are also ignored
std::atomic<size_t> threadsFinished( 0 ); std::copy_if( m_nets.begin() + 1, m_nets.end(), std::back_inserter( dirty_nets ),
[] ( RN_NET* aNet ) { return aNet->IsDirty() && aNet->GetNodeCount() > 0; } );
// We don't want to spin up a new thread for fewer than two nets (overhead costs) // We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
size_t parallelThreadCount = std::min<size_t>( size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
std::max<size_t>( std::thread::hardware_concurrency(), 2 ), ( dirty_nets.size() + 7 ) / 8 );
( numDirty + 1 ) / 2 );
std::atomic<size_t> nextNet( 0 );
std::vector<std::future<size_t>> returns( parallelThreadCount );
auto update_lambda = [&nextNet, &dirty_nets]() -> size_t
{
size_t processed = 0;
for( size_t i = nextNet++; i < dirty_nets.size(); i = nextNet++ )
{
dirty_nets[i]->Update();
processed++;
}
return processed;
};
if( parallelThreadCount == 1 )
update_lambda();
else
{
for( size_t ii = 0; ii < parallelThreadCount; ++ii ) for( size_t ii = 0; ii < parallelThreadCount; ++ii )
{ returns[ii] = std::async( std::launch::async, update_lambda );
std::thread t = std::thread( [&nextNet, &threadsFinished, this]()
{
for( size_t i = nextNet.fetch_add( 1 ); i < m_nets.size(); i = nextNet.fetch_add( 1 ) )
{
if( m_nets[i]->IsDirty() )
m_nets[i]->Update();
}
threadsFinished++;
} );
t.detach();
}
// Finalize the ratsnest threads // Finalize the ratsnest threads
while( threadsFinished < parallelThreadCount ) for( size_t ii = 0; ii < parallelThreadCount; ++ii )
std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) ); returns[ii].wait();
}
#ifdef PROFILE #ifdef PROFILE
rnUpdate.Show(); rnUpdate.Show();