2009-08-24

Seminar on parallel development and Open CASCADE

Folks,

Today I would like to come with a question to you.

As you probably noticed, in several last posts, I was uncovering multi-threading programming issues. This subject has really caught me and applying it in Open CASCADE-based software reveals huge potential. Talking to my readers, on this blog and outside, I conclude that the issue of parallel programming and performance (regardless of Open CASCADE) is important for many developers and their employers. So, I thought to come out to you with the following idea.

What would be your thoughts on organizing some sort of technical seminar/training on parallel development ? This could be combined with training/consulting on Open CASCADE if there is a need. Regarding the former part (multi-threading) I would work with my colleagues at Intel to get support. Intel is very serious and working hard to promote this knowledge among mainstream software developers, and likely this idea will be supported if there is sufficient audience. Regarding the latter (Open CASCADE) I could check with Open CASCADE team if this will be of interest of them.

The challenge is how to find a place in the world for us to meet. Obviously, it will depend on locations of those who will respond.

So could you please think of this idea and let me know if you might be interested in such an arrangement. Certainly there will be some expenses involved (traveling and lodging) but all together we'll try to figure out how to minimize them.

Sounds too crazy? Post your comments with any ideas here or just send me an email at roman.lygin@gmail.com.

Thanks a lot in advance ! Let's make it happen !!!

2009-08-07

const Handle & vs Handle

Quick post. The addressed issue may seem quite obvious for professional C++ developers yet it's often overlooked.

Case1. When you need to downcast a handle to superclass to one to subclass bets are you are following Open CASCADE conventions:

Handle(Geom_Curve) aCurve = ...;
...
Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast (aCurve);
gp_Ax1 anAx1 = aLine->Position();
...

Case2. When you have a function returning a const Handle& you likely often write:

const Handle(MyClass)& GetMyClassInstance();

Handle(MyClass) anInstance = GetMyClassInstance();
//though you could write const Handle(MyClass)& anInstance

Both are totally valid code. But have you ever thought about what happens inside ? Remember that a Handle is not just simple type (like pointer), there is certain overhead inside. This overhead is to maintain a reference counter (increment, decrement) any time you copy a handle. If you use debugger and follow step-by-step instructions you will go through Handle_Standard_Transient::BeginScope(), EndScope(), copy constructor, assignment operator, etc.

This overhead is quite negligible when you deal with a few (hundreds ?) objects. However it may become noticeable when you are making performance-critical computations or deal with dozens of hundreds of objects. For instance, I did notice this when translating huge ACIS-SAT files with CAD Exchanger. Surprisingly BeginScope() and EndScope() appeared among top 5 hotspots.

Bad news is that such issue may often be hidden by other types, not necessarily handles themselves. The most frequent case, which Open CASCADE itself is vastly contaminated with is TopoDS_Shape. As you remember, TopoDS_Shape contains a field myTShape of the TopoDS_TShape type (subclass of Handle_Standard_Transient). So whenever you use something like:

1). TopoDS_Edge anEdge = TopoDS::Edge (aShape);
//instead of const TopoDS_Edge& anEdge = TopoDS::Edge (aShape);

or

2). const TopoDS_Shape& GetShape();

TopoDS_Shape aShape = GetShape();

//instead of const TopoDS_Shape& aShape = GetShape();

or

3). have a class returning TopoDS_Shape instead of const TopoDS_Shape& while it could have (e.g. when returning its own field)

class MyClass

{
public:
...
TopoDS_Shape Child() const { return myChild; }

//instead of const TopoDS_Shape& Child();

private:
TopoDS_Shape myChild;
};

You always assume a penalty of copy constructors and reference counters. Beware and pay attention to that !

Here are some quick recommendations on how to avoid this overhead:
  • a). use const Handle()& (or any other type) as return type whenever possible;
  • b). use const& as local variables whenever possible;
  • c). substitute Handle(MyClass)::DownCast() with direct cast (but only if you are certain of the type!):
Handle(Standard_Transient) aTarget;
const Handle(MyClass)& aMyClass = * static_cast
(&aTarget);

We touched c) in a very first post here. I'm currently thinking to extend Handle class with such a method to cast to const Handle&. Thus, Handle could cast the same as two C++ operators dynamic_cast and static_cast.

Any thoughts on this ?