Archived issue #0026551
Optimization of initialization of OCCT RTTI
Description
Since about version 6.5.0, OCCT RTTI system initializes all type descriptors defined in a library by the time of loading that library, via use of global variables. This is done in order to prevent possible data races if type descriptors are initialized upon first use (defined as static variables in corresponding getter function) in multithreaded applications.
In OCCT 7 (see #0024947) this feature is also implicitly used to optimize implementation of Standard_Type class: it stores pointers to strings defining its name (user and system) without copying it. This works only if each type descriptor is removed (when last library using it is unloaded) while these pointers are still valid (i.e. they are not part of another library that might have been unloaded previously). Initialization of all descriptors upon library loading is a means to ensure that.
C++11 adds a requirement that static variables should be protected against concurrent initialization (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm), this would make global variables for types not necessary. Unfortunately, this C++11 feature is not supported by Visual Studio until version 15 (GCC supports it since 4.3).
On the other side, even if not guaranteed by compiler, current implementation of OCCT RTTI should make initialization of type objects as static variables reasonably safe, even in case of concurrency. The point is that types are created in single function (Standard_Type::Register()) which is protected by
mutex. Hence, in the the worst case of concurrency static variable (handle to the type) will be initialized twice, by the same pointer. This will lead to twice incrementing reference counter, and leak of the type descriptor when library is unloaded. This should not be harmful (apart of minor memory leak).
Thus it is proposed to eliminate global type variables (Standard_Type::myInstance). The instance of Standard_Type should keep names of the type as string objects (not as pointers to string literals, as now -- these can be already unloaded by the time of destruction of the type descriptor).
That change should reduce time of loading OCCT libraries, and memory consumption (see timings attached to #0024947).
In OCCT 7 (see #0024947) this feature is also implicitly used to optimize implementation of Standard_Type class: it stores pointers to strings defining its name (user and system) without copying it. This works only if each type descriptor is removed (when last library using it is unloaded) while these pointers are still valid (i.e. they are not part of another library that might have been unloaded previously). Initialization of all descriptors upon library loading is a means to ensure that.
C++11 adds a requirement that static variables should be protected against concurrent initialization (see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm), this would make global variables for types not necessary. Unfortunately, this C++11 feature is not supported by Visual Studio until version 15 (GCC supports it since 4.3).
On the other side, even if not guaranteed by compiler, current implementation of OCCT RTTI should make initialization of type objects as static variables reasonably safe, even in case of concurrency. The point is that types are created in single function (Standard_Type::Register()) which is protected by
mutex. Hence, in the the worst case of concurrency static variable (handle to the type) will be initialized twice, by the same pointer. This will lead to twice incrementing reference counter, and leak of the type descriptor when library is unloaded. This should not be harmful (apart of minor memory leak).
Thus it is proposed to eliminate global type variables (Standard_Type::myInstance). The instance of Standard_Type should keep names of the type as string objects (not as pointers to string literals, as now -- these can be already unloaded by the time of destruction of the type descriptor).
That change should reduce time of loading OCCT libraries, and memory consumption (see timings attached to #0024947).
Steps to reproduce
a) test perf fclasses bug24947
b) Start DRAW in Debug mode and then exit it by closing window; look for debug asserts
b) Start DRAW in Debug mode and then exit it by closing window; look for debug asserts
Public activity
6 archived notes
Participants are labeled by their role within this record.
Branch [archived branch] has been created by Author.
[revision removed]
Detailed log of new commits:
Author: Author
Date: Sat Dec 12 19:07:35 2015 +0300
0026551: Optimization of initialization of OCCT RTTI
Global instances of type descriptors are eliminated as unnecessary
Author: Commenter 4
Date: Sun Nov 22 14:54:39 2015 +0400
0026913: Vulnerable mechanism in Standard_Type leads to assert
[revision removed]
Detailed log of new commits:
Author: Author
Date: Sat Dec 12 19:07:35 2015 +0300
0026551: Optimization of initialization of OCCT RTTI
Global instances of type descriptors are eliminated as unnecessary
Author: Commenter 4
Date: Sun Nov 22 14:54:39 2015 +0400
0026913: Vulnerable mechanism in Standard_Type leads to assert
Change (based on previous fix made for #0026913) is pushed to CR26551, please review.
Note that by my measurements, it yields considerable decrease of size of libraries and load time of OCCT dlls (see attached Excel table), due to elimination of global variables holding type descriptors, and deferring initialization of descriptors to the time of first access.
On modern compilers (VC++ 14, GCC since 4.3, CLang since 2.9) it should be safe, since type descriptors instantiated as static variables in function should be protected against concurrent initialization. On older compilers, this should be safe anyway due to the fact that registry of the types is protected by mutex.
For status of compilers, see "magic statics" or N2660 in:
VC++: https://msdn.microsoft.com/ru-ru/library/hh567368.aspx#concurrencytable
GCC: https://gcc.gnu.org/projects/cxx0x.html
CLang: http://clang.llvm.org/cxx_status.html
Note that by my measurements, it yields considerable decrease of size of libraries and load time of OCCT dlls (see attached Excel table), due to elimination of global variables holding type descriptors, and deferring initialization of descriptors to the time of first access.
On modern compilers (VC++ 14, GCC since 4.3, CLang since 2.9) it should be safe, since type descriptors instantiated as static variables in function should be protected against concurrent initialization. On older compilers, this should be safe anyway due to the fact that registry of the types is protected by mutex.
For status of compilers, see "magic statics" or N2660 in:
VC++: https://msdn.microsoft.com/ru-ru/library/hh567368.aspx#concurrencytable
GCC: https://gcc.gnu.org/projects/cxx0x.html
CLang: http://clang.llvm.org/cxx_status.html
Please test the patch.
Fix has been tested with fix for issue 0026988
This change proved to be unsafe for VC++ 10 and 12, see #0027016
Branch [archived branch] has been deleted by Commenter 3.
[revision removed]
[revision removed]
Related records