pcbnew: Connectivity threads update
This is a melded cherry-pick of the following commits from 5.159fb6d8851
ed1c8eee9e
4a730e6c54
This implements the std::async connecitivty and locking for the 5.0 branch
This commit is contained in:
parent
0b5ca1a883
commit
a77caa6baa
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <future>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#ifdef PROFILE
|
#ifdef PROFILE
|
||||||
#include <profile.h>
|
#include <profile.h>
|
||||||
|
@ -325,58 +327,63 @@ void CN_CONNECTIVITY_ALGO::searchConnections()
|
||||||
PROF_COUNTER search_basic( "search-basic" );
|
PROF_COUNTER search_basic( "search-basic" );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t numDirty = std::count_if( m_itemList.begin(), m_itemList.end(), [] ( CN_ITEM* aItem )
|
std::vector<CN_ITEM*> dirtyItems;
|
||||||
{ return aItem->Dirty(); } );
|
std::copy_if( m_itemList.begin(), m_itemList.end(), std::back_inserter( dirtyItems ),
|
||||||
|
[] ( CN_ITEM* aItem ) { return aItem->Dirty(); } );
|
||||||
|
|
||||||
if( m_progressReporter )
|
if( m_progressReporter )
|
||||||
{
|
{
|
||||||
m_progressReporter->SetMaxProgress( numDirty );
|
m_progressReporter->SetMaxProgress( dirtyItems.size() );
|
||||||
m_progressReporter->KeepRefreshing();
|
m_progressReporter->KeepRefreshing();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_itemList.IsDirty() )
|
if( m_itemList.IsDirty() )
|
||||||
{
|
{
|
||||||
std::atomic<int> nextItem( 0 );
|
size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
|
||||||
std::atomic<size_t> threadsFinished( 0 );
|
( dirtyItems.size() + 7 ) / 8 );
|
||||||
|
|
||||||
size_t parallelThreadCount = std::min<size_t>(
|
std::atomic<size_t> nextItem( 0 );
|
||||||
std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
|
std::vector<std::future<size_t>> returns( parallelThreadCount );
|
||||||
numDirty );
|
|
||||||
|
|
||||||
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
auto conn_lambda = [&nextItem, &dirtyItems]
|
||||||
|
( CN_LIST* aItemList, PROGRESS_REPORTER* aReporter) -> size_t
|
||||||
{
|
{
|
||||||
std::thread t = std::thread( [&nextItem, &threadsFinished, this]()
|
for( size_t i = nextItem++; i < dirtyItems.size(); i = nextItem++ )
|
||||||
{
|
{
|
||||||
for( int i = nextItem.fetch_add( 1 );
|
CN_VISITOR visitor( dirtyItems[i] );
|
||||||
i < m_itemList.Size();
|
aItemList->FindNearby( dirtyItems[i], visitor );
|
||||||
i = nextItem.fetch_add( 1 ) )
|
|
||||||
{
|
|
||||||
auto item = m_itemList[i];
|
|
||||||
if( item->Dirty() )
|
|
||||||
{
|
|
||||||
CN_VISITOR visitor( item, &m_listLock );
|
|
||||||
m_itemList.FindNearby( item, visitor );
|
|
||||||
|
|
||||||
if( m_progressReporter )
|
if( aReporter )
|
||||||
m_progressReporter->AdvanceProgress();
|
aReporter->AdvanceProgress();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
threadsFinished++;
|
return 1;
|
||||||
} );
|
};
|
||||||
|
|
||||||
t.detach();
|
if( parallelThreadCount <= 1 )
|
||||||
}
|
conn_lambda( &m_itemList, m_progressReporter );
|
||||||
|
else
|
||||||
// Finalize the connectivity threads
|
|
||||||
while( threadsFinished < parallelThreadCount )
|
|
||||||
{
|
{
|
||||||
if( m_progressReporter )
|
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||||
m_progressReporter->KeepRefreshing();
|
returns[ii] = std::async( std::launch::async, conn_lambda,
|
||||||
|
&m_itemList, m_progressReporter );
|
||||||
|
|
||||||
// This routine is called every click while routing so keep the sleep time minimal
|
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
|
||||||
std::this_thread::sleep_for( std::chrono::milliseconds( 1 ) );
|
{
|
||||||
|
// Here we balance returns with a 100ms timeout to allow UI updating
|
||||||
|
std::future_status status;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if( m_progressReporter )
|
||||||
|
m_progressReporter->KeepRefreshing();
|
||||||
|
|
||||||
|
status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
|
||||||
|
} while( status != std::future_status::ready );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( m_progressReporter )
|
||||||
|
m_progressReporter->KeepRefreshing();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PROFILE
|
#ifdef PROFILE
|
||||||
|
@ -766,8 +773,8 @@ void CN_VISITOR::checkZoneItemConnection( CN_ZONE* aZone, CN_ITEM* aItem )
|
||||||
( aItem->Parent()->Type() == PCB_TRACE_T &&
|
( aItem->Parent()->Type() == PCB_TRACE_T &&
|
||||||
zoneItem->ContainsPoint( aItem->GetAnchor( 1 ) ) ) )
|
zoneItem->ContainsPoint( aItem->GetAnchor( 1 ) ) ) )
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock( *m_listLock );
|
zoneItem->Connect( aItem );
|
||||||
CN_ITEM::Connect( zoneItem, aItem );
|
aItem->Connect( zoneItem );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,8 +798,8 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE* aZoneA, CN_ZONE* aZoneB )
|
||||||
{
|
{
|
||||||
if( aZoneB->ContainsPoint( outline.CPoint( i ) ) )
|
if( aZoneB->ContainsPoint( outline.CPoint( i ) ) )
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock( *m_listLock );
|
aZoneA->Connect( aZoneB );
|
||||||
CN_ITEM::Connect( aZoneA, aZoneB );
|
aZoneB->Connect( aZoneA );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -803,8 +810,8 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE* aZoneA, CN_ZONE* aZoneB )
|
||||||
{
|
{
|
||||||
if( aZoneA->ContainsPoint( outline2.CPoint( i ) ) )
|
if( aZoneA->ContainsPoint( outline2.CPoint( i ) ) )
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock( *m_listLock );
|
aZoneA->Connect( aZoneB );
|
||||||
CN_ITEM::Connect( aZoneA, aZoneB );
|
aZoneB->Connect( aZoneA );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -862,8 +869,8 @@ bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
|
||||||
( parentA->Type() == PCB_TRACE_T && parentB->HitTest( ptA2 ) ) ||
|
( parentA->Type() == PCB_TRACE_T && parentB->HitTest( ptA2 ) ) ||
|
||||||
( parentB->Type() == PCB_TRACE_T && parentA->HitTest( ptB2 ) ) )
|
( parentB->Type() == PCB_TRACE_T && parentA->HitTest( ptB2 ) ) )
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock( *m_listLock );
|
m_item->Connect( aCandidate );
|
||||||
CN_ITEM::Connect( m_item, aCandidate );
|
aCandidate->Connect( m_item );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -284,6 +284,9 @@ private:
|
||||||
///> valid flag, used to identify garbage items (we use lazy removal)
|
///> valid flag, used to identify garbage items (we use lazy removal)
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
|
|
||||||
|
///> mutex protecting this item's connected_items set to allow parallel connection threads
|
||||||
|
std::mutex m_listLock;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
///> dirty flag, used to identify recently added item not yet scanned into the connectivity search
|
///> dirty flag, used to identify recently added item not yet scanned into the connectivity search
|
||||||
bool m_dirty;
|
bool m_dirty;
|
||||||
|
@ -436,10 +439,10 @@ public:
|
||||||
return ( m_connected.find( aItem ) != m_connected.end() );
|
return ( m_connected.find( aItem ) != m_connected.end() );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Connect( CN_ITEM* a, CN_ITEM* b )
|
void Connect( CN_ITEM* b )
|
||||||
{
|
{
|
||||||
a->m_connected.insert( b );
|
std::lock_guard<std::mutex> lock( m_listLock );
|
||||||
b->m_connected.insert( a );
|
m_connected.insert( b );
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoveInvalidRefs();
|
void RemoveInvalidRefs();
|
||||||
|
@ -835,9 +838,8 @@ class CN_VISITOR {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
CN_VISITOR( CN_ITEM* aItem, std::mutex* aListLock ) :
|
CN_VISITOR( CN_ITEM* aItem ) :
|
||||||
m_item( aItem ),
|
m_item( aItem )
|
||||||
m_listLock( aListLock )
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool operator()( CN_ITEM* aCandidate );
|
bool operator()( CN_ITEM* aCandidate );
|
||||||
|
@ -850,10 +852,6 @@ protected:
|
||||||
|
|
||||||
///> the item we are looking for connections to
|
///> the item we are looking for connections to
|
||||||
CN_ITEM* m_item;
|
CN_ITEM* m_item;
|
||||||
|
|
||||||
///> the mutex protecting our connection list
|
|
||||||
std::mutex* m_listLock;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue