From ca095896cb048f5d7f67bcf6451f9f7dd961e8f5 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Wed, 16 Feb 2022 14:10:43 +0000 Subject: [PATCH] Performance: multi-thread CN_ZONE_LAYER RTree generation. --- pcbnew/connectivity/connectivity_algo.cpp | 107 ++++++++++++++++----- pcbnew/connectivity/connectivity_items.cpp | 24 +++-- pcbnew/connectivity/connectivity_items.h | 12 ++- 3 files changed, 105 insertions(+), 38 deletions(-) diff --git a/pcbnew/connectivity/connectivity_algo.cpp b/pcbnew/connectivity/connectivity_algo.cpp index b584ae6c4f..c8f2c49147 100644 --- a/pcbnew/connectivity/connectivity_algo.cpp +++ b/pcbnew/connectivity/connectivity_algo.cpp @@ -423,43 +423,104 @@ CN_CONNECTIVITY_ALGO::SearchClusters( CLUSTER_SEARCH_MODE aMode, const KICAD_T a void CN_CONNECTIVITY_ALGO::Build( BOARD* aBoard, PROGRESS_REPORTER* aReporter ) { - int delta = 100; // Number of additions between 2 calls to the progress bar - int zoneScaler = 50; // Zones are more expensive - int ii = 0; - int size = 0; + // Generate CN_ZONE_LAYERs for each island on each layer of each zone + // + std::vector zitems; - size += aBoard->Zones().size() * zoneScaler; + for( ZONE* zone : aBoard->Zones() ) + { + if( zone->IsOnCopperLayer() ) + { + m_itemMap[zone] = ITEM_MAP_ENTRY(); + markItemNetAsDirty( zone ); + + for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() ) + { + if( IsCopperLayer( layer ) ) + { + for( int j = 0; j < zone->GetFilledPolysList( layer )->OutlineCount(); j++ ) + zitems.push_back( new CN_ZONE_LAYER( zone, layer, j ) ); + } + } + } + } + + // Setup progress metrics + // + int delta = 50; // Number of additions between 2 calls to the progress bar + double size = 0.0; + + size += zitems.size(); // Once for building RTrees + size += zitems.size(); // Once for adding to connectivity size += aBoard->Tracks().size(); for( FOOTPRINT* footprint : aBoard->Footprints() ) size += footprint->Pads().size(); - size *= 1.5; // Our caller gets the other third of the progress bar + size *= 1.5; // Our caller gets the other third of the progress bar - delta = std::max( delta, size / 10 ); + delta = std::max( delta, KiROUND( size / 10 ) ); - for( ZONE* zone : aBoard->Zones() ) + auto report = + [&]( int progress ) + { + if( aReporter && ( progress % delta ) == 0 ) + { + aReporter->SetCurrentProgress( progress / size ); + aReporter->KeepRefreshing( false ); + } + }; + + // Generate RTrees for CN_ZONE_LAYER items (in parallel) + // + std::atomic next( 0 ); + std::atomic zitems_done( 0 ); + std::atomic threads_done( 0 ); + size_t parallelThreadCount = std::max( std::thread::hardware_concurrency(), 2 ); + + for( size_t ii = 0; ii < parallelThreadCount; ++ii ) { - Add( zone ); - ii += zoneScaler; + std::thread t = std::thread( + [ &zitems, &zitems_done, &threads_done, &next ]( ) + { + for( size_t i = next.fetch_add( 1 ); i < zitems.size(); i = next.fetch_add( 1 ) ) + { + zitems[i]->BuildRTree(); + zitems_done.fetch_add( 1 ); + } + threads_done.fetch_add( 1 ); + } ); + + t.detach(); + } + + while( threads_done < parallelThreadCount ) + { if( aReporter ) { - aReporter->SetCurrentProgress( (double) ii / (double) size ); - aReporter->KeepRefreshing( false ); + aReporter->SetCurrentProgress( zitems_done / size ); + aReporter->KeepRefreshing(); } + + std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); + } + + // Add CN_ZONE_LAYERS, tracks, and pads to connectivity + // + int ii = zitems.size(); + + for( CN_ZONE_LAYER* zitem : zitems ) + { + m_itemList.Add( zitem ); + m_itemMap[ zitem->Parent() ].Link( zitem ); + report( ++ii ); } for( PCB_TRACK* tv : aBoard->Tracks() ) { Add( tv ); - ii++; - - if( aReporter && ( ii % delta ) == 0 ) - { - aReporter->SetCurrentProgress( (double) ii / (double) size ); - aReporter->KeepRefreshing( false ); - } + report( ++ii ); } for( FOOTPRINT* footprint : aBoard->Footprints() ) @@ -467,13 +528,7 @@ void CN_CONNECTIVITY_ALGO::Build( BOARD* aBoard, PROGRESS_REPORTER* aReporter ) for( PAD* pad : footprint->Pads() ) { Add( pad ); - ii++; - - if( aReporter && ( ii % delta ) == 0 ) - { - aReporter->SetCurrentProgress( (double) ii / (double) size ); - aReporter->KeepRefreshing( false ); - } + report( ++ii ); } } diff --git a/pcbnew/connectivity/connectivity_items.cpp b/pcbnew/connectivity/connectivity_items.cpp index 20cd5655c2..f9d5acc17d 100644 --- a/pcbnew/connectivity/connectivity_items.cpp +++ b/pcbnew/connectivity/connectivity_items.cpp @@ -205,23 +205,29 @@ CN_ITEM* CN_LIST::Add( PCB_ARC* aArc ) for( int j = 0; j < polys->OutlineCount(); j++ ) { - CN_ZONE_LAYER* zitem = new CN_ZONE_LAYER( zone, aLayer, false, j ); - const SHAPE_LINE_CHAIN& outline = zone->GetFilledPolysList( aLayer )->COutline( j ); + CN_ZONE_LAYER* zitem = new CN_ZONE_LAYER( zone, aLayer, j ); - for( int k = 0; k < outline.PointCount(); k++ ) - zitem->AddAnchor( outline.CPoint( k ) ); + zitem->BuildRTree(); - m_items.push_back( zitem ); - zitem->SetLayer( aLayer ); - addItemtoTree( zitem ); - rv.push_back( zitem ); - SetDirty(); + for( VECTOR2I pt : zone->GetFilledPolysList( aLayer )->COutline( j ).CPoints() ) + zitem->AddAnchor( pt ); + + rv.push_back( Add( zitem ) ); } return rv; } +CN_ITEM* CN_LIST::Add( CN_ZONE_LAYER* zitem ) +{ + m_items.push_back( zitem ); + addItemtoTree( zitem ); + SetDirty(); + return zitem; +} + + void CN_LIST::RemoveInvalidItems( std::vector& aGarbage ) { if( !m_hasInvalid ) diff --git a/pcbnew/connectivity/connectivity_items.h b/pcbnew/connectivity/connectivity_items.h index d5d3d53eb9..7fb2c298ef 100644 --- a/pcbnew/connectivity/connectivity_items.h +++ b/pcbnew/connectivity/connectivity_items.h @@ -285,18 +285,22 @@ typedef std::shared_ptr CN_ITEM_PTR; class CN_ZONE_LAYER : public CN_ITEM { public: - CN_ZONE_LAYER( ZONE* aParent, PCB_LAYER_ID aLayer, bool aCanChangeNet, int aSubpolyIndex ) : - CN_ITEM( aParent, aCanChangeNet ), + CN_ZONE_LAYER( ZONE* aParent, PCB_LAYER_ID aLayer, int aSubpolyIndex ) : + CN_ITEM( aParent, false ), m_subpolyIndex( aSubpolyIndex ), m_layer( aLayer ) { m_triangulatedPoly = aParent->GetFilledPolysList( aLayer ); + SetLayers( aLayer ); + } + void BuildRTree() + { for( unsigned int ii = 0; ii < m_triangulatedPoly->TriangulatedPolyCount(); ++ii ) { const auto* triangleSet = m_triangulatedPoly->TriangulatedPolygon( ii ); - if( triangleSet->GetSourceOutlineIndex() != aSubpolyIndex ) + if( triangleSet->GetSourceOutlineIndex() != m_subpolyIndex ) continue; for( const SHAPE_POLY_SET::TRIANGULATED_POLYGON::TRI& tri : triangleSet->Triangles() ) @@ -449,6 +453,8 @@ public: CN_ITEM* Add( PCB_VIA* via ); + CN_ITEM* Add( CN_ZONE_LAYER* zitem ); + const std::vector Add( ZONE* zone, PCB_LAYER_ID aLayer ); private: