BREP File is loading very slow

Forums: 

Hi,

is there any way to evaluate why a brep file is loading very slow?
Any recommended way to analyse what's going on and where to look at?

I have a 6mb file here which is loading around 1 minute, if I load the same object from an iges file it loads within a few seconds.

following is the test code:

int main(int argc, char *argv[]) {
TopoDS_Shape s;
BRep_Builder b;
std::ifstream is;
is.open(argv[1]);
BRepTools::Read(s, is, b);
is.close();
return 0;
}

It would be nice to have a general rule of thumb what can be done (what can be checked) in such a case to improve the performance.

aside of that is BRepTools::Read thread safe / reentrant?

Kirill Gavrilov's picture

I have a 6mb file here which is loading around 1 minute.

If you'll share the file, it would be possible to reproduce scenario and see what happens.

what can be done (what can be checked) in such a case to improve the performance.

Reading ASCII file formats in general has penalty due to expensive text parsing. Moreover, it may considerably flow depending on compiler / STL implementation. If I recall correctly, we've seen a noticeable slowdown in some operations within VS2010 -> VS2013+ movement.

Is there is some specific reason for using ASCII format? You may use a binary persistence for TopoDS_Shape with help of BinTools::Write() / BinTools::Read().

is BRepTools::Read thread safe / reentrant?

It should be safe using BRepTools::Read() from different threads for different files, if that is what you asking. If you see experience problems here - then it should be a bug.

Markus R.'s picture

I'm using freecad and text based is how it's implemented right now. The brep text files are stored inside the FCStd zip file.

-rw-r--r-- 1 mr wheel 3.7M Nov 20 10:31 test4.bin (the binary file is bigger than the text file?)
-rw-r--r-- 1 mr wheel 3.4M Nov 20 10:31 test4.brp

time ./load test4.bin
./load test4.bin 45.03s user 0.45s system 94% cpu 48.062 total

time ./load test4.brp
./load test4.brp 46.25s user 0.58s system 91% cpu 51.364 total

I'm using MacOS
Apple clang version 12.0.0 (clang-1200.0.32.29)

OpenCascade 7.5 is used.

head of the bin file:
Open CASCADE Topology V3 (c)
Locations 3018
(followed by binary data)

TopoDS_Shape s;
BRep_Builder b;
std::ifstream is;
is.open(argv[1]);
BinTools::Read(s, is);

Sharing the file is not really possible, but I can give remove access to that system?

Thank you for all that information!

Kirill Gavrilov's picture

(the binary file is bigger than the text file?)

Binary format stores numbers aligned, so that integer takes 4 bytes and double takes 8 bytes nevertheless of what number is written. In ASCII format numbers are written formatted, with limited precision and potentially more compact - e.g. "0" might take just 1+1 bytes, which is smaller than 8 bytes. So yes, in some cases binary file might be larger in size, though this is uncommon.

std::ifstream is;
is.open(argv[1]);
BinTools::Read(s, is);

Binary files are expected to be opened in binary mode, though it shouldn't make much difference in performance.

Sharing the file is not really possible

If sharing a sample is not possible, then the only thing I may suggest is to perform profiling and identify hot spots in OCCT reader. On Windows you may build OCCT in Release mode with Debug symbols and use Visual Studio profile; I guess XCode provides something similar.

If you have access to other systems - it might be interesting to measure times on Linux / Windows to see if there is noticeable difference on this particular use case. Are you running your tests on Intel or Apple M1? In the latter case - FreeCAD / OCCT are built for ARM64 or running through Rosetta translator?

Markus R.'s picture

Hi,

I am using a Macbook Pro from 2012, I can probably also test it on an Apple M1 next week.

> Binary files are expected to be opened in binary mode

I opened it in binary mode ios::binary, it made no difference.

I also have linux here, I will try with the latest OCCT library version on linux next week, I can also do some profiling with it and show the results here.
The tests which I perform are isolated to the OCCT library - however as frontend I'm using FreeCAD for modelling and that's where the speed actually matters.
FreeCAD copies every BREP file and creates a new instance for every modification on the object. So in case of my actual object one BREP file loads around 40-60 seconds, after 10 changes (since freecad creates 10 brep copies each with its corresponding modification) we're at 40-60 seconds multiplied by 10.
If the loading part can be improved somehow FreeCAD will certainly benefit from it.
Aside of that creating a live copy/clone of the object also seems to be quick (just a few seconds).

Thank you for your support!

Kirill Gavrilov's picture

Macbook Pro from 2012

