pcbnew: Shift zone filler to std::async

This commit is contained in:
Seth Hillbrand 2018-11-05 21:22:16 -07:00
parent a24bd9baa1
commit 1f25fcd3d6
1 changed files with 71 additions and 118 deletions

View File

@ -26,6 +26,8 @@
#include <cstdint> #include <cstdint>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <algorithm>
#include <future>
#include <class_board.h> #include <class_board.h>
#include <class_zone.h> #include <class_zone.h>
@ -109,47 +111,66 @@ bool ZONE_FILLER::Fill( std::vector<ZONE_CONTAINER*> aZones, bool aCheck )
m_progressReporter->SetMaxProgress( toFill.size() ); m_progressReporter->SetMaxProgress( toFill.size() );
} }
// Remove deprecaded segment zones (only found in very old boards)
m_board->m_SegZoneDeprecated.DeleteAll();
std::atomic<size_t> nextItem( 0 ); std::atomic<size_t> nextItem( 0 );
std::atomic<size_t> threadsFinished( 0 ); size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(), toFill.size() );
size_t parallelThreadCount = std::min<size_t>( std::vector<std::future<size_t>> returns( parallelThreadCount );
std::max<size_t>( std::thread::hardware_concurrency(), 2 ),
toFill.size() );
for( size_t ii = 0; ii < parallelThreadCount; ++ii ) auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
{ {
std::thread t = std::thread( [ & ]() size_t num = 0;
for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
{ {
for( size_t i = nextItem.fetch_add( 1 ); ZONE_CONTAINER* zone = toFill[i].m_zone;
i < toFill.size();
i = nextItem.fetch_add( 1 ) ) if( zone->GetFillMode() == ZFM_SEGMENTS )
{
ZONE_SEGMENT_FILL segFill;
fillZoneWithSegments( zone, zone->GetFilledPolysList(), segFill );
zone->SetFillSegments( segFill );
}
else
{ {
SHAPE_POLY_SET rawPolys, finalPolys; SHAPE_POLY_SET rawPolys, finalPolys;
ZONE_CONTAINER* zone = toFill[i].m_zone;
fillSingleZone( zone, rawPolys, finalPolys ); fillSingleZone( zone, rawPolys, finalPolys );
zone->SetRawPolysList( rawPolys ); zone->SetRawPolysList( rawPolys );
zone->SetFilledPolysList( finalPolys ); zone->SetFilledPolysList( finalPolys );
zone->SetIsFilled( true );
if( m_progressReporter )
m_progressReporter->AdvanceProgress();
} }
threadsFinished++; zone->SetIsFilled( true );
} );
t.detach(); if( m_progressReporter )
} m_progressReporter->AdvanceProgress();
num++;
}
// Finalize the triangulation threads return num;
while( threadsFinished < parallelThreadCount ) };
if( parallelThreadCount <= 1 )
fill_lambda( m_progressReporter );
else
{ {
if( m_progressReporter ) for( size_t ii = 0; ii < parallelThreadCount; ++ii )
m_progressReporter->KeepRefreshing(); returns[ii] = std::async( std::launch::async, fill_lambda, m_progressReporter );
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); for( size_t ii = 0; ii < parallelThreadCount; ++ii )
{
// 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 );
}
} }
// Now update the connectivity to check for copper islands // Now update the connectivity to check for copper islands
@ -164,13 +185,6 @@ bool ZONE_FILLER::Fill( std::vector<ZONE_CONTAINER*> aZones, bool aCheck )
connectivity->FindIsolatedCopperIslands( toFill ); connectivity->FindIsolatedCopperIslands( toFill );
// Now remove insulated copper islands // Now remove insulated copper islands
if( m_progressReporter )
{
m_progressReporter->AdvancePhase();
m_progressReporter->SetMaxProgress( toFill.size() );
m_progressReporter->KeepRefreshing();
}
bool outOfDate = false; bool outOfDate = false;
for( auto& zone : toFill ) for( auto& zone : toFill )
@ -187,12 +201,6 @@ bool ZONE_FILLER::Fill( std::vector<ZONE_CONTAINER*> aZones, bool aCheck )
if( aCheck && zone.m_lastPolys.GetHash() != poly.GetHash() ) if( aCheck && zone.m_lastPolys.GetHash() != poly.GetHash() )
outOfDate = true; outOfDate = true;
if( m_progressReporter )
{
m_progressReporter->AdvanceProgress();
m_progressReporter->KeepRefreshing();
}
} }
if( aCheck ) if( aCheck )
@ -235,99 +243,44 @@ bool ZONE_FILLER::Fill( std::vector<ZONE_CONTAINER*> aZones, bool aCheck )
nextItem = 0; nextItem = 0;
threadsFinished = 0;
for( size_t ii = 0; ii < parallelThreadCount; ++ii ) auto tri_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
{ {
std::thread t = std::thread( [ & ]() size_t num = 0;
for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
{ {
for( size_t i = nextItem.fetch_add( 1 ); toFill[i].m_zone->CacheTriangulation();
i < toFill.size(); num++;
i = nextItem.fetch_add( 1 ) )
{
toFill[i].m_zone->CacheTriangulation();
if( m_progressReporter ) if( m_progressReporter )
m_progressReporter->AdvanceProgress(); m_progressReporter->AdvanceProgress();
}
threadsFinished++;
} );
t.detach();
}
// Finalize the triangulation threads
while( threadsFinished < parallelThreadCount )
{
if( m_progressReporter )
m_progressReporter->KeepRefreshing();
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
}
// Remove deprecaded segment zones (only found in very old boards)
m_board->m_SegZoneDeprecated.DeleteAll();
// If some zones must be filled by segments, create the filling segments
// (note, this is a outdated option, but it exists)
int zone_count = std::count_if( toFill.begin(), toFill.end(),
[]( CN_ZONE_ISOLATED_ISLAND_LIST& aList )
{ return aList.m_zone->GetFillMode() == ZFM_SEGMENTS; } );
if( zone_count > 0 )
{
if( m_progressReporter )
{
m_progressReporter->AdvancePhase();
m_progressReporter->Report( _( "Performing segment fills..." ) );
m_progressReporter->SetMaxProgress( zone_count );
} }
parallelThreadCount = std::min<size_t>( static_cast<size_t>( zone_count ), parallelThreadCount ); return num;
nextItem = 0; };
threadsFinished = 0;
if( parallelThreadCount <= 1 )
tri_lambda( m_progressReporter );
else
{
for( size_t ii = 0; ii < parallelThreadCount; ++ii )
returns[ii] = std::async( std::launch::async, tri_lambda, m_progressReporter );
for( size_t ii = 0; ii < parallelThreadCount; ++ii ) for( size_t ii = 0; ii < parallelThreadCount; ++ii )
{ {
std::thread t = std::thread( [ & ]() // Here we balance returns with a 100ms timeout to allow UI updating
std::future_status status;
do
{ {
for( size_t i = nextItem.fetch_add( 1 ); if( m_progressReporter )
i < toFill.size(); m_progressReporter->KeepRefreshing();
i = nextItem.fetch_add( 1 ) )
{
ZONE_CONTAINER* zone = toFill[i].m_zone;
if( zone->GetFillMode() == ZFM_SEGMENTS ) status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
{ } while( status != std::future_status::ready );
ZONE_SEGMENT_FILL segFill; }
fillZoneWithSegments( zone, zone->GetFilledPolysList(), segFill );
zone->SetFillSegments( segFill );
if( m_progressReporter )
m_progressReporter->AdvanceProgress();
}
}
threadsFinished++;
} );
t.detach();
}
// Finalize the triangulation threads
while( threadsFinished < parallelThreadCount )
{
if( m_progressReporter )
m_progressReporter->KeepRefreshing();
std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) );
}
} }
if( m_progressReporter ) if( m_progressReporter )
{ {
m_progressReporter->AdvancePhase(); m_progressReporter->AdvancePhase();