From ab8ff442d36607b49cf275f474ec08af3c85ebcd Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Fri, 9 Jan 2026 16:50:08 -0800 Subject: [PATCH] Some performance optimizations for PNS/DRC Removed the double map lookup (count() + op[]) Normalized the commutative caching so A,B = B,A Batched the locks for the layers --- pcbnew/drc/drc_engine.cpp | 57 +++++++++++++++------------- pcbnew/pcbexpr_functions.cpp | 63 +++++++++++++++++++++---------- pcbnew/router/pns_kicad_iface.cpp | 14 +++++-- 3 files changed, 85 insertions(+), 49 deletions(-) diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index e763cb3bf2..35cf60fe84 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -716,8 +716,10 @@ void DRC_ENGINE::compileRules() for( const DRC_CONSTRAINT& constraint : rule->m_Constraints ) { - if( !m_constraintMap.count( constraint.m_Type ) ) - m_constraintMap[ constraint.m_Type ] = new std::vector(); + auto& ruleVec = m_constraintMap[ constraint.m_Type ]; + + if( !ruleVec ) + ruleVec = new std::vector(); DRC_ENGINE_CONSTRAINT* engineConstraint = new DRC_ENGINE_CONSTRAINT; @@ -725,7 +727,7 @@ void DRC_ENGINE::compileRules() engineConstraint->condition = condition; engineConstraint->constraint = constraint; engineConstraint->parentRule = rule; - m_constraintMap[ constraint.m_Type ]->push_back( engineConstraint ); + ruleVec->push_back( engineConstraint ); } } @@ -1680,12 +1682,15 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO constraint.m_ImplicitMin = true; } } - else if( m_constraintMap.count( aConstraintType ) ) + else { - std::vector* ruleset = m_constraintMap[ aConstraintType ]; + auto it = m_constraintMap.find( aConstraintType ); - for( DRC_ENGINE_CONSTRAINT* rule : *ruleset ) - processConstraint( rule ); + if( it != m_constraintMap.end() ) + { + for( DRC_ENGINE_CONSTRAINT* rule : *it->second ) + processConstraint( rule ); + } } if( constraint.GetParentRule() && !constraint.GetParentRule()->IsImplicit() ) @@ -1710,11 +1715,11 @@ DRC_CONSTRAINT DRC_ENGINE::EvalRules( DRC_CONSTRAINT_T aConstraintType, const BO else b = parentFootprint; - if( m_constraintMap.count( aConstraintType ) ) - { - std::vector* ruleset = m_constraintMap[ aConstraintType ]; + auto it = m_constraintMap.find( aConstraintType ); - for( DRC_ENGINE_CONSTRAINT* rule : *ruleset ) + if( it != m_constraintMap.end() ) + { + for( DRC_ENGINE_CONSTRAINT* rule : *it->second ) processConstraint( rule ); if( constraint.GetParentRule() && !constraint.GetParentRule()->IsImplicit() ) @@ -2015,12 +2020,12 @@ void DRC_ENGINE::ProcessAssertions( const BOARD_ITEM* a, } }; - if( m_constraintMap.count( ASSERTION_CONSTRAINT ) ) - { - std::vector* ruleset = m_constraintMap[ ASSERTION_CONSTRAINT ]; + auto it = m_constraintMap.find( ASSERTION_CONSTRAINT ); - for( int ii = 0; ii < (int) ruleset->size(); ++ii ) - processConstraint( ruleset->at( ii ) ); + if( it != m_constraintMap.end() ) + { + for( int ii = 0; ii < (int) it->second->size(); ++ii ) + processConstraint( it->second->at( ii ) ); } } @@ -2124,22 +2129,19 @@ bool DRC_ENGINE::IsCancelled() const bool DRC_ENGINE::HasRulesForConstraintType( DRC_CONSTRAINT_T constraintID ) { - //drc_dbg( 10, "hascorrect id %d size %d\n", ruleID, m_ruleMap[ruleID]->sortedRules.size() ); - - if( m_constraintMap.count( constraintID ) ) - return m_constraintMap[ constraintID ]->size() > 0; - - return false; + auto it = m_constraintMap.find( constraintID ); + return it != m_constraintMap.end() && !it->second->empty(); } bool DRC_ENGINE::QueryWorstConstraint( DRC_CONSTRAINT_T aConstraintId, DRC_CONSTRAINT& aConstraint ) { - int worst = 0; + int worst = 0; + auto it = m_constraintMap.find( aConstraintId ); - if( m_constraintMap.count( aConstraintId ) ) + if( it != m_constraintMap.end() ) { - for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] ) + for( DRC_ENGINE_CONSTRAINT* c : *it->second ) { int current = c->constraint.GetValue().Min(); @@ -2158,10 +2160,11 @@ bool DRC_ENGINE::QueryWorstConstraint( DRC_CONSTRAINT_T aConstraintId, DRC_CONST std::set DRC_ENGINE::QueryDistinctConstraints( DRC_CONSTRAINT_T aConstraintId ) { std::set distinctMinimums; + auto it = m_constraintMap.find( aConstraintId ); - if( m_constraintMap.count( aConstraintId ) ) + if( it != m_constraintMap.end() ) { - for( DRC_ENGINE_CONSTRAINT* c : *m_constraintMap[aConstraintId] ) + for( DRC_ENGINE_CONSTRAINT* c : *it->second ) distinctMinimums.emplace( c->constraint.GetValue().Min() ); } diff --git a/pcbnew/pcbexpr_functions.cpp b/pcbnew/pcbexpr_functions.cpp index 6f4375e1f1..b1528178aa 100644 --- a/pcbnew/pcbexpr_functions.cpp +++ b/pcbnew/pcbexpr_functions.cpp @@ -729,33 +729,58 @@ static void intersectsAreaFunc( LIBEVAL::CONTEXT* aCtx, void* self ) else testLayers = commonLayers; - for( PCB_LAYER_ID layer : testLayers.UIOrder() ) + bool isTransient = ( item->GetFlags() & ROUTER_TRANSIENT ) != 0; + std::vector layersToCompute; + + if( !isTransient ) { - PTR_PTR_LAYER_CACHE_KEY key = { aArea, item, layer }; + std::shared_lock readLock( board->m_CachesMutex ); - if( ( item->GetFlags() & ROUTER_TRANSIENT ) == 0 ) + for( PCB_LAYER_ID layer : testLayers.UIOrder() ) { - std::shared_lock readLock( board->m_CachesMutex ); - + PTR_PTR_LAYER_CACHE_KEY key = { aArea, item, layer }; auto i = board->m_IntersectsAreaCache.find( key ); - if( i != board->m_IntersectsAreaCache.end() && i->second ) - return true; + if( i != board->m_IntersectsAreaCache.end() ) + { + if( i->second ) + return true; + } + else + { + layersToCompute.push_back( layer ); + } } - - bool collides = collidesWithArea( item, layer, context, aArea ); - - if( ( item->GetFlags() & ROUTER_TRANSIENT ) == 0 ) - { - std::unique_lock writeLock( board->m_CachesMutex ); - board->m_IntersectsAreaCache[ key ] = collides; - } - - if( collides ) - return true; + } + else + { + for( PCB_LAYER_ID layer : testLayers.UIOrder() ) + layersToCompute.push_back( layer ); } - return false; + std::vector> results; + bool anyCollision = false; + + for( PCB_LAYER_ID layer : layersToCompute ) + { + bool collides = collidesWithArea( item, layer, context, aArea ); + + if( !isTransient ) + results.push_back( { { aArea, item, layer }, collides } ); + + if( collides ) + anyCollision = true; + } + + if( !isTransient && !results.empty() ) + { + std::unique_lock writeLock( board->m_CachesMutex ); + + for( const auto& [key, collides] : results ) + board->m_IntersectsAreaCache[key] = collides; + } + + return anyCollision; } ) ) { return 1.0; diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index 0933d70679..ee0721c9ca 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -90,7 +90,14 @@ struct CLEARANCE_CACHE_KEY const PNS::ITEM* B; bool Flag; - bool operator==(const CLEARANCE_CACHE_KEY& other) const + CLEARANCE_CACHE_KEY( const PNS::ITEM* aA, const PNS::ITEM* aB, bool aFlag ) : + A( aA < aB ? aA : aB ), + B( aA < aB ? aB : aA ), + Flag( aFlag ) + { + } + + bool operator==( const CLEARANCE_CACHE_KEY& other ) const { return A == other.A && B == other.B && Flag == other.Flag; } @@ -104,7 +111,8 @@ namespace std std::size_t operator()( const CLEARANCE_CACHE_KEY& k ) const { size_t retval = 0xBADC0FFEE0DDF00D; - hash_combine( retval, hash()( k.A ), hash()( k.B ), hash()( k.Flag ) ); + hash_combine( retval, hash()( k.A ), hash()( k.B ), + hash()( k.Flag ) ); return retval; } }; @@ -509,7 +517,7 @@ void PNS_PCBNEW_RULE_RESOLVER::ClearTemporaryCaches() int PNS_PCBNEW_RULE_RESOLVER::Clearance( const PNS::ITEM* aA, const PNS::ITEM* aB, bool aUseClearanceEpsilon ) { - CLEARANCE_CACHE_KEY key = { aA, aB, aUseClearanceEpsilon }; + CLEARANCE_CACHE_KEY key( aA, aB, aUseClearanceEpsilon ); // Search cache (used for actual board items) auto it = m_clearanceCache.find( key );