Feedback on 7.0 RTTI mechanism implementation

Roman Lygin's picture

In current master (7.0 preview), DEFINE_STANDARD_RTTI macro includes declaration and inlined definition of the static
and virtual method as follows (see Standard_Type.hxx):
static const char* get_type_name () { return #Class; } \
virtual const Handle(Standard_Type)& DynamicType() const { return STANDARD_TYPE(Class); }

At the same time previously used macro IMPLEMENT_STANDARD_RTTIEXT is defined empty (see Standard_DefineHandle.hxx).

To ensure creation of a static variable Handle_Standard_Type for each type, a method opencascade::type_instance::get() contains an explicit use of the variable myInstance what makes compiler to ensure its presence.

AFAIU, this creates the following downsides:
1. Use of inlined virtual methods would enforce the linker create duplicated implementation in each shared library.
2. Likewise for inlined static method returning a string constant.
3. No way to find a moment where the respective static variable of Handle_Standard_Type is created (as all instances are created by dynamic initializers during library loading). In some cases this can be helpful (for instance, during debugging of #26913).

Instead, why not to create (or rather restore) a more explicit and streamlined approach (used in earlier versions):
- make out of line implementations of get_type_name() and DynamicType();
- create explicit definitions of static variables defining each type.

All this can be put (back) into IMPLEMENT_STANDARD_RTTIEXT macros to be used in .cxx.

Any thoughts on this ?

Best regards,
Roman

Roman Lygin's picture

One more argument against inlining DynamicType()

As we move further in porting to 7.0, another issue popped up which is creating of redundant dependencies from user libraries to OCC's.

Here is a use case:

User's library A depends on OCC library TKLCAF (uses TDocStd_Document); the A's link list includes TKLCAF.

TDocStd_Document.hxx (which includes CDM_Document.hxx) now injects inlined code of CDM_Document::DynamicType() and hence Standard_Type::Instance into A. When linking A on Linux the linker complains about unresolved symbols defined in TKCDM. Same for Geom2d and other libraries - see below. Thus, this requires addition of TKCDM and TKG2d into the link list of A which previously was not necessary.

Thus, due to inlining, the definitions become viral and penetrate user libraries which do not need them. This increases porting overhead, contaminates dependency list and complicates maintenance (as you now don't clearly know what you really depend on and what comes as derivation).

../lin64/gcc4/obj/QOCoreLib/Debug/QOBase_Action.o: In function `opencascade::type_instance::get()':
/Dev/occ/git.dev/fix-lin64-gcc4-debug/inc/Standard_Type.hxx:171: undefined reference to `typeinfo for Geom2d_Curve'
../lin64/gcc4/obj/QOCoreLib/Debug/QOBase_Action.o: In function `opencascade::type_instance::get()':
/Dev/occ/git.dev/fix-lin64-gcc4-debug/inc/Standard_Type.hxx:171: undefined reference to `typeinfo for CDM_Document'

abv's picture

Patch is ready

Hello Roman,

First, thank you for indicating the problem and suggesting a way to address it.

I have registered an issue #26936 for this problem. Please try the fix available in branch CR26936. As discussed before, that fix replaces macro DEFINE_STANDARD_RTTI by two -- DEFINE_STANDARD_RTTI_INLINE and DEFINE_STANDARD_RTTIEXT. The latter should be used together with IMPLEMENT_STANDARD_RTTIEXT, and together they should have essentially the same features as in OCCT 6.x.

The result is considerable reduction of size of OCCT binaries -- by 8% for VC++ 10, 15% for VC++ 14 and CLang 3.6.2, and 25% for GCC 5.2. The effect should be stronger on dependent projects, please share your numbers.

Note that this does not yet make binaries of OCCT 7 less than that of OCCT 6.9.1 (except for VC++ 10), they still are ~15% greater for modern compilers. I suspect that this can be mostly due to multiple instances of NCollection templates, and will try to address this later.

Andrey

Roman Lygin's picture

Data

Hi Andrey,

Thank you very much for paying attention to the issue and willingness to address it.
I have rebuilt our product with three versions of OCC to track size dynamics. Data are here - I cannot figure out how to attach here on the forum:-\.

General observations:
1. Release mode sizes are generally on par, within [-9%,+5%]
2. Debug mode sizes were [+12%,+64%] on master of Nov 22 and [+5%,+17%] on CR26396. Reduction of CR26396 vs master of Nov 22 - [-29%,-7%].
So CR26396 definitively helps.

3. Macro definitions DEFINE_STANDARD_RTTI_INLINE are used in templates/generics (e.g in NCOLLECTION_HARRAY1, etc). That causes compilation error on user-defined types (due to former use of IMPLEMENT_STANDARD_RTTIEXT in .cxx) but that is minor issue, resolvable with #if OCC_VERSION_HEX < 0x070000.

I have not tested yet the use of the registry in Standard_Type.cxx but assume duplicated type registrations are now significantly reduced, what should also improve loading time.

So overall must be good. Thanks again for this effort.
Roman

abv's picture

New RTTI macros are in master

Hello Roman,

Thank you for feedback! This change has been raised to master last Friday.

Andrey

Roman Lygin's picture

Thanks

Cool! Thanks Andrey.

www.opencascade.com

Copyright 2011-2017
OPEN CASCADE SAS
Contact us