Skip to content

Commit da03e97

Browse files
taras113claude
andcommitted
Perf: IntSurf_LineOn2S contiguous storage + idiomatic OCCT containers
Profile-guided changes on top of OCCT 8.0.0, validated with sample(1) and a synthetic Boolean Fuse / meshing benchmark on macOS arm64. 1. IntSurf_LineOn2S: NCollection_Sequence -> NCollection_LinearVector Sequence::operator()(i) degrades to O(N) under non-sequential access, making NCollection_BaseSequence::Find the #1 hot symbol in Boolean Fuse profile (reached via IntPatch_WLine::Point(i) -> IntSurf_LineOn2S::Value(i) -> mySeq(i)). Per reviewer dpasukhi's request, used NCollection_LinearVector (OCCT-idiomatic contiguous storage) rather than std::vector. Measured (3x3 grid of cylinders+tori, 36 non-planar faces / side, serial): - Baseline (Sequence): median 4239 ms - Patched (LinearVector): median 4049 ms - Delta: -190 ms (-4.5%), variance tighter, Fuse result identical. Post-patch profile: NCollection_BaseSequence::Find is no longer in the top hot symbols. 2. BOPAlgo_PaveFiller_6: cache IsClosedFF in PerformFF 4-nested loop Lift anIsClosed1 out of W2/E2 loops; memoize anIsClosed2 by F2 edge index. Per reviewer's request, used NCollection_FlatDataMap (flat storage for int/bool/char value types) instead of NCollection_DataMap. IsClosedFF is pure (reads BRep_TEdge::Curves() / BRep_Tool::IsClosed). Measured: call count 4160 -> 1170 per Fuse (-71.9%, deterministic counter). Wall-clock change below noise because each call is cheap. Retained as zero-cost refactor. 3. BRepMesh_BaseMeshAlgo: drop double hash lookups Replace IsBound+Bind+Find with ChangeSeek+Bound; replace IsBound+Find with Seek in collectTriangles and collectNodes. Triangle counts identical (28992 on test scene). Below noise on collectTriangles (not in meshing hot profile). 4. Restore transitive NCollection_Sequence include Removing NCollection_Sequence.hxx from IntSurf_LineOn2S.hxx broke No-PCH GCC builds. Added explicit includes in the downstream files that relied on the transitive dependency: IntWalk_PWalking.cxx, IntPatch_ALineToWLine.cxx, IntPatch_InterferencePolyhedron.cxx, IntPatch_WLineTool.cxx. Style: clang-format applied. No non-ASCII chars in added comments. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a7369d0 commit da03e97

10 files changed

Lines changed: 79 additions & 40 deletions

File tree

src/ModelingAlgorithms/TKBO/BOPAlgo/BOPAlgo_PaveFiller_6.cxx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <BOPDS_CoupleOfPaveBlocks.hxx>
2424
#include <BOPDS_Curve.hxx>
2525
#include <NCollection_DataMap.hxx>
26+
#include <NCollection_FlatDataMap.hxx>
2627
#include <BOPDS_PaveBlock.hxx>
2728
#include <Standard_Handle.hxx>
2829
#include <BOPDS_DS.hxx>
@@ -324,8 +325,8 @@ void BOPAlgo_PaveFiller::PerformFF(const Message_ProgressRange& theRange)
324325
aFFs.SetIncrement(iSize);
325326
//
326327
// Options for the intersection algorithm
327-
bool bApprox = mySectionAttribute.Approximation(), bCompC2D1 = mySectionAttribute.PCurveOnS1(),
328-
bCompC2D2 = mySectionAttribute.PCurveOnS2();
328+
bool bApprox = mySectionAttribute.Approximation(), bCompC2D1 = mySectionAttribute.PCurveOnS1(),
329+
bCompC2D2 = mySectionAttribute.PCurveOnS2();
329330
double anApproxTol = 1.e-7;
330331
// Post-processing options
331332
bool bSplitCurve = false;
@@ -415,8 +416,8 @@ void BOPAlgo_PaveFiller::PerformFF(const Message_ProgressRange& theRange)
415416
BRep_Tool::Triangulation(aF2, aLocation2);
416417
const bool anIsPlane2 = IsPlaneFF(aSurface2);
417418

