diff --git a/pcbnew/connectivity_algo.cpp b/pcbnew/connectivity_algo.cpp index d11ea0bb7d..50863e5725 100644 --- a/pcbnew/connectivity_algo.cpp +++ b/pcbnew/connectivity_algo.cpp @@ -324,17 +324,19 @@ void CN_CONNECTIVITY_ALGO::searchConnections() PROF_COUNTER search_basic( "search-basic" ); #endif + size_t numDirty = std::count_if( m_itemList.begin(), m_itemList.end(), [] ( CN_ITEM* aItem ) + { return aItem->Dirty(); } ); + if( m_progressReporter ) { - m_progressReporter->SetMaxProgress( m_itemList.IsDirty() ? m_itemList.Size() : 0 ); + m_progressReporter->SetMaxProgress( numDirty ); + m_progressReporter->KeepRefreshing(); } if( m_itemList.IsDirty() ) { 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(); } ); size_t parallelThreadCount = std::min( std::max( std::thread::hardware_concurrency(), 2 ), @@ -353,10 +355,10 @@ void CN_CONNECTIVITY_ALGO::searchConnections() { CN_VISITOR visitor( item, &m_listLock ); m_itemList.FindNearby( item, visitor ); - } - if( m_progressReporter ) - m_progressReporter->AdvanceProgress(); + if( m_progressReporter ) + m_progressReporter->AdvanceProgress(); + } } threadsFinished++; diff --git a/pcbnew/tools/zone_filler_tool.cpp b/pcbnew/tools/zone_filler_tool.cpp index 4da12d4924..75817e2192 100644 --- a/pcbnew/tools/zone_filler_tool.cpp +++ b/pcbnew/tools/zone_filler_tool.cpp @@ -90,7 +90,7 @@ int ZONE_FILLER_TOOL::ZoneFill( const TOOL_EVENT& aEvent ) } std::unique_ptr progressReporter( - new WX_PROGRESS_REPORTER( frame(), _( "Fill Zone" ), 3 ) + new WX_PROGRESS_REPORTER( frame(), _( "Fill Zone" ), 4 ) ); ZONE_FILLER filler( board(), &commit ); @@ -113,7 +113,7 @@ int ZONE_FILLER_TOOL::ZoneFillAll( const TOOL_EVENT& aEvent ) } std::unique_ptr progressReporter( - new WX_PROGRESS_REPORTER( frame(), _( "Fill All Zones" ), 3 ) + new WX_PROGRESS_REPORTER( frame(), _( "Fill All Zones" ), 4 ) ); ZONE_FILLER filler( board(), &commit ); diff --git a/pcbnew/zone_filler.cpp b/pcbnew/zone_filler.cpp index 07697d3733..b929c76adc 100644 --- a/pcbnew/zone_filler.cpp +++ b/pcbnew/zone_filler.cpp @@ -63,8 +63,7 @@ static double s_thermalRot = 450; // angle of stubs in thermal reliefs for ro static const bool s_DumpZonesWhenFilling = false; ZONE_FILLER::ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit ) : - m_board( aBoard ), m_commit( aCommit ), m_progressReporter( nullptr ), - m_next( 0 ), m_count_done( 0 ) + m_board( aBoard ), m_commit( aCommit ), m_progressReporter( nullptr ) { } @@ -81,8 +80,6 @@ void ZONE_FILLER::SetProgressReporter( WX_PROGRESS_REPORTER* aReporter ) bool ZONE_FILLER::Fill( std::vector aZones, bool aCheck ) { - int parallelThreadCount = std::max( ( int )std::thread::hardware_concurrency(), 2 ); - std::vector toFill; auto connectivity = m_board->GetConnectivity(); @@ -112,16 +109,20 @@ bool ZONE_FILLER::Fill( std::vector aZones, bool aCheck ) m_progressReporter->SetMaxProgress( toFill.size() ); } - m_next = 0; - m_count_done = 0; - std::vector fillWorkers; - for( ssize_t ii = 0; ii < parallelThreadCount; ++ii ) + std::atomic nextItem( 0 ); + std::atomic threadsFinished( 0 ); + size_t parallelThreadCount = std::min( + std::max( std::thread::hardware_concurrency(), 2 ), + toFill.size() ); + + for( size_t ii = 0; ii < parallelThreadCount; ++ii ) { - fillWorkers.push_back( std::thread( [ this, toFill ]() + std::thread t = std::thread( [ & ]() { - size_t i = m_next.fetch_add( 1 ); - while( i < toFill.size() ) + for( size_t i = nextItem.fetch_add( 1 ); + i < toFill.size(); + i = nextItem.fetch_add( 1 ) ) { SHAPE_POLY_SET rawPolys, finalPolys; ZONE_CONTAINER* zone = toFill[i].m_zone; @@ -133,25 +134,25 @@ bool ZONE_FILLER::Fill( std::vector aZones, bool aCheck ) if( m_progressReporter ) m_progressReporter->AdvanceProgress(); - - m_count_done.fetch_add( 1 ); - i = m_next.fetch_add( 1 ); } - } ) ); + + threadsFinished++; + } ); + + t.detach(); } - while( m_count_done.load() < toFill.size() ) + + // Finalize the triangulation threads + while( threadsFinished < parallelThreadCount ) { if( m_progressReporter ) m_progressReporter->KeepRefreshing(); - wxMilliSleep( 20 ); + std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); } - for( size_t ii = 0; ii < fillWorkers.size(); ++ii ) - fillWorkers[ ii ].join(); - - // Now remove insulated copper islands + // Now update the connectivity to check for copper islands if( m_progressReporter ) { m_progressReporter->AdvancePhase(); @@ -162,6 +163,14 @@ bool ZONE_FILLER::Fill( std::vector aZones, bool aCheck ) connectivity->SetProgressReporter( m_progressReporter ); connectivity->FindIsolatedCopperIslands( toFill ); + // Now remove insulated copper islands + if( m_progressReporter ) + { + m_progressReporter->AdvancePhase(); + m_progressReporter->SetMaxProgress( toFill.size() ); + m_progressReporter->KeepRefreshing(); + } + bool outOfDate = false; for( auto& zone : toFill ) @@ -178,6 +187,12 @@ bool ZONE_FILLER::Fill( std::vector aZones, bool aCheck ) if( aCheck && zone.m_lastPolys.GetHash() != poly.GetHash() ) outOfDate = true; + + if( m_progressReporter ) + { + m_progressReporter->AdvanceProgress(); + m_progressReporter->KeepRefreshing(); + } } if( aCheck ) @@ -211,9 +226,6 @@ bool ZONE_FILLER::Fill( std::vector aZones, bool aCheck ) } } - // Remove deprecaded segment zones (only found in very old boards) - m_board->m_SegZoneDeprecated.DeleteAll(); - if( m_progressReporter ) { m_progressReporter->AdvancePhase(); @@ -221,82 +233,104 @@ bool ZONE_FILLER::Fill( std::vector aZones, bool aCheck ) m_progressReporter->SetMaxProgress( toFill.size() ); } - m_next = 0; - m_count_done = 0; - std::vector triangulationWorkers; - for( ssize_t ii = 0; ii < parallelThreadCount; ++ii ) + nextItem = 0; + threadsFinished = 0; + for( size_t ii = 0; ii < parallelThreadCount; ++ii ) { - triangulationWorkers.push_back( std::thread( [ this, toFill ]() + std::thread t = std::thread( [ & ]() { - size_t i = m_next.fetch_add( 1 ); - while( i < toFill.size() ) + for( size_t i = nextItem.fetch_add( 1 ); + i < toFill.size(); + i = nextItem.fetch_add( 1 ) ) { + toFill[i].m_zone->CacheTriangulation(); + if( m_progressReporter ) - m_progressReporter->AdvanceProgress(); + m_progressReporter->AdvanceProgress(); + } - toFill[i].m_zone->CacheTriangulation(); + threadsFinished++; + } ); - m_count_done.fetch_add( 1 ); - i = m_next.fetch_add( 1 ); - } - } ) ); - } + t.detach(); + } - while( m_count_done.load() < toFill.size() ) - { - if( m_progressReporter ) - m_progressReporter->KeepRefreshing(); - wxMilliSleep( 10 ); - } + // Finalize the triangulation threads + while( threadsFinished < parallelThreadCount ) + { + if( m_progressReporter ) + m_progressReporter->KeepRefreshing(); - for( size_t ii = 0; ii < triangulationWorkers.size(); ++ii ) - triangulationWorkers[ ii ].join(); + std::this_thread::sleep_for( std::chrono::milliseconds( 10 ) ); + } - // If some zones must be filled by segments, create the filling segments - // (note, this is a outdated option, but it exists) - int zones_to_fill_count = 0; - for( unsigned i = 0; i < toFill.size(); i++ ) - { - if( toFill[i].m_zone->GetFillMode() == ZFM_SEGMENTS ) - zones_to_fill_count++; - } + // Remove deprecaded segment zones (only found in very old boards) + m_board->m_SegZoneDeprecated.DeleteAll(); - if( zones_to_fill_count ) + // If some zones must be filled by segments, create the filling segments + // (note, this is a outdated option, but it exists) + if( int zone_count = std::count_if( toFill.begin(), toFill.end(), + []( CN_ZONE_ISOLATED_ISLAND_LIST& aList ) + { return aList.m_zone->GetFillMode() == ZFM_SEGMENTS; } ) > 0 ) { if( m_progressReporter ) { m_progressReporter->AdvancePhase(); m_progressReporter->Report( _( "Performing segment fills..." ) ); - m_progressReporter->SetMaxProgress( zones_to_fill_count ); + m_progressReporter->SetMaxProgress( zone_count ); } - // TODO: use thread pool to speedup calculations: - for( unsigned i = 0; i < toFill.size(); i++ ) + parallelThreadCount = std::min( static_cast( zone_count ), parallelThreadCount ); + nextItem = 0; + threadsFinished = 0; + for( size_t ii = 0; ii < parallelThreadCount; ++ii ) { - ZONE_CONTAINER* zone = toFill[i].m_zone; + std::thread t = std::thread( [ & ]() + { + for( size_t i = nextItem.fetch_add( 1 ); + i < toFill.size(); + i = nextItem.fetch_add( 1 ) ) + { + ZONE_CONTAINER* zone = toFill[i].m_zone; - if( zone->GetFillMode() != ZFM_SEGMENTS ) - continue; + if( zone->GetFillMode() == ZFM_SEGMENTS ) + { + ZONE_SEGMENT_FILL segFill; - if( m_progressReporter ) - { - m_progressReporter->AdvanceProgress(); - } + fillZoneWithSegments( zone, zone->GetFilledPolysList(), segFill ); + zone->SetFillSegments( segFill ); + + if( m_progressReporter ) + m_progressReporter->AdvanceProgress(); + } + } - ZONE_SEGMENT_FILL segFill; + threadsFinished++; + } ); - fillZoneWithSegments( zone, zone->GetFilledPolysList(), segFill ); - toFill[i].m_zone->SetFillSegments( segFill ); - } + 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 ) { m_progressReporter->AdvancePhase(); m_progressReporter->Report( _( "Committing changes..." ) ); + m_progressReporter->KeepRefreshing(); } connectivity->SetProgressReporter( nullptr ); diff --git a/pcbnew/zone_filler.h b/pcbnew/zone_filler.h index 27f50a1a51..19c7efdea7 100644 --- a/pcbnew/zone_filler.h +++ b/pcbnew/zone_filler.h @@ -118,11 +118,6 @@ private: BOARD* m_board; COMMIT* m_commit; WX_PROGRESS_REPORTER* m_progressReporter; - - std::atomic_size_t m_next; // An index into the vector of zones to fill. - // Used by the variuos parallel thread sets during - // fill operations. - std::atomic_size_t m_count_done; }; #endif diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 890174286b..e0b3edaff6 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -968,7 +968,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) wxString title; title.Printf( _( "Refill %d Zones" ), (int)zones_to_refill.size() ); std::unique_ptr progressReporter( - new WX_PROGRESS_REPORTER( this, title, 3 ) ); + new WX_PROGRESS_REPORTER( this, title, 4 ) ); filler.SetProgressReporter( progressReporter.get() ); filler.Fill( zones_to_refill ); diff --git a/pcbnew/zones_by_polygon_fill_functions.cpp b/pcbnew/zones_by_polygon_fill_functions.cpp index 4a472713f1..2e609d9d63 100644 --- a/pcbnew/zones_by_polygon_fill_functions.cpp +++ b/pcbnew/zones_by_polygon_fill_functions.cpp @@ -117,7 +117,7 @@ void PCB_EDIT_FRAME::Check_All_Zones( wxWindow* aActiveWindow ) BOARD_COMMIT commit( this ); std::unique_ptr progressReporter( - new WX_PROGRESS_REPORTER( aActiveWindow, _( "Checking Zones" ), 3 ) ); + new WX_PROGRESS_REPORTER( aActiveWindow, _( "Checking Zones" ), 4 ) ); ZONE_FILLER filler( GetBoard(), &commit ); filler.SetProgressReporter( progressReporter.get() );