From 80bfe4472cc481bcdd2cac9c09de552922fd0367 Mon Sep 17 00:00:00 2001 From: Seth Hillbrand Date: Fri, 20 Feb 2026 14:54:32 -0800 Subject: [PATCH] Fix routing perf regression from clearance cache The clearance cache added in b0d0dd57ef invalidates on every SetLayer() and SetNetCode() call. The router's rule resolver calls SetLayer() on dummy board items for every clearance evaluation during routing. Each call acquires an exclusive lock and linearly scans the entire cache, but dummy items never exist in the cache, so this is pure waste. Skip cache invalidation for items flagged ROUTER_TRANSIENT. The flag is already set on all dummy items in the rule resolver. Also replace the O(n) linear scan in InvalidateClearanceCache with targeted O(1) hash erasure per copper layer. --- pcbnew/board_connected_item.cpp | 12 +++++++----- pcbnew/drc/drc_engine.cpp | 25 +++++++++++++++++-------- pcbnew/pad.cpp | 16 ++++++++++------ pcbnew/pcb_track.cpp | 24 +++++++++++++++--------- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/pcbnew/board_connected_item.cpp b/pcbnew/board_connected_item.cpp index 8869367c13..5519a09929 100644 --- a/pcbnew/board_connected_item.cpp +++ b/pcbnew/board_connected_item.cpp @@ -53,9 +53,11 @@ void BOARD_CONNECTED_ITEM::SetLayer( PCB_LAYER_ID aLayer ) { BOARD_ITEM::SetLayer( aLayer ); - // Invalidate clearance cache since layer can affect clearance rules - if( BOARD* board = GetBoard() ) - board->InvalidateClearanceCache( m_Uuid ); + if( !( GetFlags() & ROUTER_TRANSIENT ) ) + { + if( BOARD* board = GetBoard() ) + board->InvalidateClearanceCache( m_Uuid ); + } } @@ -103,10 +105,10 @@ bool BOARD_CONNECTED_ITEM::SetNetCode( int aNetCode, bool aNoAssert ) if( !aNoAssert ) wxASSERT( m_netinfo ); - // Invalidate clearance cache since net can affect clearance rules if( board ) { - board->InvalidateClearanceCache( m_Uuid ); + if( !( GetFlags() & ROUTER_TRANSIENT ) ) + board->InvalidateClearanceCache( m_Uuid ); std::unique_lock writeLock( board->m_CachesMutex ); board->m_ItemNetclassCache.erase( this ); diff --git a/pcbnew/drc/drc_engine.cpp b/pcbnew/drc/drc_engine.cpp index e0478165f3..d9b706725a 100644 --- a/pcbnew/drc/drc_engine.cpp +++ b/pcbnew/drc/drc_engine.cpp @@ -2553,15 +2553,24 @@ void DRC_ENGINE::InvalidateClearanceCache( const KIID& aUuid ) { std::unique_lock writeLock( m_clearanceCacheMutex ); - // Remove all entries for this item (across all layers) - auto it = m_ownClearanceCache.begin(); - - while( it != m_ownClearanceCache.end() ) + if( m_board ) { - if( it->first.m_uuid == aUuid ) - it = m_ownClearanceCache.erase( it ); - else - ++it; + LSET copperLayers = m_board->GetEnabledLayers() & LSET::AllCuMask(); + + for( PCB_LAYER_ID layer : copperLayers.Seq() ) + m_ownClearanceCache.erase( DRC_OWN_CLEARANCE_CACHE_KEY{ aUuid, layer } ); + } + else + { + auto it = m_ownClearanceCache.begin(); + + while( it != m_ownClearanceCache.end() ) + { + if( it->first.m_uuid == aUuid ) + it = m_ownClearanceCache.erase( it ); + else + ++it; + } } } diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index 660b318b79..fae830774a 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -1388,9 +1388,11 @@ void PAD::SetAttribute( PAD_ATTRIB aAttribute ) break; } - // Invalidate clearance cache since pad type affects constraint evaluation - if( BOARD* board = GetBoard() ) - board->InvalidateClearanceCache( m_Uuid ); + if( !( GetFlags() & ROUTER_TRANSIENT ) ) + { + if( BOARD* board = GetBoard() ) + board->InvalidateClearanceCache( m_Uuid ); + } } SetDirty(); @@ -1619,9 +1621,11 @@ void PAD::SetLayerSet( const LSET& aLayers ) m_padStack.SetLayerSet( aLayers ); SetDirty(); - // Invalidate clearance cache since layer set can affect clearance rules - if( BOARD* board = GetBoard() ) - board->InvalidateClearanceCache( m_Uuid ); + if( !( GetFlags() & ROUTER_TRANSIENT ) ) + { + if( BOARD* board = GetBoard() ) + board->InvalidateClearanceCache( m_Uuid ); + } } diff --git a/pcbnew/pcb_track.cpp b/pcbnew/pcb_track.cpp index 3cce238d5a..49dcf353aa 100644 --- a/pcbnew/pcb_track.cpp +++ b/pcbnew/pcb_track.cpp @@ -1643,9 +1643,11 @@ void PCB_VIA::SetLayerPair( PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer ) Padstack().Drill().end = aBottomLayer; SanitizeLayers(); - // Invalidate clearance cache since layer can affect clearance rules - if( BOARD* board = GetBoard() ) - board->InvalidateClearanceCache( m_Uuid ); + if( !( GetFlags() & ROUTER_TRANSIENT ) ) + { + if( BOARD* board = GetBoard() ) + board->InvalidateClearanceCache( m_Uuid ); + } } @@ -1658,9 +1660,11 @@ void PCB_VIA::SetTopLayer( PCB_LAYER_ID aLayer ) Padstack().Drill().start = aLayer; SanitizeLayers(); - // Invalidate clearance cache since layer can affect clearance rules - if( BOARD* board = GetBoard() ) - board->InvalidateClearanceCache( m_Uuid ); + if( !( GetFlags() & ROUTER_TRANSIENT ) ) + { + if( BOARD* board = GetBoard() ) + board->InvalidateClearanceCache( m_Uuid ); + } } @@ -1673,9 +1677,11 @@ void PCB_VIA::SetBottomLayer( PCB_LAYER_ID aLayer ) Padstack().Drill().end = aLayer; SanitizeLayers(); - // Invalidate clearance cache since layer can affect clearance rules - if( BOARD* board = GetBoard() ) - board->InvalidateClearanceCache( m_Uuid ); + if( !( GetFlags() & ROUTER_TRANSIENT ) ) + { + if( BOARD* board = GetBoard() ) + board->InvalidateClearanceCache( m_Uuid ); + } }