Thread testTrackClearances
We are frequently testing thousands of track segments. They can each be uniquely tested in parallel with reporting and marking guarded by mutexes. This speeds up the DRC tests substantially Fixes https://gitlab.com/kicad/code/kicad/-/issues/15466
This commit is contained in:
parent
b2ef620ea6
commit
f4afd7e363
|
@ -75,6 +75,7 @@ const wxString DRC_TEST_PROVIDER::GetDescription() const { return wxEmptyString;
|
||||||
void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr<DRC_ITEM>& item,
|
void DRC_TEST_PROVIDER::reportViolation( std::shared_ptr<DRC_ITEM>& item,
|
||||||
const VECTOR2I& aMarkerPos, int aMarkerLayer )
|
const VECTOR2I& aMarkerPos, int aMarkerLayer )
|
||||||
{
|
{
|
||||||
|
std::lock_guard<std::mutex> lock( m_statsMutex );
|
||||||
if( item->GetViolatingRule() )
|
if( item->GetViolatingRule() )
|
||||||
accountCheck( item->GetViolatingRule() );
|
accountCheck( item->GetViolatingRule() );
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,7 @@ protected:
|
||||||
DRC_ENGINE* m_drcEngine;
|
DRC_ENGINE* m_drcEngine;
|
||||||
std::unordered_map<const DRC_RULE*, int> m_stats;
|
std::unordered_map<const DRC_RULE*, int> m_stats;
|
||||||
bool m_isRuleDriven = true;
|
bool m_isRuleDriven = true;
|
||||||
|
std::mutex m_statsMutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DRC_TEST_PROVIDER__H
|
#endif // DRC_TEST_PROVIDER__H
|
||||||
|
|
|
@ -559,108 +559,132 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
|
||||||
{
|
{
|
||||||
// This is the number of tests between 2 calls to the progress bar
|
// This is the number of tests between 2 calls to the progress bar
|
||||||
const int progressDelta = 100;
|
const int progressDelta = 100;
|
||||||
int ii = 0;
|
|
||||||
|
|
||||||
reportAux( wxT( "Testing %d tracks & vias..." ), m_board->Tracks().size() );
|
reportAux( wxT( "Testing %d tracks & vias..." ), m_board->Tracks().size() );
|
||||||
|
|
||||||
std::map<BOARD_ITEM*, int> freePadsUsageMap;
|
std::map<BOARD_ITEM*, int> freePadsUsageMap;
|
||||||
std::unordered_map<PTR_PTR_CACHE_KEY, layers_checked> checkedPairs;
|
std::unordered_map<PTR_PTR_CACHE_KEY, layers_checked> checkedPairs;
|
||||||
|
std::mutex checkedPairsMutex;
|
||||||
|
std::mutex freePadsUsageMapMutex;
|
||||||
|
std::atomic<int> tracks_checked( 0 );
|
||||||
|
|
||||||
LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
|
LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
|
||||||
|
|
||||||
for( PCB_TRACK* track : m_board->Tracks() )
|
auto testTrack = [&]( const int start_idx, const int end_idx )
|
||||||
{
|
{
|
||||||
if( !reportProgress( ii++, m_board->Tracks().size(), progressDelta ) )
|
for( int trackIdx = start_idx; trackIdx < end_idx; ++trackIdx )
|
||||||
break;
|
|
||||||
|
|
||||||
for( PCB_LAYER_ID layer : LSET( track->GetLayerSet() & boardCopperLayers ).Seq() )
|
|
||||||
{
|
{
|
||||||
std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
|
PCB_TRACK* track = m_board->Tracks()[trackIdx];
|
||||||
|
|
||||||
m_board->m_CopperItemRTreeCache->QueryColliding( track, layer, layer,
|
for( PCB_LAYER_ID layer : LSET( track->GetLayerSet() & boardCopperLayers ).Seq() )
|
||||||
// Filter:
|
{
|
||||||
[&]( BOARD_ITEM* other ) -> bool
|
std::shared_ptr<SHAPE> trackShape = track->GetEffectiveShape( layer );
|
||||||
{
|
|
||||||
auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
|
|
||||||
|
|
||||||
if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
|
m_board->m_CopperItemRTreeCache->QueryColliding( track, layer, layer,
|
||||||
return false;
|
// Filter:
|
||||||
|
[&]( BOARD_ITEM* other ) -> bool
|
||||||
BOARD_ITEM* a = track;
|
|
||||||
BOARD_ITEM* b = other;
|
|
||||||
|
|
||||||
// store canonical order so we don't collide in both directions
|
|
||||||
// (a:b and b:a)
|
|
||||||
if( static_cast<void*>( a ) > static_cast<void*>( b ) )
|
|
||||||
std::swap( a, b );
|
|
||||||
|
|
||||||
auto it = checkedPairs.find( { a, b } );
|
|
||||||
|
|
||||||
if( it != checkedPairs.end() && ( it->second.layers.test( layer )
|
|
||||||
|| ( it->second.has_error && !m_drcEngine->GetReportAllTrackErrors() ) ) )
|
|
||||||
{
|
{
|
||||||
return false;
|
auto otherCItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( other );
|
||||||
}
|
|
||||||
else
|
if( otherCItem && otherCItem->GetNetCode() == track->GetNetCode() )
|
||||||
{
|
return false;
|
||||||
checkedPairs[ { a, b } ].layers.set( layer );
|
|
||||||
return true;
|
BOARD_ITEM* a = track;
|
||||||
}
|
BOARD_ITEM* b = other;
|
||||||
},
|
|
||||||
// Visitor:
|
// store canonical order so we don't collide in both directions
|
||||||
[&]( BOARD_ITEM* other ) -> bool
|
// (a:b and b:a)
|
||||||
{
|
if( static_cast<void*>( a ) > static_cast<void*>( b ) )
|
||||||
if( other->Type() == PCB_PAD_T && static_cast<PAD*>( other )->IsFreePad() )
|
std::swap( a, b );
|
||||||
{
|
|
||||||
if( other->GetEffectiveShape( layer )->Collide( trackShape.get() ) )
|
std::lock_guard<std::mutex> lock( checkedPairsMutex );
|
||||||
|
auto it = checkedPairs.find( { a, b } );
|
||||||
|
|
||||||
|
if( it != checkedPairs.end() && ( it->second.layers.test( layer )
|
||||||
|
|| ( it->second.has_error && !m_drcEngine->GetReportAllTrackErrors() ) ) )
|
||||||
{
|
{
|
||||||
auto it = freePadsUsageMap.find( other );
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
checkedPairs[ { a, b } ].layers.set( layer );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Visitor:
|
||||||
|
[&]( BOARD_ITEM* other ) -> bool
|
||||||
|
{
|
||||||
|
if( other->Type() == PCB_PAD_T && static_cast<PAD*>( other )->IsFreePad() )
|
||||||
|
{
|
||||||
|
if( other->GetEffectiveShape( layer )->Collide( trackShape.get() ) )
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock( freePadsUsageMapMutex );
|
||||||
|
auto it = freePadsUsageMap.find( other );
|
||||||
|
|
||||||
if( it == freePadsUsageMap.end() )
|
if( it == freePadsUsageMap.end() )
|
||||||
{
|
{
|
||||||
freePadsUsageMap[ other ] = track->GetNetCode();
|
freePadsUsageMap[ other ] = track->GetNetCode();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if( it->second == track->GetNetCode() )
|
else if( it->second == track->GetNetCode() )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BOARD_ITEM* a = track;
|
BOARD_ITEM* a = track;
|
||||||
BOARD_ITEM* b = other;
|
BOARD_ITEM* b = other;
|
||||||
|
|
||||||
// store canonical order so we don't collide in both directions
|
// store canonical order so we don't collide in both directions
|
||||||
// (a:b and b:a)
|
// (a:b and b:a)
|
||||||
if( static_cast<void*>( a ) > static_cast<void*>( b ) )
|
if( static_cast<void*>( a ) > static_cast<void*>( b ) )
|
||||||
std::swap( a, b );
|
std::swap( a, b );
|
||||||
|
|
||||||
auto it = checkedPairs.find( { a, b } );
|
// If we get an error, mark the pair as having a clearance error already
|
||||||
|
// Only continue if we are reporting all track errors
|
||||||
|
if( !testSingleLayerItemAgainstItem( track, trackShape.get(), layer,
|
||||||
|
other ) )
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock( checkedPairsMutex );
|
||||||
|
auto it = checkedPairs.find( { a, b } );
|
||||||
|
|
||||||
// If we get an error, mark the pair as having a clearance error already
|
if( it != checkedPairs.end() )
|
||||||
// Only continue if we are reporting all track errors
|
it->second.has_error = true;
|
||||||
if( !testSingleLayerItemAgainstItem( track, trackShape.get(), layer,
|
|
||||||
other ) )
|
|
||||||
{
|
|
||||||
if( it != checkedPairs.end() )
|
|
||||||
it->second.has_error = true;
|
|
||||||
|
|
||||||
return m_drcEngine->GetReportAllTrackErrors() && !m_drcEngine->IsCancelled();
|
return m_drcEngine->GetReportAllTrackErrors() && !m_drcEngine->IsCancelled();
|
||||||
}
|
}
|
||||||
|
|
||||||
return !m_drcEngine->IsCancelled();
|
return !m_drcEngine->IsCancelled();
|
||||||
},
|
},
|
||||||
m_board->m_DRCMaxClearance );
|
m_board->m_DRCMaxClearance );
|
||||||
|
|
||||||
for( ZONE* zone : m_board->m_DRCCopperZones )
|
for( ZONE* zone : m_board->m_DRCCopperZones )
|
||||||
{
|
{
|
||||||
testItemAgainstZone( track, zone, layer );
|
testItemAgainstZone( track, zone, layer );
|
||||||
|
|
||||||
if( m_drcEngine->IsCancelled() )
|
if( m_drcEngine->IsCancelled() )
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
++tracks_checked;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
thread_pool& tp = GetKiCadThreadPool();
|
||||||
|
|
||||||
|
tp.push_loop( m_board->Tracks().size(), testTrack );
|
||||||
|
|
||||||
|
while( tracks_checked < static_cast<int>( m_board->Tracks().size() ) )
|
||||||
|
{
|
||||||
|
if( !reportProgress( tracks_checked, m_board->Tracks().size(), progressDelta ) )
|
||||||
|
{
|
||||||
|
tp.wait_for_tasks();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue