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
This commit is contained in:
Seth Hillbrand
2026-01-09 16:50:08 -08:00
parent e741ee2e6c
commit ab8ff442d3
3 changed files with 85 additions and 49 deletions
+30 -27
View File
@@ -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<DRC_ENGINE_CONSTRAINT*>();
auto& ruleVec = m_constraintMap[ constraint.m_Type ];
if( !ruleVec )
ruleVec = new std::vector<DRC_ENGINE_CONSTRAINT*>();
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<DRC_ENGINE_CONSTRAINT*>* 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<DRC_ENGINE_CONSTRAINT*>* 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<DRC_ENGINE_CONSTRAINT*>* 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<int> DRC_ENGINE::QueryDistinctConstraints( DRC_CONSTRAINT_T aConstraintId )
{
std::set<int> 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() );
}
+44 -19
View File
@@ -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<PCB_LAYER_ID> layersToCompute;
if( !isTransient )
{
PTR_PTR_LAYER_CACHE_KEY key = { aArea, item, layer };
std::shared_lock<std::shared_mutex> readLock( board->m_CachesMutex );
if( ( item->GetFlags() & ROUTER_TRANSIENT ) == 0 )
for( PCB_LAYER_ID layer : testLayers.UIOrder() )
{
std::shared_lock<std::shared_mutex> 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<std::shared_mutex> 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<std::pair<PTR_PTR_LAYER_CACHE_KEY, bool>> 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<std::shared_mutex> writeLock( board->m_CachesMutex );
for( const auto& [key, collides] : results )
board->m_IntersectsAreaCache[key] = collides;
}
return anyCollision;
} ) )
{
return 1.0;
+11 -3
View File
@@ -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<const void*>()( k.A ), hash<const void*>()( k.B ), hash<int>()( k.Flag ) );
hash_combine( retval, hash<const void*>()( k.A ), hash<const void*>()( k.B ),
hash<int>()( 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 );