From 87171f53c78b16d60f61173a0df2684fad628c90 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Tue, 4 Oct 2022 17:00:08 -0700 Subject: [PATCH] Speedup dynamic ratsnest Removes some unneeded calculations and threads the remaining. Threading was previously removed to avoid overhead issues with small boards. This is no longer needed with the thread pool implementation Fixes https://gitlab.com/kicad/code/kicad/issues/12131 --- pcbnew/connectivity/connectivity_data.cpp | 16 +++++++++++--- pcbnew/ratsnest/ratsnest_data.cpp | 27 ++++++++++++----------- pcbnew/ratsnest/ratsnest_data.h | 2 +- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/pcbnew/connectivity/connectivity_data.cpp b/pcbnew/connectivity/connectivity_data.cpp index 97e28cbe96..ae139ee945 100644 --- a/pcbnew/connectivity/connectivity_data.cpp +++ b/pcbnew/connectivity/connectivity_data.cpp @@ -313,10 +313,12 @@ void CONNECTIVITY_DATA::ComputeLocalRatsnest( const std::vector& aI return; m_dynamicRatsnest.clear(); + std::mutex dynamic_ratsnest_mutex; // This gets connections between the stationary board and the // moving selection - for( unsigned int nc = 1; nc < aDynamicData->m_nets.size(); nc++ ) + + auto update_lambda = [&]( int nc ) { RN_NET* dynamicNet = aDynamicData->m_nets[nc]; RN_NET* staticNet = m_nets[nc]; @@ -329,17 +331,25 @@ void CONNECTIVITY_DATA::ComputeLocalRatsnest( const std::vector& aI { VECTOR2I pos1, pos2; - if( staticNet->NearestBicoloredPair( *dynamicNet, &pos1, &pos2 ) ) + if( staticNet->NearestBicoloredPair( dynamicNet, pos1, pos2 ) ) { RN_DYNAMIC_LINE l; l.a = pos1; l.b = pos2; l.netCode = nc; + std::lock_guard lock( dynamic_ratsnest_mutex ); m_dynamicRatsnest.push_back( l ); } } - } + }; + + GetKiCadThreadPool().parallelize_loop( 1, aDynamicData->m_nets.size(), + [&]( const int a, const int b) + { + for( int ii = a; ii < b; ++ii ) + update_lambda( ii ); + }).wait(); // This gets the ratsnest for internal connections in the moving set const std::vector& edges = GetRatsnestForItems( aItems ); diff --git a/pcbnew/ratsnest/ratsnest_data.cpp b/pcbnew/ratsnest/ratsnest_data.cpp index 0f24c60aac..7e9e187026 100644 --- a/pcbnew/ratsnest/ratsnest_data.cpp +++ b/pcbnew/ratsnest/ratsnest_data.cpp @@ -494,7 +494,7 @@ void RN_NET::AddCluster( std::shared_ptr aCluster ) } -bool RN_NET::NearestBicoloredPair( const RN_NET& aOtherNet, VECTOR2I* aPos1, VECTOR2I* aPos2 ) const +bool RN_NET::NearestBicoloredPair( RN_NET* aOtherNet, VECTOR2I& aPos1, VECTOR2I& aPos2 ) const { bool rv = false; @@ -511,32 +511,36 @@ bool RN_NET::NearestBicoloredPair( const RN_NET& aOtherNet, VECTOR2I* aPos1, VEC { rv = true; distMax_sq = dist_sq; - *aPos1 = aTestNode1->Pos(); - *aPos2 = aTestNode2->Pos(); + aPos1 = aTestNode1->Pos(); + aPos2 = aTestNode2->Pos(); } }; + std::multiset, CN_PTR_CMP> nodes_b; + + std::copy_if( m_nodes.begin(), m_nodes.end(), std::inserter( nodes_b, nodes_b.end() ), + []( const std::shared_ptr &aVal ) + { return !aVal->GetNoLine(); } ); + /// Sweep-line algorithm to cut the number of comparisons to find the closest point /// /// Step 1: The outer loop needs to be the subset (selected nodes) as it is a linear search - for( const std::shared_ptr& nodeA : aOtherNet.m_nodes ) + for( const std::shared_ptr& nodeA : aOtherNet->m_nodes ) { + if( nodeA->GetNoLine() ) continue; /// Step 2: O( log n ) search to identify a close element ordered by x /// The fwd_it iterator will move forward through the elements while /// the rev_it iterator will move backward through the same set - auto fwd_it = m_nodes.lower_bound( nodeA ); + auto fwd_it = nodes_b.lower_bound( nodeA ); auto rev_it = std::make_reverse_iterator( fwd_it ); - for( ; fwd_it != m_nodes.end(); ++fwd_it ) + for( ; fwd_it != nodes_b.end(); ++fwd_it ) { const std::shared_ptr& nodeB = *fwd_it; - if( nodeB->GetNoLine() ) - continue; - SEG::ecoord distX_sq = SEG::Square( nodeA->Pos().x - nodeB->Pos().x ); /// As soon as the x distance (primary sort) is larger than the smallest distance, @@ -548,13 +552,10 @@ bool RN_NET::NearestBicoloredPair( const RN_NET& aOtherNet, VECTOR2I* aPos1, VEC } /// Step 3: using the same starting point, check points backwards for closer points - for( ; rev_it != m_nodes.rend(); ++rev_it ) + for( ; rev_it != nodes_b.rend(); ++rev_it ) { const std::shared_ptr& nodeB = *rev_it; - if( nodeB->GetNoLine() ) - continue; - SEG::ecoord distX_sq = SEG::Square( nodeA->Pos().x - nodeB->Pos().x ); if( distX_sq > distMax_sq ) diff --git a/pcbnew/ratsnest/ratsnest_data.h b/pcbnew/ratsnest/ratsnest_data.h index fb1c9e83a2..e388d735cd 100644 --- a/pcbnew/ratsnest/ratsnest_data.h +++ b/pcbnew/ratsnest/ratsnest_data.h @@ -90,7 +90,7 @@ public: const std::vector& GetEdges() const { return m_rnEdges; } std::vector& GetEdges() { return m_rnEdges; } - bool NearestBicoloredPair( const RN_NET& aOtherNet, VECTOR2I* aPos1, VECTOR2I* aPos2 ) const; + bool NearestBicoloredPair( RN_NET* aOtherNet, VECTOR2I& aPos1, VECTOR2I& aPos2 ) const; protected: ///< Recompute ratsnest from scratch.