Thread pad & graphic clearance testing.

This allows us to poll the event loop & update the progress
on a time interval rather than on an items-completed
interval (the later of which can't easily take host machine
performance into account).

Also fixes a bug where we'd bail out of QueryColliding if
we ever found !testClearance && !testShorting && !testHoles.
This commit is contained in:
Jeff Young 2024-01-03 13:49:29 +00:00
parent 8993cd12a6
commit 1e71899611
1 changed files with 147 additions and 125 deletions

View File

@ -95,7 +95,7 @@ private:
void testTrackClearances(); void testTrackClearances();
bool testPadAgainstItem( PAD* pad, SHAPE* padShape, PCB_LAYER_ID layer, BOARD_ITEM* other ); void testPadAgainstItem( PAD* pad, SHAPE* padShape, PCB_LAYER_ID layer, BOARD_ITEM* other );
void testPadClearances(); void testPadClearances();
@ -557,16 +557,14 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testKnockoutTextAgainstZone( BOARD_ITEM
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances() void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
{ {
// This is the number of tests between 2 calls to the progress bar
const int progressDelta = 100;
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 checkedPairsMutex;
std::mutex freePadsUsageMapMutex; std::mutex freePadsUsageMapMutex;
std::atomic<int> tracks_checked( 0 ); std::atomic<size_t> done( 0 );
size_t count = m_board->Tracks().size();
reportAux( wxT( "Testing %d tracks & vias..." ), count );
LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() ); LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
@ -668,7 +666,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
} }
} }
++tracks_checked; done.fetch_add( 1 );
} }
}; };
@ -676,20 +674,22 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testTrackClearances()
tp.push_loop( m_board->Tracks().size(), testTrack ); tp.push_loop( m_board->Tracks().size(), testTrack );
while( tracks_checked < static_cast<int>( m_board->Tracks().size() ) ) while( done < count )
{ {
if( !reportProgress( tracks_checked, m_board->Tracks().size(), progressDelta ) ) m_drcEngine->ReportProgress( static_cast<double>( done ) / count );
if( m_drcEngine->IsCancelled() )
{ {
tp.wait_for_tasks(); tp.wait_for_tasks();
break; break;
} }
std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) ); std::this_thread::sleep_for( std::chrono::milliseconds( 250 ) );
} }
} }
bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* padShape, void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* padShape,
PCB_LAYER_ID aLayer, PCB_LAYER_ID aLayer,
BOARD_ITEM* other ) BOARD_ITEM* other )
{ {
@ -763,7 +763,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
} }
if( !testClearance && !testShorting && !testHoles ) if( !testClearance && !testShorting && !testHoles )
return false; return;
std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( aLayer ); std::shared_ptr<SHAPE> otherShape = other->GetEffectiveShape( aLayer );
DRC_CONSTRAINT constraint; DRC_CONSTRAINT constraint;
@ -779,12 +779,12 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
if( testShorting ) if( testShorting )
{ {
if( pad->GetNetCode() == 0 || pad->GetNetCode() == otherPad->GetNetCode() ) if( pad->GetNetCode() == 0 || pad->GetNetCode() == otherPad->GetNetCode() )
return !m_drcEngine->IsCancelled(); return;
if( pad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) ) if( pad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) )
&& otherPad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) ) ) && otherPad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) ) )
{ {
return !m_drcEngine->IsCancelled(); return;
} }
std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS ); std::shared_ptr<DRC_ITEM> drce = DRC_ITEM::Create( DRCE_SHORTING_ITEMS );
@ -800,7 +800,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
reportViolation( drce, otherPad->GetPosition(), aLayer ); reportViolation( drce, otherPad->GetPosition(), aLayer );
} }
return !m_drcEngine->IsCancelled(); return;
} }
if( testClearance || testShorting ) if( testClearance || testShorting )
@ -923,15 +923,15 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa
} }
} }
return !m_drcEngine->IsCancelled(); return;
} }
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( ) void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
{ {
const int progressDelta = 100; thread_pool& tp = GetKiCadThreadPool();
size_t count = 0; size_t count = 0;
int ii = 0; std::atomic<size_t> done( 1 );
for( FOOTPRINT* footprint : m_board->Footprints() ) for( FOOTPRINT* footprint : m_board->Footprints() )
count += footprint->Pads().size(); count += footprint->Pads().size();
@ -942,12 +942,18 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() ); LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() );
std::future<void> retn = tp.submit(
[&]()
{
for( FOOTPRINT* footprint : m_board->Footprints() ) for( FOOTPRINT* footprint : m_board->Footprints() )
{ {
for( PAD* pad : footprint->Pads() ) for( PAD* pad : footprint->Pads() )
{ {
for( PCB_LAYER_ID layer : LSET( pad->GetLayerSet() & boardCopperLayers ).Seq() ) for( PCB_LAYER_ID layer : LSET( pad->GetLayerSet() & boardCopperLayers ).Seq() )
{ {
if( m_drcEngine->IsCancelled() )
return;
std::shared_ptr<SHAPE> padShape = pad->GetEffectiveShape( layer ); std::shared_ptr<SHAPE> padShape = pad->GetEffectiveShape( layer );
m_board->m_CopperItemRTreeCache->QueryColliding( pad, layer, layer, m_board->m_CopperItemRTreeCache->QueryColliding( pad, layer, layer,
@ -957,8 +963,8 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
BOARD_ITEM* a = pad; BOARD_ITEM* a = pad;
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
// (a:b and b:a) // directions (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 );
@ -975,7 +981,9 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
// Visitor // Visitor
[&]( BOARD_ITEM* other ) -> bool [&]( BOARD_ITEM* other ) -> bool
{ {
return testPadAgainstItem( pad, padShape.get(), layer, other ); testPadAgainstItem( pad, padShape.get(), layer, other );
return !m_drcEngine->IsCancelled();
}, },
m_board->m_DRCMaxClearance ); m_board->m_DRCMaxClearance );
@ -988,21 +996,26 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( )
} }
} }
if( !reportProgress( ii++, (int) count, progressDelta ) ) done.fetch_add( 1 );
return;
} }
}
} );
if( m_drcEngine->IsCancelled() ) std::future_status status = retn.wait_for( std::chrono::milliseconds( 250 ) );
return;
while( status != std::future_status::ready )
{
m_drcEngine->ReportProgress( static_cast<double>( done ) / count );
status = retn.wait_for( std::chrono::milliseconds( 250 ) );
} }
} }
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( ) void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( )
{ {
const int progressDelta = 100; thread_pool& tp = GetKiCadThreadPool();
size_t count = m_board->Drawings().size(); size_t count = m_board->Drawings().size();
int ii = 0; std::atomic<size_t> done( 1 );
for( FOOTPRINT* footprint : m_board->Footprints() ) for( FOOTPRINT* footprint : m_board->Footprints() )
count += footprint->GraphicalItems().size(); count += footprint->GraphicalItems().size();
@ -1110,6 +1123,9 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( )
m_board->m_DRCMaxClearance ); m_board->m_DRCMaxClearance );
}; };
std::future<void> retn = tp.submit(
[&]()
{
for( BOARD_ITEM* item : m_board->Drawings() ) for( BOARD_ITEM* item : m_board->Drawings() )
{ {
testGraphicAgainstZone( item ); testGraphicAgainstZone( item );
@ -1117,8 +1133,10 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( )
if( item->Type() == PCB_SHAPE_T && item->IsOnCopperLayer() ) if( item->Type() == PCB_SHAPE_T && item->IsOnCopperLayer() )
testCopperGraphic( static_cast<PCB_SHAPE*>( item ) ); testCopperGraphic( static_cast<PCB_SHAPE*>( item ) );
if( !reportProgress( ii++, (int) count, progressDelta ) ) done.fetch_add( 1 );
return;
if( m_drcEngine->IsCancelled() )
break;
} }
for( FOOTPRINT* footprint : m_board->Footprints() ) for( FOOTPRINT* footprint : m_board->Footprints() )
@ -1127,36 +1145,43 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( )
{ {
testGraphicAgainstZone( item ); testGraphicAgainstZone( item );
if( !reportProgress( ii++, (int) count, progressDelta ) ) done.fetch_add( 1 );
return;
if( m_drcEngine->IsCancelled() )
break;
} }
} }
} );
std::future_status status = retn.wait_for( std::chrono::milliseconds( 250 ) );
while( status != std::future_status::ready )
{
m_drcEngine->ReportProgress( static_cast<double>( done ) / count );
status = retn.wait_for( std::chrono::milliseconds( 250 ) );
}
} }
void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
{ {
const int progressDelta = 50;
bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ); bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE );
bool testIntersects = !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT ); bool testIntersects = !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT );
DRC_CONSTRAINT constraint; DRC_CONSTRAINT constraint;
bool cancelled = false;
std::vector<std::map<PCB_LAYER_ID, std::vector<SEG>>> poly_segments;
std::vector<std::map<PCB_LAYER_ID, std::vector<SEG>>> poly_segments;
poly_segments.resize( m_board->m_DRCCopperZones.size() ); poly_segments.resize( m_board->m_DRCCopperZones.size() );
// Contains the index for zoneA, zoneB, the conflict point, the actual clearance, the // Contains the index for zoneA, zoneB, the conflict point, the actual clearance, the
// required clearance, and the layer // required clearance, and the layer
using report_data = std::tuple<int, int, VECTOR2I, int, int, PCB_LAYER_ID>; using report_data = std::tuple<int, int, VECTOR2I, int, int, PCB_LAYER_ID>;
const int invalid_zone = -1;
std::vector<std::future<report_data>> futures; std::vector<std::future<report_data>> futures;
thread_pool& tp = GetKiCadThreadPool(); thread_pool& tp = GetKiCadThreadPool();
std::atomic<size_t> done( 1 );
auto checkZones = auto checkZones =
[testClearance, testIntersects, &poly_segments, &cancelled, invalid_zone] [this, testClearance, testIntersects, &poly_segments, &done]
( int zoneA, int zoneB, int clearance, PCB_LAYER_ID layer ) -> report_data ( int zoneA, int zoneB, int clearance, PCB_LAYER_ID layer ) -> report_data
{ {
// Iterate through all the segments of refSmoothedPoly // Iterate through all the segments of refSmoothedPoly
@ -1165,8 +1190,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
std::vector<SEG>& refSegments = poly_segments[zoneA][layer]; std::vector<SEG>& refSegments = poly_segments[zoneA][layer];
std::vector<SEG>& testSegments = poly_segments[zoneB][layer]; std::vector<SEG>& testSegments = poly_segments[zoneB][layer];
bool reported = false; bool reported = false;
auto invalid_result = std::make_tuple( invalid_zone, invalid_zone, VECTOR2I(), auto invalid_result = std::make_tuple( -1, -1, VECTOR2I(), 0, 0, F_Cu );
0, 0, F_Cu );
for( SEG& refSegment : refSegments ) for( SEG& refSegment : refSegments )
{ {
@ -1204,14 +1228,18 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
reported = true; reported = true;
if( reported ) if( reported )
{
done.fetch_add( 1 );
return std::make_tuple( zoneA, zoneB, pt, d, clearance, layer ); return std::make_tuple( zoneA, zoneB, pt, d, clearance, layer );
} }
}
if( cancelled ) if( m_drcEngine->IsCancelled() )
return invalid_result; return invalid_result;
} }
} }
done.fetch_add( 1 );
return invalid_result; return invalid_result;
}; };
@ -1229,10 +1257,10 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
if( m_board->m_DRCCopperZones[ii]->IsOnLayer( layer ) ) if( m_board->m_DRCCopperZones[ii]->IsOnLayer( layer ) )
{ {
SHAPE_POLY_SET poly = *m_board->m_DRCCopperZones[ii]->GetFilledPolysList( layer ); SHAPE_POLY_SET poly = *m_board->m_DRCCopperZones[ii]->GetFilledPolysList( layer );
std::vector<SEG>& poly_segs = poly_segments[ii][layer]; std::vector<SEG>& zone_layer_poly_segs = poly_segments[ii][layer];
poly.BuildBBoxCaches(); poly.BuildBBoxCaches();
poly_segs.reserve( poly.FullPointCount() ); zone_layer_poly_segs.reserve( poly.FullPointCount() );
for( auto it = poly.IterateSegmentsWithHoles(); it; it++ ) for( auto it = poly.IterateSegmentsWithHoles(); it; it++ )
{ {
@ -1241,10 +1269,10 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
if( seg.A.x > seg.B.x ) if( seg.A.x > seg.B.x )
seg.Reverse(); seg.Reverse();
poly_segs.push_back( seg ); zone_layer_poly_segs.push_back( seg );
} }
std::sort( poly_segs.begin(), poly_segs.end() ); std::sort( zone_layer_poly_segs.begin(), zone_layer_poly_segs.end() );
} }
} }
@ -1252,12 +1280,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
for( size_t ia = 0; ia < m_board->m_DRCCopperZones.size(); ia++ ) for( size_t ia = 0; ia < m_board->m_DRCCopperZones.size(); ia++ )
{ {
if( !reportProgress( layer_id * m_board->m_DRCCopperZones.size() + ia,
B_Cu * m_board->m_DRCCopperZones.size(), progressDelta ) )
{
return; // DRC cancelled
}
ZONE* zoneA = m_board->m_DRCCopperZones[ia]; ZONE* zoneA = m_board->m_DRCCopperZones[ia];
if( !zoneA->IsOnLayer( layer ) ) if( !zoneA->IsOnLayer( layer ) )
@ -1298,6 +1320,8 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
} }
} }
size_t count = futures.size();
for( auto& task : futures ) for( auto& task : futures )
{ {
if( !task.valid() ) if( !task.valid() )
@ -1307,28 +1331,27 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
while( true ) while( true )
{ {
result = task.wait_for( std::chrono::milliseconds( 200 ) ); result = task.wait_for( std::chrono::milliseconds( 250 ) );
m_drcEngine->ReportProgress( static_cast<double>( done ) / count );
if( m_drcEngine->IsCancelled() ) if( m_drcEngine->IsCancelled() )
{
cancelled = true;
break; break;
}
if( result == std::future_status::ready ) if( result == std::future_status::ready )
{ {
report_data data = task.get(); report_data data = task.get();
int zoneA_id = std::get<0>( data ); int zoneA_idx = std::get<0>( data );
int zoneB_id = std::get<1>( data ); int zoneB_idx = std::get<1>( data );
VECTOR2I pt = std::get<2>( data ); VECTOR2I pt = std::get<2>( data );
int actual = std::get<3>( data ); int actual = std::get<3>( data );
int required = std::get<4>( data ); int required = std::get<4>( data );
PCB_LAYER_ID layer = std::get<5>( data ); PCB_LAYER_ID layer = std::get<5>( data );
if( zoneA_id != invalid_zone ) if( zoneA_idx >= 0 )
{ {
ZONE* zoneA = m_board->m_DRCCopperZones[zoneA_id]; ZONE* zoneA = m_board->m_DRCCopperZones[zoneA_idx];
ZONE* zoneB = m_board->m_DRCCopperZones[zoneB_id]; ZONE* zoneB = m_board->m_DRCCopperZones[zoneB_idx];
constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer ); constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer );
std::shared_ptr<DRC_ITEM> drce; std::shared_ptr<DRC_ITEM> drce;
@ -1359,7 +1382,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones()
break; break;
} }
} }
} }
} }