If your device is that old, I may expect it still running on a very slow HDD. In that case, a large number of small RW operations to the drive might show considerable performance issues.

You may check this by preloading the whole file into memory instead of passing std::ifstream to the reader.

std::vector<char> aBuffer;
{
  std::ifstream aFile;
  OSD_OpenStream (aFile, "myfile.brep", std::ios::binary | std::ios::in);
  aFile.seekg (0, std::ios_base::end);
  const int64_t aFileLen = int64_t (aFile.tellg());
  aFile.seekg (0, std::ios_base::beg);

  aBuffer.resize (aFileLen);
  aFile.read (aBuffer.data(), aBuffer.size());
}

Standard_ArrayStreamBuffer aStreamBuffer (aBuffer.data(), aBuffer.size());
std::istream aStream (&aStreamBuffer);

TopoDS_Shape aShape;
BRep_Builder aBuilder;
BRepTools::Read (aShape, aStream, aBuilder);
Markus R.'s picture

I'm only using SSDs harddisks.

cat Ubuntu\ Server.vdi | pv > /dev/null
27GiB 0:00:05 [ 483MiB/s] [ <=>

As mentioned the iges file loads within a few seconds, also creating a copy of the Topos Shape in memory only takes a few seconds. But loading it from disk just takes so long > 40 seconds (the object has less than 10mb, uncompressed)

2,5 GHz Dual-Core Intel Core i5 2 cores 2 threads / 16 GB RAM. Certainly not the fastest machine, however fluent to work with CAD is no problem with it.
I'll run the test on other machines tomorrow.

Markus R.'s picture

Should I upload the tracing information? (I'm using instruments on MacOS).

time ./test
./test 89.03s user 1.20s system 90% cpu 1:39.38 total

If I should provide a gprof file let me know; I have only built the latest OCCT Version on MacOS.

89 Seconds to load a 6.9MB brep file

Attachments: 
Mikhail Sazonov's picture

I see the hot spot is multiplication of location matrices. Could you provide the statistics of your shape? E.g. by the command nbshapes in Draw.

If you control the creation of that shape you might eliminate locations of subshapes so that to put all transformations to geometries. Such a way this hot spot during reading the file would be gone.

Markus R.'s picture

I have re-created the object by extracting all the faces and recreate the object by sewing things together again - that has fixed the loading problem.
However it has introduced other issues -- tolerance issues.

I have one tolerance here on an Edge:
0.050000 (edge)
0.116921 (Vertex1)
0.132306 (Vertex2)

do you know how I can fix the tolerance of the vertexes?

sewing the faces together creates further problems down the road with such high tolerances on the vertexes.

(sorry for the slow reply I'm having lots of issues in various areas with freecad and opencascade and I'm trying to sort them out myself first).


int main(int argc, char *argv[]) {

// TopoDS_Face s;
TopoDS_Shape s;
TopoDS_Vertex v1;
TopoDS_Vertex v2;
BRep_Builder b;
std::ifstream is;
//is.open("test3.brp");
is.open("PartShape.brp");
BRepTools::Read(s, is, b);

printf("%d\n", s.ShapeType());
TopoDS_Edge e=TopoDS::Edge(s);
printf("%f\n", BRep_Tool::Tolerance(e));

TopExp::Vertices(e, v1, v2);

b.UpdateVertex(v1, 0.01);
b.UpdateVertex(v2, 0.01);
printf("%f\n", BRep_Tool::Tolerance(v1));
printf("%f\n", BRep_Tool::Tolerance(v2));
double myTolerance = 0.01;
ShapeFix_Shape Stol(e);
Stol.SetMaxTolerance(myTolerance);
Stol.Perform();

Handle(ShapeFix_Edge) se2 = Stol.FixEdgeTool();
se2->FixVertexTolerance(e);

//ShapeFix_Edge se=Stol.FixEdgeTool();
//se.FixVertexTolerance();

s = Stol.Shape();
//e=TopoDS::Edge(s);
TopExp::Vertices(e, v1, v2);

b.UpdateVertex(v1, 0.01);
b.UpdateVertex(v2, 0.01);
printf("%f\n", BRep_Tool::Tolerance(v1));
printf("%f\n", BRep_Tool::Tolerance(v2));

return 0;

Markus R.'s picture

ShapeFix_ShapeTolerance st;
st.SetTolerance(e, <newtolerance>, TopAbs_VERTEX);

- ok the file loading problem is solved by regenerating the object
- the tolerance issue is also solved now for me.

One problem left, intersecting holes but I still need to investigate that issue a bit.