From 1e718996117f327a9460f496921af60fd871ccb6 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Wed, 3 Jan 2024 13:49:29 +0000 Subject: [PATCH] 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. --- .../drc_test_provider_copper_clearance.cpp | 272 ++++++++++-------- 1 file changed, 147 insertions(+), 125 deletions(-) diff --git a/pcbnew/drc/drc_test_provider_copper_clearance.cpp b/pcbnew/drc/drc_test_provider_copper_clearance.cpp index 22b1f013ef..1d717768f5 100644 --- a/pcbnew/drc/drc_test_provider_copper_clearance.cpp +++ b/pcbnew/drc/drc_test_provider_copper_clearance.cpp @@ -95,7 +95,7 @@ private: 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(); @@ -557,16 +557,14 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testKnockoutTextAgainstZone( BOARD_ITEM 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 freePadsUsageMap; std::unordered_map checkedPairs; std::mutex checkedPairsMutex; std::mutex freePadsUsageMapMutex; - std::atomic tracks_checked( 0 ); + std::atomic done( 0 ); + size_t count = m_board->Tracks().size(); + + reportAux( wxT( "Testing %d tracks & vias..." ), count ); 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 ); - while( tracks_checked < static_cast( m_board->Tracks().size() ) ) + while( done < count ) { - if( !reportProgress( tracks_checked, m_board->Tracks().size(), progressDelta ) ) + m_drcEngine->ReportProgress( static_cast( done ) / count ); + + if( m_drcEngine->IsCancelled() ) { tp.wait_for_tasks(); 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, BOARD_ITEM* other ) { @@ -763,7 +763,7 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa } if( !testClearance && !testShorting && !testHoles ) - return false; + return; std::shared_ptr otherShape = other->GetEffectiveShape( aLayer ); DRC_CONSTRAINT constraint; @@ -779,12 +779,12 @@ bool DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadAgainstItem( PAD* pad, SHAPE* pa if( testShorting ) { if( pad->GetNetCode() == 0 || pad->GetNetCode() == otherPad->GetNetCode() ) - return !m_drcEngine->IsCancelled(); + return; if( pad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) ) && otherPad->GetShortNetname().StartsWith( wxS( "unconnected-(" ) ) ) { - return !m_drcEngine->IsCancelled(); + return; } std::shared_ptr 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 ); } - return !m_drcEngine->IsCancelled(); + return; } 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( ) { - const int progressDelta = 100; - size_t count = 0; - int ii = 0; + thread_pool& tp = GetKiCadThreadPool(); + size_t count = 0; + std::atomic done( 1 ); for( FOOTPRINT* footprint : m_board->Footprints() ) count += footprint->Pads().size(); @@ -942,67 +942,80 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testPadClearances( ) LSET boardCopperLayers = LSET::AllCuMask( m_board->GetCopperLayerCount() ); - for( FOOTPRINT* footprint : m_board->Footprints() ) - { - for( PAD* pad : footprint->Pads() ) - { - for( PCB_LAYER_ID layer : LSET( pad->GetLayerSet() & boardCopperLayers ).Seq() ) + std::future retn = tp.submit( + [&]() { - std::shared_ptr padShape = pad->GetEffectiveShape( layer ); - - m_board->m_CopperItemRTreeCache->QueryColliding( pad, layer, layer, - // Filter: - [&]( BOARD_ITEM* other ) -> bool - { - BOARD_ITEM* a = pad; - BOARD_ITEM* b = other; - - // store canonical order so we don't collide in both directions - // (a:b and b:a) - if( static_cast( a ) > static_cast( b ) ) - std::swap( a, b ); - - if( checkedPairs.find( { a, b } ) != checkedPairs.end() ) - { - return false; - } - else - { - checkedPairs[ { a, b } ] = 1; - return true; - } - }, - // Visitor - [&]( BOARD_ITEM* other ) -> bool - { - return testPadAgainstItem( pad, padShape.get(), layer, other ); - }, - m_board->m_DRCMaxClearance ); - - for( ZONE* zone : m_board->m_DRCCopperZones ) + for( FOOTPRINT* footprint : m_board->Footprints() ) { - testItemAgainstZone( pad, zone, layer ); + for( PAD* pad : footprint->Pads() ) + { + for( PCB_LAYER_ID layer : LSET( pad->GetLayerSet() & boardCopperLayers ).Seq() ) + { + if( m_drcEngine->IsCancelled() ) + return; - if( m_drcEngine->IsCancelled() ) - return; + std::shared_ptr padShape = pad->GetEffectiveShape( layer ); + + m_board->m_CopperItemRTreeCache->QueryColliding( pad, layer, layer, + // Filter: + [&]( BOARD_ITEM* other ) -> bool + { + BOARD_ITEM* a = pad; + BOARD_ITEM* b = other; + + // store canonical order so we don't collide in both + // directions (a:b and b:a) + if( static_cast( a ) > static_cast( b ) ) + std::swap( a, b ); + + if( checkedPairs.find( { a, b } ) != checkedPairs.end() ) + { + return false; + } + else + { + checkedPairs[ { a, b } ] = 1; + return true; + } + }, + // Visitor + [&]( BOARD_ITEM* other ) -> bool + { + testPadAgainstItem( pad, padShape.get(), layer, other ); + + return !m_drcEngine->IsCancelled(); + }, + m_board->m_DRCMaxClearance ); + + for( ZONE* zone : m_board->m_DRCCopperZones ) + { + testItemAgainstZone( pad, zone, layer ); + + if( m_drcEngine->IsCancelled() ) + return; + } + } + + done.fetch_add( 1 ); + } } - } + } ); - if( !reportProgress( ii++, (int) count, progressDelta ) ) - return; - } + std::future_status status = retn.wait_for( std::chrono::milliseconds( 250 ) ); - if( m_drcEngine->IsCancelled() ) - return; + while( status != std::future_status::ready ) + { + m_drcEngine->ReportProgress( static_cast( done ) / count ); + status = retn.wait_for( std::chrono::milliseconds( 250 ) ); } } void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( ) { - const int progressDelta = 100; - size_t count = m_board->Drawings().size(); - int ii = 0; + thread_pool& tp = GetKiCadThreadPool(); + size_t count = m_board->Drawings().size(); + std::atomic done( 1 ); for( FOOTPRINT* footprint : m_board->Footprints() ) count += footprint->GraphicalItems().size(); @@ -1110,53 +1123,65 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testGraphicClearances( ) m_board->m_DRCMaxClearance ); }; - for( BOARD_ITEM* item : m_board->Drawings() ) + std::future retn = tp.submit( + [&]() + { + for( BOARD_ITEM* item : m_board->Drawings() ) + { + testGraphicAgainstZone( item ); + + if( item->Type() == PCB_SHAPE_T && item->IsOnCopperLayer() ) + testCopperGraphic( static_cast( item ) ); + + done.fetch_add( 1 ); + + if( m_drcEngine->IsCancelled() ) + break; + } + + for( FOOTPRINT* footprint : m_board->Footprints() ) + { + for( BOARD_ITEM* item : footprint->GraphicalItems() ) + { + testGraphicAgainstZone( item ); + + done.fetch_add( 1 ); + + if( m_drcEngine->IsCancelled() ) + break; + } + } + } ); + + std::future_status status = retn.wait_for( std::chrono::milliseconds( 250 ) ); + + while( status != std::future_status::ready ) { - testGraphicAgainstZone( item ); - - if( item->Type() == PCB_SHAPE_T && item->IsOnCopperLayer() ) - testCopperGraphic( static_cast( item ) ); - - if( !reportProgress( ii++, (int) count, progressDelta ) ) - return; - } - - for( FOOTPRINT* footprint : m_board->Footprints() ) - { - for( BOARD_ITEM* item : footprint->GraphicalItems() ) - { - testGraphicAgainstZone( item ); - - if( !reportProgress( ii++, (int) count, progressDelta ) ) - return; - } + m_drcEngine->ReportProgress( static_cast( done ) / count ); + status = retn.wait_for( std::chrono::milliseconds( 250 ) ); } } void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() { - const int progressDelta = 50; + bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ); + bool testIntersects = !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT ); + DRC_CONSTRAINT constraint; - bool testClearance = !m_drcEngine->IsErrorLimitExceeded( DRCE_CLEARANCE ); - bool testIntersects = !m_drcEngine->IsErrorLimitExceeded( DRCE_ZONES_INTERSECT ); - - DRC_CONSTRAINT constraint; - bool cancelled = false; std::vector>> poly_segments; - poly_segments.resize( m_board->m_DRCCopperZones.size() ); // Contains the index for zoneA, zoneB, the conflict point, the actual clearance, the // required clearance, and the layer using report_data = std::tuple; - const int invalid_zone = -1; std::vector> futures; - thread_pool& tp = GetKiCadThreadPool(); + thread_pool& tp = GetKiCadThreadPool(); + std::atomic done( 1 ); 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 { // Iterate through all the segments of refSmoothedPoly @@ -1165,8 +1190,7 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() std::vector& refSegments = poly_segments[zoneA][layer]; std::vector& testSegments = poly_segments[zoneB][layer]; bool reported = false; - auto invalid_result = std::make_tuple( invalid_zone, invalid_zone, VECTOR2I(), - 0, 0, F_Cu ); + auto invalid_result = std::make_tuple( -1, -1, VECTOR2I(), 0, 0, F_Cu ); for( SEG& refSegment : refSegments ) { @@ -1204,14 +1228,18 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() reported = true; if( reported ) + { + done.fetch_add( 1 ); return std::make_tuple( zoneA, zoneB, pt, d, clearance, layer ); + } } - if( cancelled ) + if( m_drcEngine->IsCancelled() ) return invalid_result; } } + done.fetch_add( 1 ); return invalid_result; }; @@ -1229,10 +1257,10 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() if( m_board->m_DRCCopperZones[ii]->IsOnLayer( layer ) ) { SHAPE_POLY_SET poly = *m_board->m_DRCCopperZones[ii]->GetFilledPolysList( layer ); - std::vector& poly_segs = poly_segments[ii][layer]; + std::vector& zone_layer_poly_segs = poly_segments[ii][layer]; poly.BuildBBoxCaches(); - poly_segs.reserve( poly.FullPointCount() ); + zone_layer_poly_segs.reserve( poly.FullPointCount() ); 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 ) 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++ ) { - 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]; if( !zoneA->IsOnLayer( layer ) ) @@ -1298,6 +1320,8 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() } } + size_t count = futures.size(); + for( auto& task : futures ) { if( !task.valid() ) @@ -1307,28 +1331,27 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() while( true ) { - result = task.wait_for( std::chrono::milliseconds( 200 ) ); + result = task.wait_for( std::chrono::milliseconds( 250 ) ); + + m_drcEngine->ReportProgress( static_cast( done ) / count ); if( m_drcEngine->IsCancelled() ) - { - cancelled = true; break; - } if( result == std::future_status::ready ) { - report_data data = task.get(); - int zoneA_id = std::get<0>( data ); - int zoneB_id = std::get<1>( data ); - VECTOR2I pt = std::get<2>( data ); - int actual = std::get<3>( data ); - int required = std::get<4>( data ); + report_data data = task.get(); + int zoneA_idx = std::get<0>( data ); + int zoneB_idx = std::get<1>( data ); + VECTOR2I pt = std::get<2>( data ); + int actual = std::get<3>( data ); + int required = std::get<4>( 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* zoneB = m_board->m_DRCCopperZones[zoneB_id]; + ZONE* zoneA = m_board->m_DRCCopperZones[zoneA_idx]; + ZONE* zoneB = m_board->m_DRCCopperZones[zoneB_idx]; constraint = m_drcEngine->EvalRules( CLEARANCE_CONSTRAINT, zoneA, zoneB, layer ); std::shared_ptr drce; @@ -1359,7 +1382,6 @@ void DRC_TEST_PROVIDER_COPPER_CLEARANCE::testZonesToZones() break; } - } } }