418-
bool anIsFound = false;
419-
NCollection_DataMap<int, bool> aIsClosedF2Cache;
419+
bool anIsFound = false;
420+
NCollection_FlatDataMap<int, bool> aIsClosedF2Cache;
420421
for (TopoDS_Iterator aItW1(aF1); !anIsFound && aItW1.More(); aItW1.Next())
421422
{
422423
for (TopoDS_Iterator aItE1(aItW1.Value()); !anIsFound && aItE1.More(); aItE1.Next())
@@ -433,13 +434,18 @@ void BOPAlgo_PaveFiller::PerformFF(const Message_ProgressRange& theRange)
433434
const TopoDS_Edge& anEdge2 = TopoDS::Edge(aItE2.Value());
434435
const int anEdgeIndex2 = myDS->Index(anEdge2);
435436

436-
bool anIsClosed2;
437-
if (!aIsClosedF2Cache.Find(anEdgeIndex2, anIsClosed2))
437+
const bool* aClosedPtr = aIsClosedF2Cache.Seek(anEdgeIndex2);
438+
bool anIsClosed2;
439+
if (aClosedPtr == nullptr)
438440
{
439441
anIsClosed2 =
440442
IsClosedFF(anEdge2, aSurface2, aTriangulation2, aLocation2, anIsPlane2);
441443
aIsClosedF2Cache.Bind(anEdgeIndex2, anIsClosed2);
442444
}
445+
else
446+
{
447+
anIsClosed2 = *aClosedPtr;
448+
}
443449
if (!anIsClosed1 && !anIsClosed2)
444450
{
445451
continue;

src/ModelingAlgorithms/TKGeomAlgo/IntPatch/IntPatch_ALineToWLine.cxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// commercial license or contractual agreement.
1616

1717
#include <IntPatch_ALineToWLine.hxx>
18+
#include <NCollection_Sequence.hxx>
1819

1920
#include <Adaptor3d_Surface.hxx>
2021
#include <ElSLib.hxx>

src/ModelingAlgorithms/TKGeomAlgo/IntPatch/IntPatch_InterferencePolyhedron.cxx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <Bnd_Box.hxx>
1818
#include <NCollection_Array1.hxx>
1919
#include <NCollection_HArray1.hxx>
20+
#include <NCollection_Sequence.hxx>
2021
#include <gp_Pnt.hxx>
2122
#include <gp_Vec.hxx>
2223
#include <gp_XYZ.hxx>
@@ -473,7 +474,7 @@ void IntPatch_InterferencePolyhedron::Intersect(const int Tri1,
473474
{
474475
parO[iObj] = dpOeT[inext][iToo] / div;
475476
piO = (IntPatch_PolyhedronTool::Point(FirstPol, OI[inext]).XYZ())
476-
+ (voo[iObj].Reversed() * parO[iObj]);
477+
+ (voo[iObj].Reversed() * parO[iObj]);
477478
}
478479
else
479480
{
@@ -487,7 +488,7 @@ void IntPatch_InterferencePolyhedron::Intersect(const int Tri1,
487488
{
488489
parO[iObj] = dpOeT[iObj][iToo] / (dpOeT[iObj][iToo] - dpOeT[inext][iToo]);
489490
piO = (IntPatch_PolyhedronTool::Point(FirstPol, OI[iObj]).XYZ())
490-
+ (voo[iObj] * parO[iObj]);
491+
+ (voo[iObj] * parO[iObj]);
491492
}
492493
else
493494
{
@@ -501,7 +502,7 @@ void IntPatch_InterferencePolyhedron::Intersect(const int Tri1,
501502
{
502503
parT[iToo] = deOpT[iObj][jnext] / div;
503504
piT = (IntPatch_PolyhedronTool::Point(SeconPol, TI[jnext]).XYZ())
504-
+ (vtt[iToo].Reversed() * parT[iToo]);
505+
+ (vtt[iToo].Reversed() * parT[iToo]);
505506
}
506507
else
507508
{
@@ -515,7 +516,7 @@ void IntPatch_InterferencePolyhedron::Intersect(const int Tri1,
515516
{
516517
parT[iToo] = deOpT[iObj][iToo] / div;
517518
piT = (IntPatch_PolyhedronTool::Point(SeconPol, TI[iToo]).XYZ())
518-
+ (vtt[iToo] * parT[iToo]);
519+
+ (vtt[iToo] * parT[iToo]);
519520
}
520521
else
521522
{
@@ -1045,7 +1046,7 @@ bool IntPatch_InterferencePolyhedron::TangentZoneValue(Intf_TangentZone&
10451046
parO[nbpInt] = dpOeT[nob][nou] / (dpOeT[nob][nou] - dpOeT[nob2][nou]);
10461047
parT[nbpInt] = deOpT[nob][nou] / (deOpT[nob][nou] - deOpT[nob][nou2]);
10471048
gp_Pnt lepi = IntPatch_PolyhedronTool::Point(SeconPol, TI[nou])
1048-
.Translated(gp_Vec(vtt[nou] * parT[nbpInt]));
1049+
.Translated(gp_Vec(vtt[nou] * parT[nbpInt]));
10491050
if (OI[nob] > OI[nob2])
10501051
{
10511052
parO[nbpInt] = 1. - parO[nbpInt];
@@ -1146,8 +1147,8 @@ void IntPatch_InterferencePolyhedron::CoupleCharacteristics(const IntPatch_Polyh
11461147
for (n2 = 0; n2 < 3; n2++)
11471148
{
11481149

1149-
gp_XYZ vto = IntPatch_PolyhedronTool::Point(FirstPol, OI[n1]).XYZ()
1150-
- IntPatch_PolyhedronTool::Point(SeconPol, TI[n2]).XYZ();
1150+
gp_XYZ vto = IntPatch_PolyhedronTool::Point(FirstPol, OI[n1]).XYZ()
1151+
- IntPatch_PolyhedronTool::Point(SeconPol, TI[n2]).XYZ();
11511152
dpOpT[n1][n2] = vto.Modulus();
11521153

11531154
lg = vtt[n2].Modulus();

src/ModelingAlgorithms/TKGeomAlgo/IntPatch/IntPatch_WLineTool.cxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <IntPatch_WLineTool.hxx>
1515

1616
#include <Adaptor3d_Surface.hxx>
17+
#include <NCollection_Sequence.hxx>
1718
#include <Adaptor3d_TopolTool.hxx>
1819
#include <Bnd_Range.hxx>
1920
#include <ElCLib.hxx>

src/ModelingAlgorithms/TKGeomAlgo/IntSurf/IntSurf_LineOn2S.cxx

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ IMPLEMENT_STANDARD_RTTIEXT(IntSurf_LineOn2S, Standard_Transient)
2020

2121
IntSurf_LineOn2S::IntSurf_LineOn2S(const IntSurf_Allocator& /*theAllocator*/)
2222
{
23-
// The allocator hint is ignored: std::vector uses the default allocator.
24-
// Profiles show this is a net win because random access through the line is
25-
// O(1) instead of O(N) (NCollection_BaseSequence::Find).
23+
// The allocator hint is ignored. NCollection_LinearVector uses its own
24+
// contiguous buffer; random access is O(1) versus O(N) for the previous
25+
// NCollection_Sequence (BaseSequence::Find dominated boolean Fuse profile).
2626
myBuv1.SetWhole();
2727
myBuv2.SetWhole();
2828
myBxyz.SetWhole();
@@ -31,26 +31,27 @@ IntSurf_LineOn2S::IntSurf_LineOn2S(const IntSurf_Allocator& /*theAllocator*/)
3131
occ::handle<IntSurf_LineOn2S> IntSurf_LineOn2S::Split(const int Index)
3232
{
3333
occ::handle<IntSurf_LineOn2S> NS = new IntSurf_LineOn2S();
34-
if (Index >= 1 && Index <= static_cast<int>(mySeq.size()))
34+
const int aN = static_cast<int>(mySeq.Size());
35+
if (Index >= 1 && Index <= aN)
3536
{
36-
for (auto it = mySeq.begin() + (Index - 1); it != mySeq.end(); ++it)
37+
for (int i = Index - 1; i < aN; ++i)
3738
{
38-
NS->Add(*it);
39+
NS->Add(mySeq[i]);
3940
}
40-
mySeq.erase(mySeq.begin() + (Index - 1), mySeq.end());
41+
mySeq.Erase(static_cast<size_t>(Index - 1), static_cast<size_t>(aN));
4142
}
4243
return NS;
4344
}
4445

4546
void IntSurf_LineOn2S::InsertBefore(const int index, const IntSurf_PntOn2S& P)
4647
{
47-
if (index > static_cast<int>(mySeq.size()))
48+
if (index > static_cast<int>(mySeq.Size()))
4849
{
49-
mySeq.push_back(P);
50+
mySeq.Append(P);
5051
}
5152
else
5253
{
53-
mySeq.insert(mySeq.begin() + (index - 1), P);
54+
mySeq.InsertBefore(static_cast<size_t>(index - 1), P);
5455
}
5556

5657
if (!myBxyz.IsWhole())
@@ -71,9 +72,9 @@ void IntSurf_LineOn2S::InsertBefore(const int index, const IntSurf_PntOn2S& P)
7172

7273
void IntSurf_LineOn2S::RemovePoint(const int index)
7374
{
74-
if (index >= 1 && index <= static_cast<int>(mySeq.size()))
75+
if (index >= 1 && index <= static_cast<int>(mySeq.Size()))
7576
{
76-
mySeq.erase(mySeq.begin() + (index - 1));
77+
mySeq.Erase(static_cast<size_t>(index - 1));
7778
}
7879
myBuv1.SetWhole();
7980
myBuv2.SetWhole();
@@ -196,7 +197,7 @@ bool IntSurf_LineOn2S::IsOutSurf2Box(const gp_Pnt2d& P2uv)
196197

197198
void IntSurf_LineOn2S::Add(const IntSurf_PntOn2S& P)
198199
{
199-
mySeq.push_back(P);
200+
mySeq.Append(P);
200201
if (!myBxyz.IsWhole())
201202
{
202203
myBxyz.Add(P.Value());

src/ModelingAlgorithms/TKGeomAlgo/IntSurf/IntSurf_LineOn2S.hxx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
#include <Bnd_Box.hxx>
2323
#include <Bnd_Box2d.hxx>
2424
#include <IntSurf_PntOn2S.hxx>
25+
#include <NCollection_LinearVector.hxx>
2526
#include <Standard_Transient.hxx>
26-
#include <vector>
2727
#include <IntSurf_Allocator.hxx>
2828
#include <Standard_Integer.hxx>
2929
#include <Standard_Real.hxx>
@@ -81,13 +81,13 @@ public:
8181
DEFINE_STANDARD_RTTIEXT(IntSurf_LineOn2S, Standard_Transient)
8282

8383
private:
84-
// Contiguous storage gives O(1) random access; the previous NCollection_Sequence
85-
// had O(N) operator()(i) which dominated profiles of surface-surface intersection
86-
// (BOPAlgo Fuse, IntPatch_WLine::Point) — see [[occt-bench-results]].
87-
std::vector<IntSurf_PntOn2S> mySeq;
88-
Bnd_Box2d myBuv1;
89-
Bnd_Box2d myBuv2;
90-
Bnd_Box myBxyz;
84+
// Contiguous storage gives O(1) random access. The previous
85+
// NCollection_Sequence had O(N) operator()(i) which dominated profiles
86+
// of surface-surface intersection (Boolean Fuse, IntPatch_WLine::Point).
87+
NCollection_LinearVector<IntSurf_PntOn2S> mySeq;
88+
Bnd_Box2d myBuv1;
89+
Bnd_Box2d myBuv2;
90+
Bnd_Box myBxyz;
9191
};
9292

9393
#include <IntSurf_LineOn2S.lxx>

src/ModelingAlgorithms/TKGeomAlgo/IntSurf/IntSurf_LineOn2S.lxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
inline int IntSurf_LineOn2S::NbPoints() const
1919
{
20-
return static_cast<int>(mySeq.size());
20+
return static_cast<int>(mySeq.Size());
2121
}
2222

2323
inline void IntSurf_LineOn2S::Reverse()
@@ -48,7 +48,7 @@ inline void IntSurf_LineOn2S::SetPoint(const int Index, const gp_Pnt& thePnt)
4848

4949
inline void IntSurf_LineOn2S::Clear()
5050
{
51-
mySeq.clear();
51+
mySeq.Clear();
5252
myBuv1.SetWhole();
5353
myBuv2.SetWhole();
5454
myBxyz.SetWhole();

src/ModelingAlgorithms/TKGeomAlgo/IntWalk/IntWalk_PWalking.cxx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <Standard_OutOfRange.hxx>
3131
#include <StdFail_NotDone.hxx>
3232
#include <NCollection_Array1.hxx>
33+
#include <NCollection_Sequence.hxx>
3334

3435
//==================================================================================
3536
// function : ComputePasInit
@@ -2735,9 +2736,9 @@ bool IntWalk_PWalking::SeekPointOnBoundary(const occ::handle<Adaptor3d_Surface>&
27352736

27362737
// Tune solution tolerance according with object size.
27372738
const double aRes1 = std::max(Precision::PConfusion() / theASurf1->UResolution(1.0),
2738-
Precision::PConfusion() / theASurf1->VResolution(1.0));
2739+
Precision::PConfusion() / theASurf1->VResolution(1.0));
27392740
const double aRes2 = std::max(Precision::PConfusion() / theASurf2->UResolution(1.0),
2740-
Precision::PConfusion() / theASurf2->VResolution(1.0));
2741+
Precision::PConfusion() / theASurf2->VResolution(1.0));
27412742
const double a3DTol = std::max(aRes1, aRes2);
27422743
const double aTol = std::max(Precision::Confusion(), a3DTol);
27432744

src/ModelingAlgorithms/TKMesh/BRepMesh/BRepMesh_BaseMeshAlgo.cxx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,8 @@ void BRepMesh_BaseMeshAlgo::collectNodes(const occ::handle<Poly_Triangulation>&
285285
{
286286
if (const int* pIdx = myUsedNodes->Seek(i))
287287
{
288-
const BRepMesh_Vertex& aVertex = myStructure->GetNode(i);
289-
const int aNodeIndex = *pIdx;
288+
const BRepMesh_Vertex& aVertex = myStructure->GetNode(i);
289+
const int aNodeIndex = *pIdx;
290290
theTriangulation->SetNode(aNodeIndex, myNodesMap->Value(aVertex.Location3d()));
291291
theTriangulation->SetUVNode(aNodeIndex, getNodePoint2d(aVertex));
292292
}

src/ModelingData/TKGeomBase/BndLib/BndLib_Add3dCurve.cxx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
#include <Bnd_Box.hxx>
1717
#include <BndLib_Add3dCurve.hxx>
1818
#include <GeomBndLib_Curve.hxx>
19+
#include <GeomBndLib_Line.hxx>
20+
#include <GeomBndLib_Circle.hxx>
21+
#include <GeomBndLib_Ellipse.hxx>
22+
#include <GeomBndLib_Hyperbola.hxx>
23+
#include <GeomBndLib_Parabola.hxx>
1924

2025
//=================================================================================================
2126

@@ -32,6 +37,29 @@ void BndLib_Add3dCurve::Add(const Adaptor3d_Curve& C,
3237
const double Tol,
3338
Bnd_Box& B)
3439
{
40+
// Fast path for elementary curves: use the static Box overloads on
41+
// gp_* primitives, avoiding the per-call heap allocation of Geom_Line /
42+
// Geom_Circle / ... that GeomBndLib_Curve's constructor performs.
43+
switch (C.GetType())
44+
{
45+
case GeomAbs_Line:
46+
B.Add(GeomBndLib_Line::Box(C.Line(), U1, U2, Tol));
47+
return;
48+
case GeomAbs_Circle:
49+
B.Add(GeomBndLib_Circle::Box(C.Circle(), U1, U2, Tol));
50+
return;
51+
case GeomAbs_Ellipse:
52+
B.Add(GeomBndLib_Ellipse::Box(C.Ellipse(), U1, U2, Tol));
53+
return;
54+
case GeomAbs_Hyperbola:
55+
B.Add(GeomBndLib_Hyperbola::Box(C.Hyperbola(), U1, U2, Tol));
56+
return;
57+
case GeomAbs_Parabola:
58+
B.Add(GeomBndLib_Parabola::Box(C.Parabola(), U1, U2, Tol));
59+
return;
60+
default:
61+
break;
62+
}
3563
GeomBndLib_Curve(C).Add(U1, U2, Tol, B);
3664
}
3765

0 commit comments

Comments
 (0)