From bf445c1a95e8c155d93417e177c47b6e9e3a2edb Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Sat, 25 Jul 2020 12:58:17 +0100 Subject: [PATCH] Performance enhancements. 1) cache pad polygon outlines huge improvement in connectivity performance and a decent improvement in DRC performance 2) don't pre-allocate CONTEXT stack significant improvement in DRC rule performance 2) don't keep re-encoding strings decent improvement in DRC rule performance --- .../3d_canvas/create_3Dgraphic_brd_items.cpp | 6 +- 3d-viewer/3d_canvas/create_layer_poly.cpp | 6 +- common/libeval_compiler/libeval_compiler.cpp | 2 +- include/libeval_compiler/libeval_compiler.h | 60 +++++++++--------- pcbnew/class_pad.cpp | 62 +++++++++---------- pcbnew/class_pad.h | 9 +-- pcbnew/connectivity/connectivity_algo.cpp | 4 +- pcbnew/connectivity/connectivity_items.cpp | 14 +++-- pcbnew/drc/drc_keepout_tester.cpp | 3 +- pcbnew/pcb_expr_evaluator.cpp | 2 +- pcbnew/plot_brditems_plotter.cpp | 13 ++-- pcbnew/router/pns_kicad_iface.cpp | 8 +-- .../drc_test_provider_copper_clearance.cpp | 8 +-- qa/libeval_compiler/libeval_compiler_test.cpp | 2 +- 14 files changed, 95 insertions(+), 104 deletions(-) diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp index 39ce3a1b4b..011b70d4f7 100644 --- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp +++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp @@ -817,10 +817,8 @@ void BOARD_ADAPTER::buildPadShapeThickOutlineAsSegments( const D_PAD* aPad, } // For other shapes, add outlines as thick segments in polygon buffer - SHAPE_POLY_SET corners; - aPad->TransformShapeWithClearanceToPolygon( corners, 0 ); - - const SHAPE_LINE_CHAIN& path = corners.COutline( 0 ); + const std::shared_ptr& corners = aPad->GetEffectivePolygon(); + const SHAPE_LINE_CHAIN& path = corners->COutline( 0 ); for( int j = 0; j < path.PointCount(); j++ ) { diff --git a/3d-viewer/3d_canvas/create_layer_poly.cpp b/3d-viewer/3d_canvas/create_layer_poly.cpp index b0e9cd7f8e..ab146c375e 100644 --- a/3d-viewer/3d_canvas/create_layer_poly.cpp +++ b/3d-viewer/3d_canvas/create_layer_poly.cpp @@ -46,10 +46,8 @@ void BOARD_ADAPTER::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad, } // For other shapes, add outlines as thick segments in polygon buffer - SHAPE_POLY_SET corners; - aPad->TransformShapeWithClearanceToPolygon( corners, 0 ); - - const SHAPE_LINE_CHAIN& path = corners.COutline( 0 ); + const std::shared_ptr& corners = aPad->GetEffectivePolygon(); + const SHAPE_LINE_CHAIN& path = corners->COutline( 0 ); for( int ii = 0; ii < path.PointCount(); ++ii ) { diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp index 3c6b934feb..008b3aeae3 100644 --- a/common/libeval_compiler/libeval_compiler.cpp +++ b/common/libeval_compiler/libeval_compiler.cpp @@ -108,7 +108,7 @@ std::string UOP::Format() const else if( val->GetType() == VT_NUMERIC ) snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH NUM [%.10f]", val->AsDouble() ); else - snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH STR [%s]", val->AsString().c_str() ); + snprintf( str, LIBEVAL_MAX_LITERAL_LENGTH, "PUSH STR [%s]", val->AsChars() ); } break; diff --git a/include/libeval_compiler/libeval_compiler.h b/include/libeval_compiler/libeval_compiler.h index 2d31990f92..d1a098c799 100644 --- a/include/libeval_compiler/libeval_compiler.h +++ b/include/libeval_compiler/libeval_compiler.h @@ -23,8 +23,8 @@ #include #include -#include #include +#include #include @@ -81,12 +81,12 @@ enum VAR_TYPE_T enum TOKEN_TYPE_T { - TR_NUMBER = 1, + TR_NUMBER = 1, TR_IDENTIFIER = 2, TR_ASSIGN = 3, TR_STRUCT_REF = 4, TR_STRING = 5, - TR_UNIT = 6 + TR_UNIT = 6 }; #define LIBEVAL_MAX_LITERAL_LENGTH 1024 @@ -175,10 +175,10 @@ public: m_valueDbl( 0 ) {}; - VALUE( std::string aStr ) : + VALUE( const wxString& aStr ) : m_type( VT_STRING ), m_valueDbl( 0 ), - m_valueStr( std::move( aStr ) ) + m_valueStr( aStr ) {}; VALUE( const double aVal ) : @@ -191,11 +191,16 @@ public: return m_valueDbl; } - const std::string& AsString() const + const wxString& AsString() const { return m_valueStr; } + const char* AsChars() const + { + return m_valueStr.ToStdString().c_str(); + } + bool operator==( const VALUE& b ) const { if( m_type == VT_NUMERIC && b.m_type == VT_NUMERIC ) @@ -214,7 +219,7 @@ public: m_valueDbl = aValue; } - void Set( const std::string& aValue ) + void Set( const wxString& aValue ) { m_type = VT_STRING; m_valueStr = aValue; @@ -237,7 +242,7 @@ public: private: VAR_TYPE_T m_type; double m_valueDbl; - std::string m_valueStr; + wxString m_valueStr; }; @@ -256,48 +261,43 @@ public: class CONTEXT { public: - const int c_memSize = 128; - - CONTEXT() + ~CONTEXT() { - m_sp = 0; - - for( int i = 0; i < c_memSize; i++ ) - m_heap.emplace_back( VALUE() ); + for( VALUE* value : m_ownedValues ) + delete value; } VALUE* AllocValue() { - assert( m_memPos < c_memSize ); - auto rv = &m_heap[ m_memPos++ ]; - return rv; + VALUE* value = new VALUE(); + m_ownedValues.push_back( value ); + return value; } - void Push( VALUE* v ) + void Push( VALUE* v ) { - m_stack[m_sp++] = v; + m_stack.push( v ); } VALUE* Pop() { - m_sp--; - return m_stack[m_sp]; + VALUE* value = m_stack.top(); + m_stack.pop(); + return value; } int SP() const { - return m_sp; + return m_stack.size(); } ERROR_STATUS GetErrorStatus() const { return m_errorStatus; } void ReportError( const wxString& aErrorMsg ); private: - std::vector m_heap; - VALUE* m_stack[128]; - int m_sp = 0; - int m_memPos = 0; - ERROR_STATUS m_errorStatus; + std::vector m_ownedValues; + std::stack m_stack; + ERROR_STATUS m_errorStatus; }; @@ -467,9 +467,9 @@ protected: return uop; } - UOP* makeUop( int op, std::string value ) + UOP* makeUop( int op, const wxString& value ) { - UOP* uop = new UOP( op, new VALUE( std::move( value ) ) ); + UOP* uop = new UOP( op, new VALUE( value ) ); return uop; } diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp index 68e92e5416..ab584eaad2 100644 --- a/pcbnew/class_pad.cpp +++ b/pcbnew/class_pad.cpp @@ -168,27 +168,6 @@ bool D_PAD::IsFlipped() const } -int D_PAD::calcBoundingRadius() const -{ - int radius = 0; - SHAPE_POLY_SET polygons; - TransformShapeWithClearanceToPolygon( polygons, 0 ); - - for( int cnt = 0; cnt < polygons.OutlineCount(); ++cnt ) - { - const SHAPE_LINE_CHAIN& poly = polygons.COutline( cnt ); - - for( int ii = 0; ii < poly.PointCount(); ++ii ) - { - int dist = KiROUND( ( poly.CPoint( ii ) - m_Pos ).EuclideanNorm() ); - radius = std::max( radius, dist ); - } - } - - return radius + 1; -} - - int D_PAD::GetRoundRectCornerRadius() const { return KiROUND( std::min( m_Size.x, m_Size.y ) * m_roundedCornerScale ); @@ -229,6 +208,15 @@ const std::vector>& D_PAD::GetEffectiveShapes() const } +const std::shared_ptr& D_PAD::GetEffectivePolygon() const +{ + if( m_shapesDirty ) + BuildEffectiveShapes(); + + return m_effectivePolygon; +} + + const SHAPE_SEGMENT* D_PAD::GetEffectiveHoleShape() const { if( m_shapesDirty ) @@ -367,9 +355,27 @@ void D_PAD::BuildEffectiveShapes() const } } + // Polygon + // + m_effectivePolygon = std::make_shared(); + TransformShapeWithClearanceToPolygon( *m_effectivePolygon, 0 ); + // Bounding box and radius // - m_effectiveBoundingRadius = calcBoundingRadius(); + m_effectiveBoundingRadius = 0; + + for( int cnt = 0; cnt < m_effectivePolygon->OutlineCount(); ++cnt ) + { + const SHAPE_LINE_CHAIN& poly = m_effectivePolygon->COutline( cnt ); + + for( int ii = 0; ii < poly.PointCount(); ++ii ) + { + int dist = KiROUND( ( poly.CPoint( ii ) - m_Pos ).EuclideanNorm() ); + m_effectiveBoundingRadius = std::max( m_effectiveBoundingRadius, dist ); + } + } + + m_effectiveBoundingRadius += 1; // reset the bbox to uninitialized state to prepare for merging m_effectiveBoundingBox = EDA_RECT(); @@ -798,10 +804,7 @@ bool D_PAD::HitTest( const wxPoint& aPosition, int aAccuracy ) const if( delta.SquaredEuclideanNorm() > SEG::Square( boundingRadius ) ) return false; - SHAPE_POLY_SET polySet; - TransformShapeWithClearanceToPolygon( polySet, aAccuracy ); - - return polySet.Contains( aPosition ); + return GetEffectivePolygon()->Contains( aPosition, -1, aAccuracy ); } @@ -827,12 +830,9 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con selRect.Append( VECTOR2I( arect.GetRight(), arect.GetBottom() ) ); selRect.Append( VECTOR2I( arect.GetLeft(), arect.GetBottom() ) ); - SHAPE_POLY_SET padPoly; - TransformShapeWithClearanceToPolygon( padPoly, aAccuracy ); + selRect.BooleanIntersection( *GetEffectivePolygon(), SHAPE_POLY_SET::PM_FAST ); - selRect.BooleanIntersection( padPoly, SHAPE_POLY_SET::PM_FAST ); - - double padArea = padPoly.Outline( 0 ).Area(); + double padArea = GetEffectivePolygon()->Outline( 0 ).Area(); double intersection = selRect.Outline( 0 ).Area(); if( intersection > ( padArea * 0.99 ) ) diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h index c5253a2c04..f7a3f21c6a 100644 --- a/pcbnew/class_pad.h +++ b/pcbnew/class_pad.h @@ -397,6 +397,8 @@ public: */ const std::vector>& GetEffectiveShapes() const; + const std::shared_ptr& GetEffectivePolygon() const; + /** * Function GetEffectiveHoleShape * Returns a list of SHAPE objects representing the pad's hole. @@ -611,12 +613,6 @@ public: private: - /** - * Function calcBoundingRadius - * returns a calculated radius of a bounding circle for this pad. - */ - int calcBoundingRadius() const; - void addPadPrimitivesToPolygon( SHAPE_POLY_SET* aMergedPolygon, int aError ) const; private: @@ -639,6 +635,7 @@ private: mutable EDA_RECT m_effectiveBoundingBox; mutable std::vector> m_effectiveShapes; mutable std::shared_ptr m_effectiveHoleShape; + mutable std::shared_ptr m_effectivePolygon; /* * How to build the custom shape in zone, to create the clearance area: diff --git a/pcbnew/connectivity/connectivity_algo.cpp b/pcbnew/connectivity/connectivity_algo.cpp index c25d88957e..d75d8796ad 100644 --- a/pcbnew/connectivity/connectivity_algo.cpp +++ b/pcbnew/connectivity/connectivity_algo.cpp @@ -684,8 +684,8 @@ void CN_VISITOR::checkZoneZoneConnection( CN_ZONE* aZoneA, CN_ZONE* aZoneB ) bool CN_VISITOR::operator()( CN_ITEM* aCandidate ) { - const auto parentA = aCandidate->Parent(); - const auto parentB = m_item->Parent(); + const BOARD_CONNECTED_ITEM* parentA = aCandidate->Parent(); + const BOARD_CONNECTED_ITEM* parentB = m_item->Parent(); if( !aCandidate->Valid() || !m_item->Valid() ) return true; diff --git a/pcbnew/connectivity/connectivity_items.cpp b/pcbnew/connectivity/connectivity_items.cpp index 4243b0e4c6..d7337bf19b 100644 --- a/pcbnew/connectivity/connectivity_items.cpp +++ b/pcbnew/connectivity/connectivity_items.cpp @@ -66,6 +66,12 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const switch( pad->GetShape() ) { + case PAD_SHAPE_TRAPEZOID: + // Because the trap delta is applied as +1/2 at one end and -1/2 at the other, + // the midpoint is actually unchanged. Therefore all the cardinal points are + // the same as for a rectangle. + KI_FALLTHROUGH; + case PAD_SHAPE_RECT: case PAD_SHAPE_CIRCLE: case PAD_SHAPE_OVAL: @@ -89,7 +95,6 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const return pt1; - case PAD_SHAPE_TRAPEZOID: case PAD_SHAPE_CUSTOM: { switch( n ) @@ -104,10 +109,9 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const if( pad->GetOrientation() ) RotatePoint( pt1, pad->ShapePos(), pad->GetOrientation() ); - SHAPE_POLY_SET padPolySet; - pad->TransformShapeWithClearanceToPolygon( padPolySet, 0, ARC_LOW_DEF ); - const SHAPE_LINE_CHAIN& padOutline = padPolySet.COutline( 0 ); - SHAPE_LINE_CHAIN::INTERSECTIONS intersections; + const std::shared_ptr& padPolySet = pad->GetEffectivePolygon(); + const SHAPE_LINE_CHAIN& padOutline = padPolySet->COutline( 0 ); + SHAPE_LINE_CHAIN::INTERSECTIONS intersections; padOutline.Intersect( SEG( pt0, pt1 ), intersections ); diff --git a/pcbnew/drc/drc_keepout_tester.cpp b/pcbnew/drc/drc_keepout_tester.cpp index 24329f984f..2a7851657b 100644 --- a/pcbnew/drc/drc_keepout_tester.cpp +++ b/pcbnew/drc/drc_keepout_tester.cpp @@ -227,8 +227,7 @@ bool DRC_KEEPOUT_TESTER::checkPads( MODULE* aModule ) if( ( m_keepoutFlags & DISALLOW_PADS ) > 0 ) { - SHAPE_POLY_SET outline; - pad->TransformShapeWithClearanceToPolygon( outline, 0 ); + SHAPE_POLY_SET outline = *pad->GetEffectivePolygon(); // Build the common area between pad and the keepout area: outline.BooleanIntersection( *m_zone->Outline(), SHAPE_POLY_SET::PM_FAST ); diff --git a/pcbnew/pcb_expr_evaluator.cpp b/pcbnew/pcb_expr_evaluator.cpp index 8c3dadbfed..181d2701a1 100644 --- a/pcbnew/pcb_expr_evaluator.cpp +++ b/pcbnew/pcb_expr_evaluator.cpp @@ -132,7 +132,7 @@ LIBEVAL::VALUE PCB_EXPR_VAR_REF::GetValue( LIBEVAL::CONTEXT* aCtx ) //printf("item %p get enum: '%s'\n", item , (const char*) str.c_str() ); } - return LIBEVAL::VALUE( (const char*) str.c_str() ); + return LIBEVAL::VALUE( str ); } } } diff --git a/pcbnew/plot_brditems_plotter.cpp b/pcbnew/plot_brditems_plotter.cpp index 63fc8bf879..2f25901c65 100644 --- a/pcbnew/plot_brditems_plotter.cpp +++ b/pcbnew/plot_brditems_plotter.cpp @@ -239,14 +239,13 @@ void BRDITEMS_PLOTTER::PlotPad( D_PAD* aPad, COLOR4D aColor, EDA_DRAW_MODE_T aPl case PAD_SHAPE_CHAMFERED_RECT: case PAD_SHAPE_CUSTOM: { - SHAPE_POLY_SET polygons; - aPad->TransformShapeWithClearanceToPolygon( polygons, 0 ); + const std::shared_ptr& polygons = aPad->GetEffectivePolygon(); - if( polygons.OutlineCount() == 0 ) - break; - - m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), &polygons, aPlotMode, - &gbr_metadata ); + if( polygons->OutlineCount() ) + { + m_plotter->FlashPadCustom( shape_pos, aPad->GetSize(), polygons.get(), aPlotMode, + &gbr_metadata ); + } } break; } diff --git a/pcbnew/router/pns_kicad_iface.cpp b/pcbnew/router/pns_kicad_iface.cpp index c2ac68d9dc..4a1bbade19 100644 --- a/pcbnew/router/pns_kicad_iface.cpp +++ b/pcbnew/router/pns_kicad_iface.cpp @@ -634,12 +634,10 @@ std::unique_ptr PNS_KICAD_IFACE_BASE::syncPad( D_PAD* aPad ) // JEY TODO: // TOM TODO: move to SHAPE_COMPOUND... - SHAPE_POLY_SET outline; - aPad->TransformShapeWithClearanceToPolygon( outline, 0 ); + const std::shared_ptr& outline = aPad->GetEffectivePolygon(); + SHAPE_SIMPLE* shape = new SHAPE_SIMPLE(); - SHAPE_SIMPLE* shape = new SHAPE_SIMPLE(); - - for( auto iter = outline.CIterate( 0 ); iter; iter++ ) + for( auto iter = outline->CIterate( 0 ); iter; iter++ ) shape->Append( *iter ); solid->SetShape( shape ); diff --git a/qa/drc_proto/drc_test_provider_copper_clearance.cpp b/qa/drc_proto/drc_test_provider_copper_clearance.cpp index 59711b922d..982842f9b3 100644 --- a/qa/drc_proto/drc_test_provider_copper_clearance.cpp +++ b/qa/drc_proto/drc_test_provider_copper_clearance.cpp @@ -296,11 +296,9 @@ void test::DRC_TEST_PROVIDER_COPPER_CLEARANCE::testCopperDrawItem( BOARD_ITEM* a if( !rect_area.Collide( SEG( shape_pos, shape_pos ), bb_radius ) ) continue; - SHAPE_POLY_SET padOutline; - pad->TransformShapeWithClearanceToPolygon( padOutline, 0 ); - - OPT minSeg; - SEG::ecoord center2center_squared = 0; + const std::shared_ptr& padOutline = pad->GetEffectivePolygon(); + OPT minSeg; + SEG::ecoord center2center_squared = 0; for( const SEG& itemSeg : itemShape ) { diff --git a/qa/libeval_compiler/libeval_compiler_test.cpp b/qa/libeval_compiler/libeval_compiler_test.cpp index 0c3c9890cd..80510f7343 100644 --- a/qa/libeval_compiler/libeval_compiler_test.cpp +++ b/qa/libeval_compiler/libeval_compiler_test.cpp @@ -47,7 +47,7 @@ bool testEvalExpr( const std::string expr, LIBEVAL::VALUE expectedResult, bool e if( expectedResult.GetType() == LIBEVAL::VT_NUMERIC ) printf("result: %s (got %.10f expected: %.10f)\n", ok ? "OK" : "FAIL", result.AsDouble(), expectedResult.AsDouble() ); else - printf("result: %s (got '%s' expected: '%s')\n", ok ? "OK" : "FAIL", result.AsString().c_str(), expectedResult.AsString().c_str() ); + printf("result: %s (got '%s' expected: '%s')\n", ok ? "OK" : "FAIL", result.AsChars(), expectedResult.AsChars() ); if (!ok ) {